Compare commits

..

No commits in common. "a537da6eff24cb082050812ad2058a7763d8fcac" and "241217e7cce778a4393ac193041a7b478e878ae4" have entirely different histories.

24 changed files with 887 additions and 1370 deletions

11
package-lock.json generated
View File

@ -18,7 +18,6 @@
"apexcharts": "^4.5.0", "apexcharts": "^4.5.0",
"axios": "^1.7.9", "axios": "^1.7.9",
"axios-retry": "^4.5.0", "axios-retry": "^4.5.0",
"date-fns": "^4.1.0",
"dotenv": "^16.4.7", "dotenv": "^16.4.7",
"dotenv-webpack": "^8.1.0", "dotenv-webpack": "^8.1.0",
"eventemitter3": "^5.0.1", "eventemitter3": "^5.0.1",
@ -2456,16 +2455,6 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/date-fns": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz",
"integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/kossnocorp"
}
},
"node_modules/debug": { "node_modules/debug": {
"version": "4.4.0", "version": "4.4.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",

View File

@ -21,7 +21,6 @@
"apexcharts": "^4.5.0", "apexcharts": "^4.5.0",
"axios": "^1.7.9", "axios": "^1.7.9",
"axios-retry": "^4.5.0", "axios-retry": "^4.5.0",
"date-fns": "^4.1.0",
"dotenv": "^16.4.7", "dotenv": "^16.4.7",
"dotenv-webpack": "^8.1.0", "dotenv-webpack": "^8.1.0",
"eventemitter3": "^5.0.1", "eventemitter3": "^5.0.1",

View File

@ -3,6 +3,10 @@
--bs-nav-link-font-size: 0.7375rem; --bs-nav-link-font-size: 0.7375rem;
} }
.nav {
--bs-nav-link-font-size: 0.7375rem;
}
.card-header { .card-header {
padding: 0.5rem var(--bs-card-cap-padding-x); padding: 0.5rem var(--bs-card-cap-padding-x);
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 376 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 426 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 364 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 376 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -6,198 +6,180 @@ import flatColors from "../Charts/flatColor";
import ChartSkeleton from "../Charts/Skelton"; import ChartSkeleton from "../Charts/Skelton";
const formatDate = (dateStr) => { const formatDate = (dateStr) => {
const date = new Date(dateStr); const date = new Date(dateStr);
return date.toLocaleDateString("en-GB", { return date.toLocaleDateString("en-GB", {
day: "2-digit", day: "2-digit",
month: "long", month: "long",
}); });
}; };
const AttendanceOverview = () => { const AttendanceOverview = () => {
const [dayRange, setDayRange] = useState(7); const [dayRange, setDayRange] = useState(7);
const [view, setView] = useState("chart"); const [view, setView] = useState("chart");
const projectId = useSelector((store) => store.localVariables.projectId); const projectId = useSelector((store) => store.localVariables.projectId);
const { attendanceOverviewData, loading, error } = useAttendanceOverviewData( const { attendanceOverviewData, loading, error } = useAttendanceOverviewData(projectId, dayRange);
projectId,
dayRange
);
const { tableData, roles, dates } = useMemo(() => { const { tableData, roles, dates } = useMemo(() => {
const map = new Map(); const map = new Map();
attendanceOverviewData.forEach((entry) => { attendanceOverviewData.forEach((entry) => {
const date = formatDate(entry.date); const date = formatDate(entry.date);
if (!map.has(date)) map.set(date, {}); if (!map.has(date)) map.set(date, {});
map.get(date)[entry.role.trim()] = entry.present; map.get(date)[entry.role.trim()] = entry.present;
}); });
const uniqueRoles = [ const uniqueRoles = [...new Set(attendanceOverviewData.map((e) => e.role.trim()))];
...new Set(attendanceOverviewData.map((e) => e.role.trim())), const sortedDates = [...map.keys()];
]; const data = sortedDates.map((date) => {
const sortedDates = [...map.keys()]; const row = { date };
const data = sortedDates.map((date) => { uniqueRoles.forEach((role) => {
const row = { date }; row[role] = map.get(date)?.[role] ?? 0;
uniqueRoles.forEach((role) => { });
row[role] = map.get(date)?.[role] ?? 0; return row;
}); });
return row;
});
return { return {
tableData: data, tableData: data,
roles: uniqueRoles, roles: uniqueRoles,
dates: sortedDates, dates: sortedDates,
};
}, [attendanceOverviewData]);
const chartSeries = roles.map((role) => ({
name: role,
data: tableData.map((row) => row[role]),
}));
const chartOptions = {
chart: {
type: "bar",
stacked: true,
height: 400,
toolbar: { show: false },
},
plotOptions: {
bar: {
borderRadius: 2,
columnWidth: "60%",
},
},
xaxis: {
categories: tableData.map((row) => row.date),
},
yaxis: {
show: true,
axisBorder: {
show: true,
color: '#78909C',
offsetX: 0,
offsetY: 0
},
axisTicks: {
show: true,
borderType: 'solid',
color: '#78909C',
width: 6,
offsetX: 0,
offsetY: 0
},
},
legend: {
position: "bottom",
},
fill: {
opacity: 1,
},
colors: roles.map((_, i) => flatColors[i % flatColors.length]),
}; };
}, [attendanceOverviewData]);
const chartSeries = roles.map((role) => ({ return (
name: role, <div
data: tableData.map((row) => row[role]), className="bg-white p-4 rounded shadow d-flex flex-column"
})); >
{/* Header */}
const chartOptions = { <div className="d-flex justify-content-between align-items-center mb-3">
chart: { <div className="card-title mb-0 text-start">
type: "bar", <h5 className="mb-1">Attendance Overview</h5>
stacked: true, <p className="card-subtitle">Role-wise present count</p>
height: 400, </div>
toolbar: { show: false }, <div className="d-flex gap-2">
}, <select
plotOptions: { className="form-select form-select-sm"
bar: { value={dayRange}
borderRadius: 2, onChange={(e) => setDayRange(Number(e.target.value))}
columnWidth: "60%",
},
},
xaxis: {
categories: tableData.map((row) => row.date),
},
yaxis: {
show: true,
axisBorder: {
show: true,
color: "#78909C",
offsetX: 0,
offsetY: 0,
},
axisTicks: {
show: true,
borderType: "solid",
color: "#78909C",
width: 6,
offsetX: 0,
offsetY: 0,
},
},
legend: {
position: "bottom",
},
fill: {
opacity: 1,
},
colors: roles.map((_, i) => flatColors[i % flatColors.length]),
};
return (
<div className="bg-white p-4 rounded shadow d-flex flex-column">
{/* Header */}
<div className="d-flex justify-content-between align-items-center mb-3">
<div className="card-title mb-0 text-start">
<h5 className="mb-1">Attendance Overview</h5>
<p className="card-subtitle">Role-wise present count</p>
</div>
<div className="d-flex gap-2">
<select
className="form-select form-select-sm w-auto"
value={dayRange}
onChange={(e) => setDayRange(Number(e.target.value))}
>
<option value={7}>Last 7 Days</option>
<option value={15}>Last 15 Days</option>
<option value={30}>Last 30 Days</option>
</select>
<button
className={`btn btn-sm p-1 ${
view === "chart" ? "btn-primary" : "btn-outline-primary"
}`}
onClick={() => setView("chart")}
>
<i class="bx bx-bar-chart fs-5"></i>
</button>
<button
className={`btn btn-sm p-1 ${
view === "table" ? "btn-primary" : "btn-outline-primary"
}`}
onClick={() => setView("table")}
>
<i class="bx bx-table fs-5"></i>
</button>
</div>
</div>
{/* Content */}
<div className="flex-grow-1 d-flex align-items-center justify-content-center">
{loading ? (
<ChartSkeleton />
) : error ? (
<p className="text-danger">{error}</p>
) : view === "chart" ? (
<div className="w-100">
<ReactApexChart
options={chartOptions}
series={chartSeries}
type="bar"
height={400}
/>
</div>
) : (
<div
className="table-responsive w-100"
style={{ maxHeight: "350px", overflowY: "auto" }}
>
<table className="table table-bordered table-sm text-start align-middle mb-0">
<thead
className="table-light"
style={{ position: "sticky", top: 0, zIndex: 1 }}
>
<tr>
<th style={{ background: "#f8f9fa", textTransform: "none" }}>
Role
</th>
{dates.map((date, idx) => (
<th
key={idx}
style={{ background: "#f8f9fa", textTransform: "none" }}
> >
{date} <option value={7}>Last 7 Days</option>
</th> <option value={15}>Last 15 Days</option>
))} <option value={30}>Last 30 Days</option>
</tr> </select>
</thead> <button
className={`btn btn-sm ${view === "chart" ? "btn-primary" : "btn-outline-primary"}`}
onClick={() => setView("chart")}
>
📊
</button>
<button
className={`btn btn-sm ${view === "table" ? "btn-primary" : "btn-outline-primary"}`}
onClick={() => setView("table")}
>
📋
</button>
</div>
</div>
<tbody> {/* Content */}
{roles.map((role) => ( <div className="flex-grow-1 d-flex align-items-center justify-content-center">
<tr key={role}> {loading ? (
<td>{role}</td> <ChartSkeleton />
{tableData.map((row, idx) => { ) : error ? (
const value = row[role]; <p className="text-danger">{error}</p>
const cellStyle = ) : view === "chart" ? (
value > 0 ? { backgroundColor: "#d5d5d5" } : {}; <div className="w-100">
return ( <ReactApexChart
<td key={idx} style={cellStyle}> options={chartOptions}
{value} series={chartSeries}
</td> type="bar"
); height={400}
})} />
</tr> </div>
))} ) : (
</tbody> <div
</table> className="table-responsive w-100"
</div> style={{ maxHeight: "350px", overflowY: "auto" }}
)} >
</div> <table className="table table-bordered table-sm text-start align-middle mb-0">
</div> <thead className="table-light" style={{ position: "sticky", top: 0, zIndex: 1 }}>
); <tr>
<th style={{ background: "#f8f9fa", textTransform: "none" }}>Role</th>
{dates.map((date, idx) => (
<th key={idx} style={{ background: "#f8f9fa", textTransform: "none" }}>{date}</th>
))}
</tr>
</thead>
<tbody>
{roles.map((role) => (
<tr key={role}>
<td>{role}</td>
{tableData.map((row, idx) => {
const value = row[role];
const cellStyle = value > 0 ? { backgroundColor: '#d5d5d5' } : {};
return (
<td key={idx} style={cellStyle}>
{value}
</td>
);
})}
</tr>
))}
</tbody>
</table>
</div>
)}
</div>
</div>
);
}; };
export default AttendanceOverview; export default AttendanceOverview;

View File

@ -1,161 +0,0 @@
import React, { useState, useEffect } from "react";
import moment from "moment";
import DateRangePicker from "../common/DateRangePicker";
import useFormattedDate from "../../hooks/useFormattedDate";
import { useProjectTasksByEmployee } from "../../hooks/useProjects";
const EmpActivities = ({ employee }) => {
const [dateRange, setDateRange] = useState({ startDate: "", endDate: "" });
const myDate = new Date("2025-08-06T10:30:00Z");
const formattedToday = useFormattedDate(myDate, "dd-MMM-yyyy");
const {
data,
isError,
isLoading,
error,
refetch,
} = useProjectTasksByEmployee(employee?.id,dateRange.startDate,dateRange.endDate);
if(isLoading) return <div>Loading...</div>
return (
<>
<div className="card h-100 mt-4">
<div className="card-body">
<div className="my-0 text-start">
<DateRangePicker
DateDifference="30"
onRangeChange={setDateRange}
endDateMode="today"
/>
</div>
<ul className="timeline mb-0 mt-5 text-start">
{data?.map((activity)=>(
<li className="timeline-item timeline-item-transparent">
<span className="timeline-point timeline-point-primary"></span>
<div className="timeline-event">
<div className="timeline-header mb-3">
<h6 className="mb-0">{activity.projectName}</h6>
<small className="text-body-secondary">
{useFormattedDate(activity.assignmentDate, "dd-MMM-yyyy")}
</small>
</div>
<p className="mb-2"><span className="fw-semibold">Activity:</span>{activity.activityName}</p>
<p className="mb-2">
<span className="fw-semibold">Location:</span> {activity.location}
</p>
<p className="mb-2">
<span className="fw-semibold">Planned: {activity.plannedTask}</span>
<span className="ms-2">Completed : {activity.completedTask}</span>
</p>
</div>
</li>
))}
{/* <li className="timeline-item timeline-item-transparent">
<span className="timeline-point timeline-point-success"></span>
<div className="timeline-event">
<div className="timeline-header mb-3">
<h6 className="mb-0">Client Meeting</h6>
<small className="text-body-secondary">45 min ago</small>
</div>
<p className="mb-2">Project meeting with john @10:15am</p>
<div className="d-flex justify-content-between flex-wrap gap-2 mb-2">
<div className="d-flex flex-wrap align-items-center mb-50">
<div className="avatar avatar-sm me-2">
<img
src="../../assets/img/avatars/1.png"
alt="Avatar"
className="rounded-circle"
/>
</div>
<div>
<p className="mb-0 small fw-medium">
Lester McCarthy (Client)
</p>
<small>CEO of ThemeSelection</small>
</div>
</div>
</div>
</div>
</li>
<li className="timeline-item timeline-item-transparent">
<span className="timeline-point timeline-point-info"></span>
<div className="timeline-event">
<div className="timeline-header mb-3">
<h6 className="mb-0">Create a new project for client</h6>
<small className="text-body-secondary">2 Day Ago</small>
</div>
<p className="mb-2">6 team members in a project</p>
<ul className="list-group list-group-flush">
<li className="list-group-item d-flex justify-content-between align-items-center flex-wrap border-top-0 p-0">
<div className="d-flex flex-wrap align-items-center">
<ul className="list-unstyled users-list d-flex align-items-center avatar-group m-0 me-2">
<li
data-bs-toggle="tooltip"
data-popup="tooltip-custom"
data-bs-placement="top"
className="avatar pull-up"
aria-label="Vinnie Mostowy"
data-bs-original-title="Vinnie Mostowy"
>
<img
className="rounded-circle"
src="../../assets/img/avatars/5.png"
alt="Avatar"
/>
</li>
<li
data-bs-toggle="tooltip"
data-popup="tooltip-custom"
data-bs-placement="top"
className="avatar pull-up"
aria-label="Allen Rieske"
data-bs-original-title="Allen Rieske"
>
<img
className="rounded-circle"
src="../../assets/img/avatars/12.png"
alt="Avatar"
/>
</li>
<li
data-bs-toggle="tooltip"
data-popup="tooltip-custom"
data-bs-placement="top"
className="avatar pull-up"
aria-label="Julee Rossignol"
data-bs-original-title="Julee Rossignol"
>
<img
className="rounded-circle"
src="../../assets/img/avatars/6.png"
alt="Avatar"
/>
</li>
<li className="avatar">
<span
className="avatar-initial rounded-circle pull-up"
data-bs-toggle="tooltip"
data-bs-placement="bottom"
data-bs-original-title="3 more"
>
+3
</span>
</li>
</ul>
</div>
</li>
</ul>
</div>
</li> */}
</ul>
</div>
</div>
</>
);
};
export default EmpActivities;

View File

@ -1,115 +0,0 @@
import React, { useState, useEffect } from "react";
import { useChangePassword } from "../../components/Context/ChangePasswordContext";
import GlobalModel from "../common/GlobalModel";
import ManageEmployee from "./ManageEmployee";
const EmpBanner = ({ profile, loggedInUser }) => {
const { openChangePassword } = useChangePassword();
const [showModal, setShowModal] = useState(false);
return (
<>
{showModal && (
<GlobalModel
size="lg"
isOpen={showModal}
closeModal={() => setShowModal(false)}
>
<ManageEmployee
employeeId={profile.id}
onClosed={() => setShowModal(false)}
/>
</GlobalModel>
)}
<div className="user-profile-header d-flex flex-column flex-lg-row text-sm-start text-center mb-8">
<div className="flex-shrink-0 mt-1 mx-sm-0 mx-auto">
{profile?.gender?.toLowerCase() == "male" && (
<img
width={125}
src="../../assets/img/avatars/avatar_m_01.png"
alt="user image"
className="d-block h-auto ms-0 ms-sm-6 rounded-3 user-profile-img"
/>
)}
{profile?.gender?.toLowerCase() == "female" && (
<img
width={125}
src="../../assets/img/avatars/avatar_f_02.png"
alt="user image"
className="d-block h-auto ms-0 ms-sm-6 rounded-3 user-profile-img"
/>
)}
</div>
<div className="flex-grow-1 mt-1 mt-lg-1">
<div className="d-flex align-items-md-end align-items-sm-start align-items-center justify-content-md-between justify-content-start mx-5 flex-md-row flex-column gap-4">
<div className="user-profile-info">
<h4 className="mb-2">
<span>{profile?.firstName}</span>
{profile?.middleName ? (
<span className="ms-1">{profile?.middleName}</span>
) : (
<></>
)}
{profile?.lastName ? (
<span className="ms-1">{profile?.lastName}</span>
) : (
<></>
)}
</h4>
<ul className="list-inline mb-0 d-flex align-items-center flex-wrap justify-content-sm-start justify-content-center gap-4 mt-4">
<li className="list-inline-item">
<i className="icon-base bx bx-crown me-2 align-top"></i>
<span className="fw-medium">
{profile?.jobRole || <em>NA</em>}
</span>
</li>
<li className="list-inline-item">
<i className="icon-base bx bx-phone me-2 align-top"></i>
<span className="fw-medium">
{" "}
{profile?.phoneNumber || <em>NA</em>}
</span>
</li>
<li className="list-inline-item">
<i className="icon-base bx bx-calendar me-2 align-top"></i>
<span className="fw-medium">
{" "}
Joined on{" "}
{profile?.joiningDate ? (
new Date(profile.joiningDate).toLocaleDateString()
) : (
<em>NA</em>
)}
</span>
</li>
</ul>
<ul className="list-inline mb-0 d-flex align-items-center flex-wrap justify-content-sm-start justify-content-center mt-4">
<li className="list-inline-item">
<button
className="btn btn-sm btn-primary btn-block"
onClick={() => setShowModal(true)}
>
Edit Profile
</button>
</li>
<li className="list-inline-item">
{profile?.id == loggedInUser?.employeeInfo?.id && (
<button
className="btn btn-sm btn-outline-primary btn-block"
onClick={() => openChangePassword()}
>
Change Password
</button>
)}
</li>
</ul>
</div>
</div>
</div>
</div>
</>
);
};
export default EmpBanner;

View File

@ -1,84 +0,0 @@
import React, { useEffect, useState } from "react";
import EmpOverview from "./EmpOverview";
import { useProjectsAllocationByEmployee } from "../../hooks/useProjects";
const EmpDashboard = ({ profile }) => {
const {
projectList,
loading: selectedProjectLoding,
refetch,
} = useProjectsAllocationByEmployee(profile?.id);
console.log(projectList);
return (
<>
<div className="row">
<div className="col-12 col-sm-6 pt-5">
{" "}
<EmpOverview profile={profile}></EmpOverview>
</div>
<div className="col col-sm-6 pt-5">
<div className="card ">
<div className="card-body">
<small className="card-text text-uppercase text-body-secondary small">
My Projects
</small>{" "}
<ul className="list-unstyled text-start my-3 py-1">
{selectedProjectLoding && <span>Loading</span>}
{projectList.map((project) => (
<li
className="d-flex mb-4 align-items-start flex-wrap"
key={project.id}
>
{/* Project Info */}
<div className="flex-grow-1">
<div className="d-flex flex-wrap align-items-center justify-content-between gap-2">
<div className="d-flex">
<div className="avatar flex-shrink-0 me-3">
<span className="avatar-initial rounded bg-label-primary">
<i className="icon-base bx bx-buildings icon-lg"></i>
</span>
</div>
<div>
<h6 className="mb-0">{project.projectShortName}</h6>
<small className="text-muted">{project.projectName}</small>
<div className="label-secondary">
Assigned:{" "}
{project.assignedDate ? (
new Date(project.assignedDate).toLocaleDateString()
) : (
<em>NA</em>
)}
</div>
</div>
</div>
<div>
<span className="badge bg-label-secondary">
{project.designation}
</span>
</div>
</div>
{/* Dates */}
{project.removedDate && (
<div className="mt-2 d-flex flex-column flex-sm-row justify-content-between">
<div className="label-secondary">
Unassigned:{" "}
{new Date(project.removedDate).toLocaleDateString()}
</div>
</div>
)}
</div>
</li>
))}
</ul>
</div>
</div>
</div>
</div>
</>
);
};
export default EmpDashboard;

View File

@ -1,12 +0,0 @@
import React, { useState, useEffect } from "react";
import { ComingSoonPage } from "../../pages/Misc/ComingSoonPage";
const EmpDocuments = ({ profile, loggedInUser }) => {
return (
<>
<ComingSoonPage/>
</>
);
};
export default EmpDocuments;

View File

@ -1,109 +0,0 @@
import React from "react";
import Avatar from "../common/Avatar";
import { useProfile } from "../../hooks/useProfile";
const EmpOverview = ({ profile }) => {
const { loggedInUserProfile } = useProfile();
return (
<>
{" "}
<div className="row">
<div className="col-12 mb-4">
<div className="card">
<div className="card-body">
<small className="card-text text-uppercase text-body-secondary small">
About
</small>
<ul className="list-unstyled my-3 py-1">
<li className="d-flex align-items-center mb-4">
<i className="icon-base bx bx-user"></i>
<span className="fw-medium mx-2">Full Name:</span>{" "}
<span>{`${profile?.firstName} ${profile?.lastName}`}</span>
</li>
<li className="d-flex align-items-center mb-4">
<i className="icon-base bx bx-check"></i>
<span className="fw-medium mx-2">Status:</span>{" "}
<span>Active</span>
</li>
<li className="d-flex align-items-center mb-4">
<i className="icon-base bx bx-crown"></i>
<span className="fw-medium mx-2">Role:</span>{" "}
<span> {profile?.jobRole || <em>NA</em>}</span>
</li>
<li className="d-flex align-items-center mb-4">
<i className="icon-base bx bx-flag"></i>
<span className="fw-medium mx-2">Gender:</span>{" "}
<span> {profile?.gender || <em>NA</em>}</span>
</li>{" "}
<li className="d-flex align-items-center mb-2">
<i className="icon-base bx bx-calendar "></i>
<span className="fw-medium mx-2">Birth Date:</span>{" "}
<span>
{profile?.birthDate ? (
new Date(profile.birthDate).toLocaleDateString()
) : (
<em>NA</em>
)}
</span>
</li>
<li className="d-flex align-items-center mb-2">
<i className="icon-base bx bx-calendar "></i>
<span className="fw-medium mx-2">Joining Date:</span>{" "}
<span>
{profile?.joiningDate ? (
new Date(profile.joiningDate).toLocaleDateString()
) : (
<em>NA</em>
)}
</span>
</li>
</ul>
<small className="card-text text-uppercase text-body-secondary small">
Contacts
</small>
<ul className="list-unstyled my-3 py-1">
<li className="d-flex align-items-center mb-4">
<i className="icon-base bx bx-phone"></i>
<span className="fw-medium mx-2">Contact:</span>{" "}
<span> {profile?.phoneNumber || <em>NA</em>}</span>
</li>
<li className="d-flex align-items-center mb-4">
<i className="icon-base bx bx-envelope"></i>
<span className="fw-medium mx-2">Email:</span>{" "}
<a href={`mailto:${profile?.email}`}>
{" "}
{profile?.email || <em>NA</em>}
</a>
</li>
<li className="d-flex align-items-center mb-4">
<i className="icon-base bx bx-user"></i>
<span className="fw-medium mx-2">
{" "}
Emergency Contact:
</span>{" "}
<span> {profile?.emergencyContactPerson || <em>NA</em>}</span>
</li>
<li className="d-flex align-items-center mb-4">
<i className="icon-base bx bx-phone"></i>
<span className="fw-medium mx-2"> Emergency Phone:</span>{" "}
<span> {profile?.emergencyPhoneNumber || <em>NA</em>}</span>
</li>
<li className="d-flex align-items-center ">
<div className="container p-0">
<div className="fw-medium text-start">
<i className="icon-base bx bx-map "></i> Address:
</div>
<div className="text-start ms-7">
{profile?.currentAddress || <em>NA</em>}
</div>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
</>
);
};
export default EmpOverview;

View File

@ -1,36 +1,53 @@
import React from "react"; import React from "react";
const EmployeeNav = ({ onPillClick, activePill }) => {
const tabs = [
{ key: "profile", icon: "bx bx-user", label: "Profile" },
{ key: "attendance", icon: "bx bx-group", label: "Attendances" },
{ key: "documents", icon: "bx bx-user", label: "Documents" },
{ key: "activities", icon: "bx bx-grid-alt", label: "Activities" },
];
const EmployeeNav = ({ onPillClick, activePill }) => {
return ( return (
<div className="col-md-12"> <div className="col-md-12">
<div className="nav-align-top"> <div className="nav-align-top ">
<ul className="nav nav-tabs overflow-auto" id="horizontal-example"> <ul className="nav nav-tabs">
{tabs.map(({ key, icon, label }) => ( <li className="nav-item" style={{ padding: "10px 10px 0 10px" }}>
<li <a
key={key} className={`nav-link py-1 px-2 small ${
className="nav-item" activePill === "attendance" ? "active" : ""
style={{ padding: "10px 10px 0 10px" }} }`}
href="#"
onClick={(e) => {
e.preventDefault(); // Prevent page reload
onPillClick("attendance");
}}
> >
<a <i className="bx bx-group bx-sm me-1_5"></i> Attendances
href="#" </a>
className={`nav-link py-1 px-2 small ${ </li>
activePill === key ? "active" : "" <li className="nav-item" style={{ padding: "10px 10px 0 10px" }}>
}`} <a
onClick={(e) => { className={`nav-link py-1 px-2 small ${
e.preventDefault(); activePill === "account" ? "active" : ""
onPillClick(key); }`}
}} href="#"
> onClick={(e) => {
<i className={`icon-base ${icon} icon-sm me-1_5`}></i> {label} e.preventDefault(); // Prevent page reload
</a> onPillClick("account");
</li> }}
))} >
<i className="bx bx-user bx-sm me-1_5"></i> Documents
</a>
</li>
<li className="nav-item" style={{ padding: "10px 10px 0 10px" }}>
<a
className={`nav-link py-1 px-2 small ${
activePill === "activities" ? "active" : ""
}`}
href="#"
onClick={(e) => {
e.preventDefault(); // Prevent page reload
onPillClick("activities");
}}
>
<i className="bx bx-grid-alt bx-sm me-1_5"></i> Activities
</a>
</li>
</ul> </ul>
</div> </div>
</div> </div>

View File

@ -27,25 +27,12 @@ const Header = () => {
const { data, loading } = useMaster(); const { data, loading } = useMaster();
const navigate = useNavigate(); const navigate = useNavigate();
const HasManageProjectPermission = useHasUserPermission(MANAGE_PROJECT); const HasManageProjectPermission = useHasUserPermission(MANAGE_PROJECT);
// {
// console.log(location.pathname);
// }
const isDashboardPath = const isDirectoryPath = /^\/directory$/.test(location.pathname);
/^\/dashboard$/.test(location.pathname) || /^\/$/.test(location.pathname);
const isProjectPath = /^\/projects$/.test(location.pathname); const isProjectPath = /^\/projects$/.test(location.pathname);
const isDashboard =
/^\/dashboard$/.test(location.pathname) || /^\/$/.test(location.pathname);
const showProjectDropdown = (pathname) => {
const isDirectoryPath = /^\/directory$/.test(pathname);
// const isProfilePage = /^\/employee$/.test(location.pathname);
const isProfilePage =
/^\/employee\/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(
pathname
);
return !(isDirectoryPath || isProfilePage);
};
const allowedProjectStatusIds = [ const allowedProjectStatusIds = [
"603e994b-a27f-4e5d-a251-f3d69b0498ba", "603e994b-a27f-4e5d-a251-f3d69b0498ba",
"cdad86aa-8a56-4ff4-b633-9c629057dfef", "cdad86aa-8a56-4ff4-b633-9c629057dfef",
@ -95,16 +82,16 @@ const Header = () => {
}; };
const handleProfilePage = () => { const handleProfilePage = () => {
navigate(`/employee/${profile?.employeeInfo?.id}`); navigate(`/employee/${profile?.employeeInfo?.id}?for=attendance`);
}; };
const { projectNames, loading: projectLoading, fetchData } = useProjectName(); const { projectNames, loading: projectLoading, fetchData } = useProjectName();
const selectedProject = useSelectedproject(); const selectedProject = useSelectedproject();
const projectsForDropdown = isDashboardPath const projectsForDropdown = isDashboard
? projectNames ? projectNames
: projectNames?.filter((project) => : projectNames?.filter(project =>
allowedProjectStatusIds.includes(project.projectStatusId) allowedProjectStatusIds.includes(project.projectStatusId)
); );
@ -122,9 +109,7 @@ const Header = () => {
const selectedProjectObj = projectNames.find( const selectedProjectObj = projectNames.find(
(p) => p?.id === selectedProject (p) => p?.id === selectedProject
); );
currentProjectDisplayName = selectedProjectObj currentProjectDisplayName = selectedProjectObj ? selectedProjectObj.name : "All Projects";
? selectedProjectObj.name
: "All Projects";
} }
} }
@ -140,17 +125,16 @@ const Header = () => {
if (projectNames.length === 1) { if (projectNames.length === 1) {
dispatch(setProjectId(projectNames[0]?.id || null)); dispatch(setProjectId(projectNames[0]?.id || null));
} else { } else {
if (isDashboardPath) { if (isDashboard) {
dispatch(setProjectId(null)); dispatch(setProjectId(null));
} else { } else {
const firstAllowedProject = projectNames.find((project) => const firstAllowedProject = projectNames.find(project => allowedProjectStatusIds.includes(project.projectStatusId));
allowedProjectStatusIds.includes(project.projectStatusId)
);
dispatch(setProjectId(firstAllowedProject?.id || null)); dispatch(setProjectId(firstAllowedProject?.id || null));
} }
} }
} }
}, [projectNames, selectedProject, dispatch, isDashboardPath]); }, [projectNames, selectedProject, dispatch, isDashboard]);
const handler = useCallback( const handler = useCallback(
async (data) => { async (data) => {
@ -220,7 +204,7 @@ const Header = () => {
className="navbar-nav-right d-flex align-items-center justify-content-between" className="navbar-nav-right d-flex align-items-center justify-content-between"
id="navbar-collapse" id="navbar-collapse"
> >
{showProjectDropdown(location.pathname) && ( {projectNames && !isDirectoryPath && (
<div className="align-items-center"> <div className="align-items-center">
<i className="rounded-circle bx bx-building-house bx-sm-lg bx-md me-2"></i> <i className="rounded-circle bx bx-building-house bx-sm-lg bx-md me-2"></i>
<div className="btn-group"> <div className="btn-group">
@ -239,42 +223,40 @@ const Header = () => {
</span> </span>
)} )}
{shouldShowDropdown && {shouldShowDropdown && projectsForDropdown && projectsForDropdown.length > 0 && (
projectsForDropdown && <ul
projectsForDropdown.length > 0 && ( className="dropdown-menu"
<ul style={{ overflow: "auto", maxHeight: "300px" }}
className="dropdown-menu" >
style={{ overflow: "auto", maxHeight: "300px" }} {isDashboard && (
> <li>
{isDashboardPath && ( <button
<li> className="dropdown-item"
onClick={() => handleProjectChange(null)}
>
All Projects
</button>
</li>
)}
{[...projectsForDropdown]
.sort((a, b) => a?.name?.localeCompare(b.name))
.map((project) => (
<li key={project?.id}>
<button <button
className="dropdown-item" className="dropdown-item"
onClick={() => handleProjectChange(null)} onClick={() => handleProjectChange(project?.id)}
> >
All Projects {project?.name}
{project?.shortName && (
<span className="text-primary fw-semibold ms-1">
({project?.shortName})
</span>
)}
</button> </button>
</li> </li>
)} ))}
{[...projectsForDropdown] </ul>
.sort((a, b) => a?.name?.localeCompare(b.name)) )}
.map((project) => (
<li key={project?.id}>
<button
className="dropdown-item"
onClick={() => handleProjectChange(project?.id)}
>
{project?.name}
{project?.shortName && (
<span className="text-primary fw-semibold ms-1">
({project?.shortName})
</span>
)}
</button>
</li>
))}
</ul>
)}
</div> </div>
</div> </div>
)} )}
@ -475,4 +457,4 @@ const Header = () => {
</nav> </nav>
); );
}; };
export default Header; export default Header;

View File

@ -27,7 +27,8 @@ const DateRangePicker = ({
altInput: true, altInput: true,
altFormat: "d-m-Y", altFormat: "d-m-Y",
defaultDate: [startDate, endDate], defaultDate: [startDate, endDate],
static: true, static: false,
// appendTo: document.body,
clickOpens: true, clickOpens: true,
maxDate: endDate, maxDate: endDate,
onChange: (selectedDates, dateStr) => { onChange: (selectedDates, dateStr) => {

View File

@ -1,26 +0,0 @@
import { format } from "date-fns";
/**
* A custom hook to format a date string, object, or number.
* @param {string | Date | number} date - The date to be formatted.
* @param {string} formatString - The format string (e.g., 'MMMM do, yyyy').
* @returns {string} The formatted date string.
*/
const useFormattedDate = (date, formatString) => {
// Return early if no date is provided
if (!date) {
return "";
}
try {
const dateObj = new Date(date);
// You could also add error handling for invalid dates
// if (!isValid(dateObj)) return 'Invalid Date';
return format(dateObj, formatString);
} catch (error) {
console.error("Error formatting date:", error);
return ""; // Return an empty string or a default value on error
}
};
export default useFormattedDate;

View File

@ -96,7 +96,7 @@ export const useProjectDetails = (projectId, isAuto = true) => {
export const useProjectsByEmployee = (employeeId) => { export const useProjectsByEmployee = (employeeId) => {
const { const {
data: projectList = [], data: projectNameList = [],
isLoading, isLoading,
error, error,
refetch, refetch,
@ -117,36 +117,6 @@ export const useProjectsByEmployee = (employeeId) => {
return { projectList, loading: isLoading, error, refetch }; return { projectList, loading: isLoading, error, refetch };
}; };
export const useProjectsAllocationByEmployee = (employeeId) => {
const {
data: projectList = [],
isLoading,
error,
refetch,
} = useQuery({
queryKey: ["ProjectsAllocationByEmployee", employeeId],
queryFn: async () => {
const res = await ProjectRepository.getProjectsAllocationByEmployee(
employeeId
);
const sortedProjects = [...res.data].sort((a, b) =>
a.projectName.localeCompare(b.projectName)
);
return sortedProjects || res;
//return res.data || res;
},
enabled: !!employeeId,
onError: (error) => {
showToast(
error.message || "Error while Fetching project Employee",
"error"
);
},
});
return { projectList, loading: isLoading, error, refetch };
};
export const useProjectName = () => { export const useProjectName = () => {
const { const {
data = [], data = [],
@ -206,29 +176,6 @@ export const useProjectTasks = (workAreaId, IsExpandedArea = false) => {
return { ProjectTaskList, isLoading, error }; return { ProjectTaskList, isLoading, error };
}; };
export const useProjectTasksByEmployee = (
employeeId,
fromDate,
toDate,
) => {
return useQuery({
queryKey: ["TasksByEmployee", employeeId],
queryFn: async () => {
const res = await ProjectRepository.getProjectTasksByEmployee(
employeeId,
fromDate,
toDate
);
return res.data;
},
enabled: !!employeeId && !!fromDate && !!toDate,
onError: (error) => {
showToast(error.message || "Error while Fetching project Tasks", "error");
},
});
};
// -- -------------Mutation------------------------------- // -- -------------Mutation-------------------------------
export const useCreateProject = ({ onSuccessCallback }) => { export const useCreateProject = ({ onSuccessCallback }) => {

View File

@ -1,30 +1,24 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import moment from "moment"; import moment from "moment";
import DateRangePicker from "../common/DateRangePicker"; import DateRangePicker from "../../components/common/DateRangePicker";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { fetchEmployeeAttendanceData } from "../../slices/apiSlice/employeeAttendanceSlice"; import { fetchEmployeeAttendanceData } from "../../slices/apiSlice/employeeAttendanceSlice";
import usePagination from "../../hooks/usePagination"; import usePagination from "../../hooks/usePagination";
import Avatar from "../common/Avatar"; import Avatar from "../../components/common/Avatar";
import { convertShortTime } from "../../utils/dateUtils"; import { convertShortTime } from "../../utils/dateUtils";
import RenderAttendanceStatus from "../Activities/RenderAttendanceStatus"; import RenderAttendanceStatus from "../../components/Activities/RenderAttendanceStatus";
import AttendLogs from "../Activities/AttendLogs"; import AttendLogs from "../../components/Activities/AttendLogs";
import { useAttendanceByEmployee } from "../../hooks/useAttendance"; import { useAttendanceByEmployee } from "../../hooks/useAttendance";
import GlobalModel from "../common/GlobalModel"; import GlobalModel from "../../components/common/GlobalModel";
import { ITEMS_PER_PAGE } from "../../utils/constants"; import { ITEMS_PER_PAGE } from "../../utils/constants";
const EmpAttendance = ({ employee }) => { const AttendancesEmployeeRecords = ({ employee }) => {
const [attendances, setAttendnaces] = useState([]); const [attendances, setAttendnaces] = useState([]);
const [selectedDate, setSelectedDate] = useState(""); const [selectedDate, setSelectedDate] = useState("");
const [dateRange, setDateRange] = useState({ startDate: "", endDate: "" }); const [dateRange, setDateRange] = useState({ startDate: "", endDate: "" });
const [isModalOpen, setIsModalOpen] = useState(false); const [isModalOpen, setIsModalOpen] = useState(false);
const [attendanceId, setAttendanecId] = useState(); const [attendanceId, setAttendanecId] = useState();
const { const {data =[],isLoading:loading,isFetching,error,refetch} = useAttendanceByEmployee(employee,dateRange.startDate, dateRange.endDate)
data = [],
isLoading: loading,
isFetching,
error,
refetch,
} = useAttendanceByEmployee(employee, dateRange.startDate, dateRange.endDate);
const dispatch = useDispatch(); const dispatch = useDispatch();
// const { data, loading, error } = useSelector( // const { data, loading, error } = useSelector(
@ -81,24 +75,16 @@ const EmpAttendance = ({ employee }) => {
const uniqueMap = new Map(); const uniqueMap = new Map();
[...group1, ...group2, ...group3, ...group4, ...group5].forEach((rec) => { [...group1, ...group2, ...group3, ...group4, ...group5].forEach((rec) => {
const date = moment(rec.checkInTime || rec.checkOutTime).format( const date = moment(rec.checkInTime || rec.checkOutTime).format("YYYY-MM-DD");
"YYYY-MM-DD"
);
const key = `${rec.employeeId}-${date}`; const key = `${rec.employeeId}-${date}`;
const existing = uniqueMap.get(key); const existing = uniqueMap.get(key);
if ( if (!existing || new Date(rec.checkInTime || rec.checkOutTime) > new Date(existing.checkInTime || existing.checkOutTime)) {
!existing ||
new Date(rec.checkInTime || rec.checkOutTime) >
new Date(existing.checkInTime || existing.checkOutTime)
) {
uniqueMap.set(key, rec); uniqueMap.set(key, rec);
} }
}); });
const sortedFinalList = [...uniqueMap.values()].sort( const sortedFinalList = [...uniqueMap.values()].sort((a, b) =>
(a, b) => new Date(b.checkInTime || b.checkOutTime) - new Date(a.checkInTime || a.checkOutTime)
new Date(b.checkInTime || b.checkOutTime) -
new Date(a.checkInTime || a.checkOutTime)
); );
const currentDate = new Date().toLocaleDateString("en-CA"); const currentDate = new Date().toLocaleDateString("en-CA");
@ -107,6 +93,8 @@ const EmpAttendance = ({ employee }) => {
ITEMS_PER_PAGE ITEMS_PER_PAGE
); );
const openModal = (id) => { const openModal = (id) => {
setAttendanecId(id); setAttendanecId(id);
setIsModalOpen(true); setIsModalOpen(true);
@ -115,28 +103,25 @@ const EmpAttendance = ({ employee }) => {
return ( return (
<> <>
{isModalOpen && ( {isModalOpen && (
<GlobalModel size="lg" isOpen={isModalOpen} closeModal={closeModal}> <GlobalModel size="lg" isOpen={isModalOpen} closeModal={closeModal}>
<AttendLogs Id={attendanceId} /> <AttendLogs Id={attendanceId} />
</GlobalModel> </GlobalModel>
)} )}
<div className="card px-4 mt-5 py-2 " style={{ minHeight: "500px" }}> <div className="px-4 py-2 " style={{ minHeight: "500px" }}>
<div <div
className="dataTables_length text-start py-2 d-flex justify-content-between " className="dataTables_length text-start py-2 d-flex justify-content-between "
id="DataTables_Table_0_length" id="DataTables_Table_0_length"
> >
<div className="col-md-3 my-0 "> <div className="col-md-3 my-0 ">
<DateRangePicker <DateRangePicker onRangeChange={setDateRange} endDateMode="yesterday" />
DateDifference="30"
onRangeChange={setDateRange}
endDateMode="today"
/>
</div> </div>
<div className="col-md-2 m-0 text-end"> <div className="col-md-2 m-0 text-end">
<i <i
className={`bx bx-refresh cursor-pointer fs-4 ${ className={`bx bx-refresh cursor-pointer fs-4 ${isFetching ? "spin" : ""
isFetching ? "spin" : "" }`}
}`}
data-toggle="tooltip" data-toggle="tooltip"
title="Refresh" title="Refresh"
onClick={() => refetch()} onClick={() => refetch()}
@ -229,9 +214,8 @@ const EmpAttendance = ({ employee }) => {
{[...Array(totalPages)].map((_, index) => ( {[...Array(totalPages)].map((_, index) => (
<li <li
key={index} key={index}
className={`page-item ${ className={`page-item ${currentPage === index + 1 ? "active" : ""
currentPage === index + 1 ? "active" : "" }`}
}`}
> >
<button <button
className="page-link " className="page-link "
@ -242,9 +226,8 @@ const EmpAttendance = ({ employee }) => {
</li> </li>
))} ))}
<li <li
className={`page-item ${ className={`page-item ${currentPage === totalPages ? "disabled" : ""
currentPage === totalPages ? "disabled" : "" }`}
}`}
> >
<button <button
className="page-link " className="page-link "
@ -261,4 +244,4 @@ const EmpAttendance = ({ employee }) => {
); );
}; };
export default EmpAttendance; export default AttendancesEmployeeRecords;

View File

@ -51,8 +51,7 @@ const EmployeeList = () => {
const { employees, loading, setLoading, error, recallEmployeeData } = const { employees, loading, setLoading, error, recallEmployeeData } =
useEmployeesAllOrByProjectId( useEmployeesAllOrByProjectId(
showAllEmployees, showAllEmployees ,selectedProjectId,
selectedProjectId,
showInactive showInactive
); );
@ -154,6 +153,8 @@ const EmployeeList = () => {
} }
}; };
const handleAllEmployeesToggle = (e) => { const handleAllEmployeesToggle = (e) => {
const isChecked = e.target.checked; const isChecked = e.target.checked;
setShowInactive(false); setShowInactive(false);
@ -294,449 +295,450 @@ const EmployeeList = () => {
{ViewTeamMember ? ( {ViewTeamMember ? (
// <div className="row"> // <div className="row">
<div className="card p-1"> <div className="card px-0 px-sm-4">
<div className="card-datatable table-responsive pt-2"> <div className="card-datatable table-responsive pt-2">
<div <div
id="DataTables_Table_0_wrapper" id="DataTables_Table_0_wrapper"
className="dataTables_wrapper dt-bootstrap5 no-footer" className="dataTables_wrapper no-footer px-2 "
style={{ width: "98%" }}
>
<div className="d-flex flex-wrap align-items-center justify-content-between gap-3 mb-3">
{/* Switches: All Employees + Inactive */}
<div className="d-flex flex-wrap align-items-center gap-3">
{/* All Employees Switch */}
{ViewAllEmployee && (
<div className="form-check form-switch text-start">
<input
type="checkbox"
className="form-check-input"
role="switch"
id="allEmployeesCheckbox"
checked={showAllEmployees}
onChange={handleAllEmployeesToggle}
/>
<label
className="form-check-label ms-0"
htmlFor="allEmployeesCheckbox"
>
All Employees
</label>
</div>
)}
{/* Show Inactive Employees Switch */}
{showAllEmployees && (
<div className="form-check form-switch text-start">
<input
type="checkbox"
className="form-check-input"
role="switch"
id="inactiveEmployeesCheckbox"
checked={showInactive}
onChange={(e) => setShowInactive(e.target.checked)}
/>
<label
className="form-check-label ms-0"
htmlFor="inactiveEmployeesCheckbox"
>
Show Inactive Employees
</label>
</div>
)}
</div>
{/* Right side: Search + Export + Add Employee */}
<div className="d-flex flex-wrap align-items-center justify-content-end gap-3 flex-grow-1">
{/* Search Input - ALWAYS ENABLED */}
<div className="dataTables_filter">
<label className="mb-0">
<input
type="search"
value={searchText}
onChange={handleSearch}
className="form-control form-control-sm"
placeholder="Search User"
aria-controls="DataTables_Table_0"
/>
</label>
</div>
{/* Export Dropdown */}
<div className="dropdown">
<button
aria-label="Click me"
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"
href="#"
onClick={() => handleExport("print")}
>
<i className="bx bx-printer me-1"></i> Print
</a>
</li>
<li>
<a
className="dropdown-item"
href="#"
onClick={() => handleExport("csv")}
>
<i className="bx bx-file me-1"></i> CSV
</a>
</li>
<li>
<a
className="dropdown-item"
href="#"
onClick={() => handleExport("excel")}
>
<i className="bx bxs-file-export me-1"></i> Excel
</a>
</li>
<li>
<a
className="dropdown-item"
href="#"
onClick={() => handleExport("pdf")}
>
<i className="bx bxs-file-pdf me-1"></i> PDF
</a>
</li>
</ul>
</div>
{/* Add Employee Button */}
{Manage_Employee && (
<button
className="btn btn-sm btn-primary"
type="button"
onClick={() => handleEmployeeModel(null)}
>
<i className="bx bx-plus-circle me-2"></i>
<span className="d-none d-md-inline-block">
Add New Employee
</span>
</button>
)}
</div>
</div>
<table
className="datatables-users table border-top dataTable no-footer dtr-column text-nowrap"
id="DataTables_Table_0"
aria-describedby="DataTables_Table_0_info"
style={{ width: "100%" }}
ref={tableRef}
> >
<thead> <div className="d-flex flex-wrap align-items-center justify-content-between gap-3 mb-3">
<tr> {/* Switches: All Employees + Inactive */}
<th <div className="d-flex flex-wrap align-items-center gap-3">
className="sorting sorting_desc" {/* All Employees Switch */}
tabIndex="0" {ViewAllEmployee && (
aria-controls="DataTables_Table_0" <div className="form-check form-switch text-start">
rowSpan="1" <input
colSpan="2" type="checkbox"
aria-label="User: activate to sort column ascending" className="form-check-input"
aria-sort="descending" role="switch"
> id="allEmployeesCheckbox"
<div className="text-start ms-6">Name</div> checked={showAllEmployees}
</th> onChange={handleAllEmployeesToggle}
<th />
className="sorting sorting_desc d-none d-sm-table-cell" <label
tabIndex="0" className="form-check-label ms-0"
aria-controls="DataTables_Table_0" htmlFor="allEmployeesCheckbox"
rowSpan="1" >
colSpan="1" All Employees
aria-label="User: activate to sort column ascending" </label>
aria-sort="descending"
>
<div className="text-start ms-5">Email</div>
</th>
<th
className="sorting sorting_desc d-none d-sm-table-cell"
tabIndex="0"
aria-controls="DataTables_Table_0"
rowSpan="1"
colSpan="1"
aria-label="User: activate to sort column ascending"
aria-sort="descending"
>
<div className="text-start ms-5">Contact</div>
</th>
<th
className="sorting sorting_desc d-none d-sm-table-cell"
tabIndex="0"
aria-controls="DataTables_Table_0"
rowSpan="1"
colSpan="1"
aria-label="User: activate to sort column ascending"
aria-sort="descending"
>
<div className="text-start ms-5">
Official Designation
</div> </div>
</th> )}
<th {/* Show Inactive Employees Switch */}
className="sorting d-none d-md-table-cell" {showAllEmployees && (
tabIndex="0" <div className="form-check form-switch text-start">
aria-controls="DataTables_Table_0" <input
rowSpan="1" type="checkbox"
colSpan="1" className="form-check-input"
aria-label="Plan: activate to sort column ascending" role="switch"
> id="inactiveEmployeesCheckbox"
Joining Date checked={showInactive}
</th> onChange={(e)=> setShowInactive(e.target.checked)}
<th />
className="sorting" <label
tabIndex="0" className="form-check-label ms-0"
aria-controls="DataTables_Table_0" htmlFor="inactiveEmployeesCheckbox"
rowSpan="1" >
colSpan="1" Show Inactive Employees
aria-label="Billing: activate to sort column ascending" </label>
> </div>
Status )}
</th> </div>
<th
className={`sorting_disabled ${ {/* Right side: Search + Export + Add Employee */}
!Manage_Employee && "d-none" <div className="d-flex flex-wrap align-items-center justify-content-end gap-3 flex-grow-1">
}`} {/* Search Input - ALWAYS ENABLED */}
rowSpan="1" <div className="dataTables_filter">
colSpan="1" <label className="mb-0">
style={{ width: "50px" }} <input
aria-label="Actions" type="search"
> value={searchText}
Actions onChange={handleSearch}
</th> className="form-control form-control-sm"
</tr> placeholder="Search User"
</thead> aria-controls="DataTables_Table_0"
<tbody> />
{loading && ( </label>
<tr> </div>
<td colSpan={8}>
<p>Loading...</p> {/* Export Dropdown */}
</td> <div className="dropdown">
</tr> <button
)} aria-label="Click me"
{/* Conditional messages for no data or no search results */} className="btn btn-sm btn-label-secondary dropdown-toggle"
{!loading && type="button"
displayData?.length === 0 && data-bs-toggle="dropdown"
searchText && aria-expanded="false"
!showAllEmployees ? (
<tr>
<td colSpan={8}>
<small className="muted">
'{searchText}' employee not found
</small>{" "}
</td>
</tr>
) : null}
{!loading &&
displayData?.length === 0 &&
(!searchText || showAllEmployees) ? (
<tr>
<td
colSpan={8}
style={{ paddingTop: "20px", textAlign: "center" }}
> >
No Data Found <i className="bx bx-export me-2 bx-sm"></i>Export
</td> </button>
<ul className="dropdown-menu">
<li>
<a
className="dropdown-item"
href="#"
onClick={() => handleExport("print")}
>
<i className="bx bx-printer me-1"></i> Print
</a>
</li>
<li>
<a
className="dropdown-item"
href="#"
onClick={() => handleExport("csv")}
>
<i className="bx bx-file me-1"></i> CSV
</a>
</li>
<li>
<a
className="dropdown-item"
href="#"
onClick={() => handleExport("excel")}
>
<i className="bx bxs-file-export me-1"></i> Excel
</a>
</li>
<li>
<a
className="dropdown-item"
href="#"
onClick={() => handleExport("pdf")}
>
<i className="bx bxs-file-pdf me-1"></i> PDF
</a>
</li>
</ul>
</div>
{/* Add Employee Button */}
{Manage_Employee && (
<button
className="btn btn-sm btn-primary"
type="button"
onClick={() => handleEmployeeModel(null)}
>
<i className="bx bx-plus-circle me-2"></i>
<span className="d-none d-md-inline-block">
Add New Employee
</span>
</button>
)}
</div>
</div>
<table
className="datatables-users table border-top dataTable no-footer dtr-column text-nowrap"
id="DataTables_Table_0"
aria-describedby="DataTables_Table_0_info"
style={{ width: "100%" }}
ref={tableRef}
>
<thead>
<tr>
<th
className="sorting sorting_desc"
tabIndex="0"
aria-controls="DataTables_Table_0"
rowSpan="1"
colSpan="2"
aria-label="User: activate to sort column ascending"
aria-sort="descending"
>
<div className="text-start ms-6">Name</div>
</th>
<th
className="sorting sorting_desc d-none d-sm-table-cell"
tabIndex="0"
aria-controls="DataTables_Table_0"
rowSpan="1"
colSpan="1"
aria-label="User: activate to sort column ascending"
aria-sort="descending"
>
<div className="text-start ms-5">Email</div>
</th>
<th
className="sorting sorting_desc d-none d-sm-table-cell"
tabIndex="0"
aria-controls="DataTables_Table_0"
rowSpan="1"
colSpan="1"
aria-label="User: activate to sort column ascending"
aria-sort="descending"
>
<div className="text-start ms-5">Contact</div>
</th>
<th
className="sorting sorting_desc d-none d-sm-table-cell"
tabIndex="0"
aria-controls="DataTables_Table_0"
rowSpan="1"
colSpan="1"
aria-label="User: activate to sort column ascending"
aria-sort="descending"
>
<div className="text-start ms-5">Official Designation</div>
</th>
<th
className="sorting d-none d-md-table-cell"
tabIndex="0"
aria-controls="DataTables_Table_0"
rowSpan="1"
colSpan="1"
aria-label="Plan: activate to sort column ascending"
>
Joining Date
</th>
<th
className="sorting"
tabIndex="0"
aria-controls="DataTables_Table_0"
rowSpan="1"
colSpan="1"
aria-label="Billing: activate to sort column ascending"
>
Status
</th>
<th
className={`sorting_disabled ${
!Manage_Employee && "d-none"
}`}
rowSpan="1"
colSpan="1"
style={{ width: "50px" }}
aria-label="Actions"
>
Actions
</th>
</tr> </tr>
) : null} </thead>
<tbody>
{loading && (
<tr>
<td colSpan={8}>
<p>Loading...</p>
</td>
</tr>
)}
{/* Conditional messages for no data or no search results */}
{!loading &&
displayData?.length === 0 &&
searchText &&
!showAllEmployees ? (
<tr>
<td colSpan={8}>
<small className="muted">
'{searchText}' employee not found
</small>{" "}
</td>
</tr>
) : null}
{!loading &&
displayData?.length === 0 &&
(!searchText || showAllEmployees) ? (
<tr>
<td
colSpan={8}
style={{ paddingTop: "20px", textAlign: "center" }}
>
No Data Found
</td>
</tr>
) : null}
{/* Render current items */} {/* Render current items */}
{currentItems && {currentItems &&
!loading && !loading &&
currentItems.map((item) => ( currentItems.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}`)
}
className="text-heading text-truncate cursor-pointer"
>
<span className="fw-normal">
{item.firstName} {item.middleName}{" "}
{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>
{showInactive ? (
<span
className="badge bg-label-danger"
text-capitalized=""
>
Inactive
</span>
) : (
<span
className="badge bg-label-success"
text-capitalized=""
>
Active
</span>
)}
</td>
{Manage_Employee && (
<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(`/employee/${item.id}`) navigate(
`/employee/${item.id}?for=attendance`
)
} }
className="dropdown-item py-1" className="text-heading text-truncate cursor-pointer"
> >
<i className="bx bx-detail bx-sm"></i> View <span className="fw-normal">
</button> {item.firstName} {item.middleName}{" "}
<button {item.lastName}
className="dropdown-item py-1" </span>
onClick={() => { </a>
handleEmployeeModel(item.id);
}}
>
<i className="bx bx-edit bx-sm"></i> Edit
</button>
{!item.isSystem && (
<>
<button
className="dropdown-item py-1"
onClick={() =>
handleOpenDelete(item.id)
}
>
<i className="bx bx-task-x bx-sm"></i>{" "}
Suspend
</button>
<button
className="dropdown-item py-1"
type="button"
data-bs-toggle="modal"
data-bs-target="#managerole-modal"
onClick={() =>
setEmpForManageRole(item.id)
}
>
<i className="bx bx-cog bx-sm"></i>{" "}
Manage Role
</button>
</>
)}
</div> </div>
</div> </div>
</td> </td>
)} <td className="text-start d-none d-sm-table-cell">
</tr> {item.email ? (
))} <span className="text-truncate">
</tbody> <i className="bx bxs-envelope text-primary text-truncate me-2"></i>
</table> {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>
<div style={{ width: "1%" }}></div> <td className=" d-none d-md-table-cell">
{moment(item.joiningDate)?.format("DD-MMM-YYYY")}
</td>
<td>
{showInactive ? (
<span
className="badge bg-label-danger"
text-capitalized=""
>
Inactive
</span>
) : (
<span
className="badge bg-label-success"
text-capitalized=""
>
Active
</span>
)}
</td>
{Manage_Employee && (
<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 py-1"
>
<i className="bx bx-detail bx-sm"></i>{" "}
View
</button>
<button
className="dropdown-item py-1"
onClick={() => {
handleEmployeeModel(item.id);
}}
>
<i className="bx bx-edit bx-sm"></i> Edit
</button>
{!item.isSystem && (
<>
<button
className="dropdown-item py-1"
onClick={() =>
handleOpenDelete(item.id)
}
>
<i className="bx bx-task-x bx-sm"></i>{" "}
Suspend
</button>
<button
className="dropdown-item py-1"
type="button"
data-bs-toggle="modal"
data-bs-target="#managerole-modal"
onClick={() =>
setEmpForManageRole(item.id)
}
>
<i className="bx bx-cog bx-sm"></i>{" "}
Manage Role
</button>
</>
)}
</div>
</div>
</td>
)}
</tr>
))}
</tbody>
</table>
{/* Pagination */} <div style={{ width: "1%" }}></div>
{!loading && displayData.length > ITEMS_PER_PAGE && (
<nav aria-label="Page">
<ul className="pagination pagination-sm justify-content-end py-1">
<li
className={`page-item ${
currentPage === 1 ? "disabled" : ""
}`}
>
<button
className="page-link btn-xs"
onClick={() => paginate(currentPage - 1)}
>
&laquo;
</button>
</li>
{[...Array(totalPages)]?.map((_, index) => ( {/* Pagination */}
{!loading && displayData.length > ITEMS_PER_PAGE && (
<nav aria-label="Page">
<ul className="pagination pagination-sm justify-content-end py-1">
<li <li
key={index}
className={`page-item ${ className={`page-item ${
currentPage === index + 1 ? "active" : "" currentPage === 1 ? "disabled" : ""
}`}
>
<button
className="page-link btn-xs"
onClick={() => paginate(currentPage - 1)}
>
&laquo;
</button>
</li>
{[...Array(totalPages)]?.map((_, index) => (
<li
key={index}
className={`page-item ${
currentPage === index + 1 ? "active" : ""
}`}
>
<button
className="page-link"
onClick={() => paginate(index + 1)}
>
{index + 1}
</button>
</li>
))}
<li
className={`page-item ${
currentPage === totalPages ? "disabled" : ""
}`} }`}
> >
<button <button
className="page-link" className="page-link"
onClick={() => paginate(index + 1)} onClick={() => paginate(currentPage + 1)}
> >
{index + 1} &raquo;
</button> </button>
</li> </li>
))} </ul>
</nav>
<li )}
className={`page-item ${ </div>
currentPage === totalPages ? "disabled" : ""
}`}
>
<button
className="page-link"
onClick={() => paginate(currentPage + 1)}
>
&raquo;
</button>
</li>
</ul>
</nav>
)}
</div> </div>
</div> </div>
</div>
) : (
// </div> // </div>
) : (
<div className="card"> <div className="card">
<div className="text-center"> <div className="text-center">
<i className="fa-solid fa-triangle-exclamation fs-5"></i> <i className="fa-solid fa-triangle-exclamation fs-5"></i>

View File

@ -1,27 +1,26 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import { useSearchParams, useParams, useNavigate } from "react-router-dom"; import EmpProfile from "../../components/Employee/EmpProfile";
import { useSelector } from "react-redux"; import axios from "axios";
import Breadcrumb from "../../components/common/Breadcrumb";
import EmployeeNav from "../../components/Employee/EmployeeNav";
import { useSearchParams, useParams } from "react-router-dom";
import { getCachedData } from "../../slices/apiDataManager";
import { import {
useEmployeeProfile, useEmployeeProfile,
useEmployees, useEmployees,
useEmployeesByProject, useEmployeesByProject,
} from "../../hooks/useEmployees"; } from "../../hooks/useEmployees";
import { useProfile } from "../../hooks/useProfile"; import { useProfile } from "../../hooks/useProfile";
import { getCachedData } from "../../slices/apiDataManager";
import { useSelector } from "react-redux";
import EmployeeRepository from "../../repositories/EmployeeRepository"; import EmployeeRepository from "../../repositories/EmployeeRepository";
import { ComingSoonPage } from "../Misc/ComingSoonPage"; import { ComingSoonPage } from "../Misc/ComingSoonPage";
import { useNavigate } from "react-router-dom";
import Breadcrumb from "../../components/common/Breadcrumb"; import Avatar from "../../components/common/Avatar";
import EmployeeNav from "../../components/Employee/EmployeeNav"; import AttendancesEmployeeRecords from "./AttendancesEmployeeRecords";
import EmpProfile from "../../components/Employee/EmpProfile";
import EmpAttendance from "../../components/Employee/EmpAttendance";
import ManageEmployee from "../../components/Employee/ManageEmployee"; import ManageEmployee from "../../components/Employee/ManageEmployee";
import EmpBanner from "../../components/Employee/EmpBanner"; import { useChangePassword } from "../../components/Context/ChangePasswordContext";
import EmpDashboard from "../../components/Employee/EmpDashboard"; import GlobalModel from "../../components/common/GlobalModel";
import EmpDocuments from "../../components/Employee/EmpDocuments";
import EmpActivities from "../../components/Employee/EmpActivities";
const EmployeeProfile = () => { const EmployeeProfile = () => {
const { profile } = useProfile(); const { profile } = useProfile();
@ -33,7 +32,7 @@ const EmployeeProfile = () => {
const [SearchParams] = useSearchParams(); const [SearchParams] = useSearchParams();
const tab = SearchParams.get("for"); const tab = SearchParams.get("for");
const [activePill, setActivePill] = useState(tab || "profile"); const [activePill, setActivePill] = useState(tab);
const [currentEmployee, setCurrentEmployee] = useState(); const [currentEmployee, setCurrentEmployee] = useState();
const [showModal, setShowModal] = useState(false); const [showModal, setShowModal] = useState(false);
@ -41,6 +40,8 @@ const EmployeeProfile = () => {
setActivePill(pillKey); setActivePill(pillKey);
}; };
const fetchEmployeeProfile = async (employeeID) => { const fetchEmployeeProfile = async (employeeID) => {
try { try {
const resp = await EmployeeRepository.getEmployeeProfile(employeeID); const resp = await EmployeeRepository.getEmployeeProfile(employeeID);
@ -61,24 +62,17 @@ const EmployeeProfile = () => {
const renderContent = () => { const renderContent = () => {
if (loading) return <div>Loading</div>; if (loading) return <div>Loading</div>;
switch (activePill) { switch (activePill) {
case "profile": {
return (
<>
<EmpDashboard profile={currentEmployee} />
</>
);
}
case "attendance": { case "attendance": {
return ( return (
<> <>
<EmpAttendance employee={employeeId} /> <AttendancesEmployeeRecords employee={employeeId} />
</> </>
); );
} }
case "documents": { case "dcoument": {
return ( return (
<> <>
<EmpDocuments /> <ComingSoonPage />
</> </>
); );
break; break;
@ -86,7 +80,7 @@ const EmployeeProfile = () => {
case "activities": { case "activities": {
return ( return (
<> <>
<EmpActivities employee={currentEmployee} /> <ComingSoonPage />
</> </>
); );
break; break;
@ -104,8 +98,14 @@ const EmployeeProfile = () => {
if (loading) { if (loading) {
return <div>Loading...</div>; return <div>Loading...</div>;
} }
const { openChangePassword } = useChangePassword();
return ( return (
<> <>
{showModal && (
<GlobalModel size="lg" isOpen={showModal} closeModal={() => setShowModal(false)}>
<ManageEmployee employeeId={employeeId} onClosed={() => setShowModal(false)} />
</GlobalModel>
)}
<div className="container-fluid"> <div className="container-fluid">
<Breadcrumb <Breadcrumb
data={[ data={[
@ -114,25 +114,152 @@ const EmployeeProfile = () => {
{ label: "Profile", link: null }, { label: "Profile", link: null },
]} ]}
></Breadcrumb> ></Breadcrumb>
<div className="row"> <div className="row">
<div className="col-12 "> <div className="col-12 col-md-8 col-lg-4 order-1 order-lg-1">
<EmpBanner <div className="row">
profile={currentEmployee} <div className="col-12 mb-4">
loggedInUser={profile} <div className="card">
></EmpBanner> <div className="card-body">
<div className="d-flex flex-row flex-lg-column">
<div className="d-flex flex-column justify-content-center align-items-center text-center">
<Avatar
firstName={`${currentEmployee?.firstName}`}
lastName={`${currentEmployee?.lastName}`}
size={"lg"}
/>
<div className="py-2">
<p className="h6">{`${currentEmployee?.firstName} ${currentEmployee?.lastName}`}</p>
</div>
</div>
<div className="w-100 d-flex flex-column justify-content-start">
<div className="mt-3 w-100">
<h6 className="mb-2 text-muted text-start">
Employee Info
</h6>
<table className="table table-borderless mb-3">
<tbody>
<tr>
<td className="fw-medium text-start">Email:</td>
<td className="text-start">
{currentEmployee?.email || <em>NA</em>}
</td>
</tr>
<tr>
<td className="fw-medium text-start text-nowrap">
Phone Number:
</td>
<td className="text-start">
{currentEmployee?.phoneNumber || <em>NA</em>}
</td>
</tr>
<tr>
<td className="fw-medium text-start" style={{ width: '120px' }}>
Emergency Contact Person:
</td>
<td className="text-start align-bottom">
{currentEmployee?.emergencyContactPerson || <em>NA</em>}
</td>
</tr>
<tr>
<td className="fw-medium text-start">
Emergency Contact Number:
</td>
<td className="text-start align-bottom">
{currentEmployee?.emergencyPhoneNumber || <em>NA</em>}
</td>
</tr>
<tr>
<td className="fw-medium text-start">
Gender:
</td>
<td className="text-start">
{currentEmployee?.gender || <em>NA</em>}
</td>
</tr>
<tr>
<td className="fw-medium text-start">
Birth Date:
</td>
<td className="text-start">
{currentEmployee?.birthDate ? (
new Date(
currentEmployee.birthDate
).toLocaleDateString()
) : (
<em>NA</em>
)}
</td>
</tr>
<tr>
<td className="fw-medium text-start">
Joining Date:
</td>
<td className="text-start">
{currentEmployee?.joiningDate ? (
new Date(
currentEmployee.joiningDate
).toLocaleDateString()
) : (
<em>NA</em>
)}
</td>
</tr>
<tr>
<td className="fw-medium text-start">
Job Role:
</td>
<td className="text-start">
{currentEmployee?.jobRole || <em>NA</em>}
</td>
</tr>
<tr>
<td className="fw-medium text-start align-top" >
Address:
</td>
<td className="text-start">
{currentEmployee?.currentAddress || <em>NA</em>}
</td>
</tr>
</tbody>
</table>
</div>
<button
className="btn btn-primary btn-block"
onClick={() => setShowModal(true)}
>
Edit Profile
</button>
{currentEmployee?.id == profile?.employeeInfo?.id && (
<button
className="btn btn-outline-primary btn-block mt-2"
onClick={() => openChangePassword()}
>
Change Password
</button>
)}
</div>
</div>
</div>
</div>
</div>
</div>
</div> </div>
</div>{" "}
<div className="row"> <div className="col-12 col-lg-8 order-2 order-lg-2 mb-4">
<div className="col-12 "> <div className="row">
<EmployeeNav <EmployeeNav
onPillClick={handlePillClick} onPillClick={handlePillClick}
activePill={activePill} activePill={activePill}
/> />
</div>
<div className="card">
<div className="row row-bordered g-0">{renderContent()}</div>
</div>
</div> </div>
</div> </div>
<div className="row">
<div className=" ">{renderContent()}</div>
</div>
</div> </div>
</> </>
); );

View File

@ -6,41 +6,32 @@ const ProjectRepository = {
api.get(`/api/project/details/${projetid}`), api.get(`/api/project/details/${projetid}`),
getProjectAllocation: (projetid) => getProjectAllocation: (projetid) =>
api.get(`api/project/allocation/${projetid}`), api.get( `api/project/allocation/${ projetid }` ),
getEmployeesByProject: (projectId) => getEmployeesByProject:(projectId)=>api.get(`/api/Project/employees/get/${projectId}`),
api.get(`/api/Project/employees/get/${projectId}`),
manageProject: (data) => api.post("/api/project", data), manageProject: (data) => api.post("/api/project", data),
// updateProject: (data) => api.post("/api/project/update", data), // updateProject: (data) => api.post("/api/project/update", data),
manageProjectAllocation: (data) => api.post("/api/project/allocation", data), manageProjectAllocation: ( data ) => api.post( "/api/project/allocation", data ),
manageProjectInfra: (data) => api.post("/api/project/manage-infra", data), manageProjectInfra: (data) => api.post("/api/project/manage-infra", data),
manageProjectTasks: (data) => api.post("/api/project/task", data), manageProjectTasks: ( data ) => api.post( "/api/project/task", data ),
deleteProjectTask: (id) => api.delete(`/api/project/task/${id}`), deleteProjectTask:(id)=> api.delete(`/api/project/task/${id}`),
updateProject: (id, data) => api.put(`/api/project/update/${id}`, data), updateProject: (id, data) => api.put(`/api/project/update/${id}`, data),
deleteProject: (id) => api.delete(`/projects/${id}`), deleteProject: ( id ) => api.delete( `/projects/${ id }` ),
getProjectsByEmployee: (id) => getProjectsByEmployee: ( id ) => api.get( `/api/project/assigned-projects/${ id }` ),
api.get(`/api/project/assigned-projects/${id}`), updateProjectsByEmployee:(id,data)=>api.post(`/api/project/assign-projects/${id}`,data),
getProjectsAllocationByEmployee: (id) => projectNameList: () => api.get( "/api/project/list/basic" ),
api.get(`/api/project/allocation-histery/${id}`),
updateProjectsByEmployee: (id, data) => getProjectDetails:(id)=>api.get(`/api/project/details/${id}`),
api.post(`/api/project/assign-projects/${id}`, data), getProjectInfraByproject: ( id ) => api.get( `/api/project/infra-details/${ id }` ),
projectNameList: () => api.get("/api/project/list/basic"), getProjectTasksByWorkArea:(id)=>api.get(`/api/project/tasks/${id}`)
getProjectDetails: (id) => api.get(`/api/project/details/${id}`),
getProjectInfraByproject: (id) => api.get(`/api/project/infra-details/${id}`),
getProjectTasksByWorkArea: (id) => api.get(`/api/project/tasks/${id}`),
getProjectTasksByEmployee: (id, fromDate, toDate) =>
api.get(
`/api/project/tasks-employee/${id}?fromDate=${fromDate}&toDate=${toDate}`
),
}; };
export const TasksRepository = { export const TasksRepository = {
assignTask: (data) => api.post("/api/task/assign", data), assignTask: ( data ) => api.post( "/api/task/assign", data ),
// reportTask:(data)=>api.post("/api/task/report",data) // reportTask:(data)=>api.post("/api/task/report",data)
}; }
export default ProjectRepository; export default ProjectRepository;