Compare commits
225 Commits
379d9ecb8b
...
93c1fb1844
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
93c1fb1844 | ||
|
|
0886990f9d | ||
|
|
c7b93006d8 | ||
|
|
b71ca1c7fb | ||
|
|
1d43470783 | ||
|
|
33f5bb3517 | ||
|
|
e3731cab5f | ||
|
|
71631fa68d | ||
|
|
0b99238fa8 | ||
|
|
376ead7967 | ||
|
|
51c02c7156 | ||
|
|
977397d31f | ||
|
|
b77389284c | ||
|
|
29ef1e4016 | ||
|
|
8d966fc5c0 | ||
|
|
901f633177 | ||
|
|
d23a090cd5 | ||
|
|
456fa6d385 | ||
|
|
7bf3d69174 | ||
|
|
d5d5ecafa9 | ||
|
|
49dfc084c0 | ||
|
|
0026de943b | ||
|
|
3e61a9959e | ||
|
|
bc657eebca | ||
| c4288fe35a | |||
| f6634eb527 | |||
|
|
763d81e3b1 | ||
|
|
c78c136467 | ||
|
|
360f3b2352 | ||
|
|
0eaea6a232 | ||
|
|
08ace9b5ba | ||
|
|
7de4de9b32 | ||
|
|
cd7422c991 | ||
|
|
e739a380f7 | ||
|
|
2eee4a1f6a | ||
|
|
b0e3b767d3 | ||
|
|
49a3bec527 | ||
|
|
289f4063f9 | ||
|
|
ffd23dc11c | ||
|
|
941e74fcbb | ||
|
|
94daa0d4c2 | ||
|
|
755ea1b0ee | ||
|
|
0082a60e02 | ||
|
|
7d3a7adf95 | ||
|
|
6d02511847 | ||
|
|
1f8ba16447 | ||
|
|
bae8b130de | ||
|
|
a35e8b645b | ||
|
|
875ba214dd | ||
|
|
bc220180c4 | ||
|
|
8a57d3e978 | ||
|
|
c9960a1273 | ||
|
|
ddaba97c8f | ||
|
|
14698e92fe | ||
|
|
ec32d9160c | ||
|
|
6346f132bd | ||
|
|
3dd901a81f | ||
|
|
f9ad47ef54 | ||
|
|
62a044261a | ||
|
|
3c75222dd7 | ||
|
|
77e3082000 | ||
|
|
db75cec8e7 | ||
|
|
a9f3b27cb3 | ||
|
|
813032ead2 | ||
|
|
eb6d4e413d | ||
|
|
16389bf102 | ||
|
|
a87d2c9143 | ||
|
|
2d1d32ee16 | ||
|
|
c77dc76079 | ||
|
|
04d64e57c9 | ||
|
|
39ef265b56 | ||
|
|
cd487dee49 | ||
|
|
fba983f41d | ||
|
|
5ef8bed2b8 | ||
|
|
201a8881a5 | ||
|
|
ed489842c6 | ||
|
|
24ffb82616 | ||
|
|
0695fb6737 | ||
|
|
45a300e540 | ||
|
|
b4157354f7 | ||
|
|
8f9bfcae6b | ||
|
|
47ecbcdafd | ||
|
|
41d9db6fcc | ||
|
|
330ac0ff62 | ||
|
|
1b399c1ebf | ||
|
|
360bfc5650 | ||
|
|
1d1f82feb6 | ||
|
|
195adbeb72 | ||
|
|
d32b954d94 | ||
|
|
c7e308586a | ||
|
|
df1838dbba | ||
|
|
276c97a734 | ||
|
|
449debc0cf | ||
|
|
560ee8fe27 | ||
|
|
dd0ec9d018 | ||
|
|
30b27ed2bb | ||
|
|
ee9c80749f | ||
|
|
2fc4db1f87 | ||
|
|
7a8bbaf561 | ||
|
|
3ff8066803 | ||
|
|
a965116aa5 | ||
|
|
5a701ca9d7 | ||
|
|
ded8ab7752 | ||
|
|
6a8332b606 | ||
|
|
51e48e632a | ||
|
|
8999d7bb47 | ||
|
|
5e3c833ca6 | ||
|
|
3f5b79dc5c | ||
|
|
f748eecf14 | ||
|
|
df5c2e4397 | ||
|
|
0d09bfda04 | ||
|
|
1b575a7d5f | ||
|
|
17cceeb97c | ||
|
|
eb8140ebac | ||
|
|
c089ee47cf | ||
|
|
6010e630e8 | ||
|
|
0d249c7cdb | ||
|
|
5fd6f26653 | ||
|
|
2643bbbe59 | ||
|
|
d40d4c59f2 | ||
|
|
bfba4133f4 | ||
|
|
31ca02fcd8 | ||
|
|
105b5c6dcc | ||
|
|
2607f852fb | ||
|
|
54de8df956 | ||
|
|
4e19c2a547 | ||
|
|
43b1b1ffe2 | ||
|
|
c784d18427 | ||
|
|
0e38709435 | ||
|
|
4f70d8cb17 | ||
|
|
24d8688069 | ||
|
|
5a3dbe466f | ||
|
|
76bbfee4fc | ||
|
|
3e251b3d47 | ||
|
|
dcc17dea0c | ||
|
|
37066904e3 | ||
|
|
0c44ae76f8 | ||
|
|
2688c95f47 | ||
|
|
8f6c4b0814 | ||
|
|
7d489d177d | ||
|
|
d9053837a6 | ||
|
|
7feaac1a94 | ||
|
|
e3cfc1c073 | ||
|
|
1a7636ad82 | ||
|
|
96d1fd648f | ||
|
|
f9c3c136b3 | ||
|
|
93c0961751 | ||
|
|
0fc460b38f | ||
|
|
7514e73d0c | ||
|
|
038ff416e1 | ||
|
|
69abe1bd42 | ||
|
|
3a6be65a48 | ||
|
|
597fa279ea | ||
|
|
61f0703096 | ||
|
|
a9a5206062 | ||
|
|
75897a2ab4 | ||
|
|
1300ea33b6 | ||
|
|
6cad6ac6e8 | ||
|
|
2d84b489f5 | ||
|
|
7b2a94b5a4 | ||
|
|
a6a4435a77 | ||
|
|
bc50e58150 | ||
|
|
f8f43b62c6 | ||
|
|
dbc1ae2c63 | ||
|
|
76ce07d4d3 | ||
|
|
65319cac7d | ||
|
|
6fec5b68e3 | ||
|
|
41494a0816 | ||
|
|
4753117d7b | ||
|
|
bb6aaeee18 | ||
|
|
bef8a28db2 | ||
|
|
f11f358f49 | ||
|
|
65f1d32bb8 | ||
|
|
7c67af41c3 | ||
|
|
b082aa370b | ||
|
|
15967ce2fc | ||
|
|
c83960c040 | ||
|
|
d10cbdd4bd | ||
|
|
42b769c1b5 | ||
|
|
ada8856b3b | ||
|
|
86e9854071 | ||
|
|
ba04e041b8 | ||
|
|
3d43facdae | ||
|
|
3e1f93d4f1 | ||
|
|
09b1664ac7 | ||
|
|
f62129e3ac | ||
|
|
cdec17735f | ||
|
|
8ece56da52 | ||
|
|
22dc355f7d | ||
|
|
f7c9c7c7ff | ||
|
|
02492b0405 | ||
|
|
283e13985d | ||
|
|
a319171674 | ||
|
|
07a402d28d | ||
|
|
354c653240 | ||
|
|
33f6220622 | ||
|
|
e8504c6627 | ||
|
|
5b3b6904bf | ||
|
|
1e3a1f0365 | ||
|
|
8d7fcc62a7 | ||
|
|
5836a24aed | ||
|
|
8c0ab1102b | ||
|
|
b4081e73bf | ||
|
|
a3428fed85 | ||
|
|
bf0af60c47 | ||
|
|
cecff08ba2 | ||
|
|
8c15cacc04 | ||
|
|
3393eaf48d | ||
|
|
c672e44c76 | ||
|
|
a1e75bf7dd | ||
| 655db6ac74 | |||
| 176535f53f | |||
| cfd5486fe2 | |||
| 3486a6bc3a | |||
| 412125e422 | |||
| cf8a67bc2c | |||
| 18d848b697 | |||
| 78bc8802d7 | |||
| 5df397488a | |||
| 4d1d3f8cca | |||
| 493689fb1a | |||
|
|
80d3434bbf | ||
| 346e7b1d1d | |||
| b697943787 | |||
| 7e05cfbd61 |
@ -21,7 +21,7 @@ export const ReportTask = ({ report, closeModal, refetch }) => {
|
|||||||
required_error: "Completed Work must be a number",
|
required_error: "Completed Work must be a number",
|
||||||
invalid_type_error: "Completed Work must be a number",
|
invalid_type_error: "Completed Work must be a number",
|
||||||
})
|
})
|
||||||
.min(1, "Completed Work must be greater than 0")
|
.min(0, "Completed Work must be greater than 0")
|
||||||
.max(maxPending, {
|
.max(maxPending, {
|
||||||
message: `Completed task cannot exceed total pending tasks: ${maxPending}`,
|
message: `Completed task cannot exceed total pending tasks: ${maxPending}`,
|
||||||
})
|
})
|
||||||
|
|||||||
79
src/components/Charts/ProgressDonutChart.jsx
Normal file
79
src/components/Charts/ProgressDonutChart.jsx
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import React from "react";
|
||||||
|
import ReactApexChart from "react-apexcharts";
|
||||||
|
|
||||||
|
const ProgressDonutChart = ({ completed = 0, planned = 1 }) => {
|
||||||
|
const percentage = planned > 0 ? Math.round((completed / planned) * 100) : 0;
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
chart: {
|
||||||
|
height: 10,
|
||||||
|
type: "radialBar",
|
||||||
|
toolbar: { show: false },
|
||||||
|
},
|
||||||
|
plotOptions: {
|
||||||
|
radialBar: {
|
||||||
|
startAngle: 0,
|
||||||
|
endAngle: 360,
|
||||||
|
hollow: {
|
||||||
|
margin: 0,
|
||||||
|
size: "10%",
|
||||||
|
background: "#fff",
|
||||||
|
dropShadow: {
|
||||||
|
enabled: true,
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
blur: 3,
|
||||||
|
opacity: 0.45,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
track: {
|
||||||
|
background: "#f5f5f5",
|
||||||
|
strokeWidth: "10%",
|
||||||
|
dropShadow: { enabled: false },
|
||||||
|
},
|
||||||
|
dataLabels: {
|
||||||
|
show: true,
|
||||||
|
name: {
|
||||||
|
offsetY: -10,
|
||||||
|
color: "#888",
|
||||||
|
fontSize: "14px",
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
formatter: (val) => `${val}%`,
|
||||||
|
color: "#111",
|
||||||
|
fontSize: "11px",
|
||||||
|
show: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fill: {
|
||||||
|
type: "gradient",
|
||||||
|
gradient: {
|
||||||
|
shade: "dark",
|
||||||
|
type: "horizontal",
|
||||||
|
shadeIntensity: 0.5,
|
||||||
|
gradientToColors: ["#ABE5A1"],
|
||||||
|
opacityFrom: 1,
|
||||||
|
opacityTo: 1,
|
||||||
|
stops: [0, 100],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
stroke: {
|
||||||
|
lineCap: "round",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div id="chart">
|
||||||
|
<ReactApexChart
|
||||||
|
options={options}
|
||||||
|
series={[percentage]}
|
||||||
|
type="radialBar"
|
||||||
|
height={100}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ProgressDonutChart;
|
||||||
@ -5,12 +5,13 @@ import useMaster from "../../hooks/masterHook/useMaster";
|
|||||||
import { useForm, Controller } from "react-hook-form";
|
import { useForm, Controller } from "react-hook-form";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { getCachedData } from "../../slices/apiDataManager";
|
import { clearCacheKey, getCachedData } from "../../slices/apiDataManager";
|
||||||
import { useEmployeesAllOrByProjectId } from "../../hooks/useEmployees";
|
import { useEmployeesAllOrByProjectId } from "../../hooks/useEmployees";
|
||||||
import { TasksRepository } from "../../repositories/ProjectRepository";
|
import { TasksRepository } from "../../repositories/ProjectRepository";
|
||||||
import showToast from "../../services/toastService";
|
import showToast from "../../services/toastService";
|
||||||
|
import { useProjectDetails } from "../../hooks/useProjects";
|
||||||
|
|
||||||
const AssignRoleModel = ({ assignData, onClose }) => {
|
const AssignRoleModel = ({ assignData, onClose, setAssigned }) => {
|
||||||
// Calculate maxPlanned based on assignData
|
// Calculate maxPlanned based on assignData
|
||||||
const maxPlanned =
|
const maxPlanned =
|
||||||
assignData?.workItem?.workItem?.plannedWork -
|
assignData?.workItem?.workItem?.plannedWork -
|
||||||
@ -50,11 +51,11 @@ const AssignRoleModel = ({ assignData, onClose }) => {
|
|||||||
// Initialize Bootstrap Popovers on component mount
|
// Initialize Bootstrap Popovers on component mount
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Check if Bootstrap is available globally
|
// Check if Bootstrap is available globally
|
||||||
if (typeof bootstrap !== 'undefined') {
|
if (typeof bootstrap !== "undefined") {
|
||||||
if (infoRef.current) {
|
if (infoRef.current) {
|
||||||
new bootstrap.Popover(infoRef.current, {
|
new bootstrap.Popover(infoRef.current, {
|
||||||
trigger: 'focus',
|
trigger: "focus",
|
||||||
placement: 'right',
|
placement: "right",
|
||||||
html: true,
|
html: true,
|
||||||
content: `<div>Total Pending tasks of the Activity</div>`,
|
content: `<div>Total Pending tasks of the Activity</div>`,
|
||||||
});
|
});
|
||||||
@ -62,8 +63,8 @@ const AssignRoleModel = ({ assignData, onClose }) => {
|
|||||||
|
|
||||||
if (infoRef1.current) {
|
if (infoRef1.current) {
|
||||||
new bootstrap.Popover(infoRef1.current, {
|
new bootstrap.Popover(infoRef1.current, {
|
||||||
trigger: 'focus',
|
trigger: "focus",
|
||||||
placement: 'right',
|
placement: "right",
|
||||||
html: true,
|
html: true,
|
||||||
content: `<div>Target task for today</div>`,
|
content: `<div>Target task for today</div>`,
|
||||||
});
|
});
|
||||||
@ -72,7 +73,6 @@ const AssignRoleModel = ({ assignData, onClose }) => {
|
|||||||
console.warn("Bootstrap is not available. Popovers might not function.");
|
console.warn("Bootstrap is not available. Popovers might not function.");
|
||||||
}
|
}
|
||||||
}, []); // Empty dependency array ensures this runs once on mount
|
}, []); // Empty dependency array ensures this runs once on mount
|
||||||
|
|
||||||
// Redux state and hooks
|
// Redux state and hooks
|
||||||
const selectedProject = useSelector(
|
const selectedProject = useSelector(
|
||||||
(store) => store.localVariables.projectId
|
(store) => store.localVariables.projectId
|
||||||
@ -173,6 +173,8 @@ const AssignRoleModel = ({ assignData, onClose }) => {
|
|||||||
await TasksRepository.assignTask(formattedData);
|
await TasksRepository.assignTask(formattedData);
|
||||||
showToast("Task Successfully Assigned", "success"); // Show success toast
|
showToast("Task Successfully Assigned", "success"); // Show success toast
|
||||||
reset(); // Reset form fields
|
reset(); // Reset form fields
|
||||||
|
clearCacheKey("projectInfo");
|
||||||
|
setAssigned(formattedData.plannedTask)
|
||||||
onClose(); // Close the modal
|
onClose(); // Close the modal
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error assigning task:", error); // Log the full error for debugging
|
console.error("Error assigning task:", error); // Log the full error for debugging
|
||||||
@ -205,7 +207,7 @@ const AssignRoleModel = ({ assignData, onClose }) => {
|
|||||||
<div className="mb-1">
|
<div className="mb-1">
|
||||||
<p className="mb-0">
|
<p className="mb-0">
|
||||||
<span className="text-dark text-start d-flex align-items-center flex-wrap form-text">
|
<span className="text-dark text-start d-flex align-items-center flex-wrap form-text">
|
||||||
<p className="me-2 m-0 font-bold">Work Location :</p>
|
<span className="me-2 m-0 font-bold">Work Location :</span>
|
||||||
{[
|
{[
|
||||||
assignData?.building?.name,
|
assignData?.building?.name,
|
||||||
assignData?.floor?.floorName,
|
assignData?.floor?.floorName,
|
||||||
@ -303,7 +305,9 @@ const AssignRoleModel = ({ assignData, onClose }) => {
|
|||||||
type="checkbox"
|
type="checkbox"
|
||||||
id={`employee-${emp?.id}`}
|
id={`employee-${emp?.id}`}
|
||||||
value={emp.id}
|
value={emp.id}
|
||||||
checked={field.value?.includes(emp.id)}
|
checked={field.value?.includes(
|
||||||
|
emp.id
|
||||||
|
)}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
handleCheckboxChange(e, emp);
|
handleCheckboxChange(e, emp);
|
||||||
}}
|
}}
|
||||||
@ -311,7 +315,10 @@ const AssignRoleModel = ({ assignData, onClose }) => {
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<div className="flex-grow-1">
|
<div className="flex-grow-1">
|
||||||
<p className="mb-0" style={{ fontSize: "13px" }}>
|
<p
|
||||||
|
className="mb-0"
|
||||||
|
style={{ fontSize: "13px" }}
|
||||||
|
>
|
||||||
{emp.firstName} {emp.lastName}
|
{emp.firstName} {emp.lastName}
|
||||||
</p>
|
</p>
|
||||||
<small
|
<small
|
||||||
@ -333,7 +340,9 @@ const AssignRoleModel = ({ assignData, onClose }) => {
|
|||||||
})
|
})
|
||||||
) : (
|
) : (
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
<p className="text-center">No employees found for the selected role.</p>
|
<p className="text-center">
|
||||||
|
No employees found for the selected role.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@ -387,23 +396,37 @@ const AssignRoleModel = ({ assignData, onClose }) => {
|
|||||||
|
|
||||||
{!loading && errors.selectedEmployees && (
|
{!loading && errors.selectedEmployees && (
|
||||||
<div className="danger-text mt-1">
|
<div className="danger-text mt-1">
|
||||||
<p>{errors.selectedEmployees.message}</p> {/* Use message from Zod schema */}
|
<p>{errors.selectedEmployees.message}</p>{" "}
|
||||||
|
{/* Use message from Zod schema */}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Pending Task of Activity section */}
|
{/* Pending Task of Activity section */}
|
||||||
<div className="col-md text-start mx-0 px-0">
|
<div className="col-md text-start mx-0 px-0">
|
||||||
<div className="form-check form-check-inline mt-3 px-1">
|
<div className="form-check form-check-inline mt-3 px-1">
|
||||||
<label className="form-text text-dark align-items-center d-flex" htmlFor="inlineCheckbox1">
|
<label
|
||||||
|
className="form-text text-dark align-items-center d-flex"
|
||||||
|
htmlFor="inlineCheckbox1"
|
||||||
|
>
|
||||||
Pending Task of Activity :
|
Pending Task of Activity :
|
||||||
<label className="form-check-label fs-7 ms-4" htmlFor="inlineCheckbox1">
|
<label
|
||||||
|
className="form-check-label fs-7 ms-4"
|
||||||
|
htmlFor="inlineCheckbox1"
|
||||||
|
>
|
||||||
<strong>
|
<strong>
|
||||||
{assignData?.workItem?.workItem?.plannedWork - assignData?.workItem?.workItem?.completedWork}
|
{assignData?.workItem?.workItem?.plannedWork -
|
||||||
|
assignData?.workItem?.workItem?.completedWork}
|
||||||
</strong>{" "}
|
</strong>{" "}
|
||||||
<u>{assignData?.workItem?.workItem?.activityMaster?.unitOfMeasurement}</u>
|
<u>
|
||||||
|
{
|
||||||
|
assignData?.workItem?.workItem?.activityMaster
|
||||||
|
?.unitOfMeasurement
|
||||||
|
}
|
||||||
|
</u>
|
||||||
</label>
|
</label>
|
||||||
|
<div
|
||||||
<div style={{ display: "flex", alignItems: "center" }}>
|
style={{ display: "flex", alignItems: "center" }}
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
ref={infoRef}
|
ref={infoRef}
|
||||||
tabIndex="0"
|
tabIndex="0"
|
||||||
@ -439,10 +462,14 @@ const AssignRoleModel = ({ assignData, onClose }) => {
|
|||||||
className="text-dark text-start d-flex align-items-center flex-wrap form-text"
|
className="text-dark text-start d-flex align-items-center flex-wrap form-text"
|
||||||
htmlFor="inlineCheckbox1"
|
htmlFor="inlineCheckbox1"
|
||||||
>
|
>
|
||||||
<span>Target for Today</span> <span style={{ marginLeft: '46px' }}>:</span>
|
<span>Target for Today</span>
|
||||||
|
<span style={{ marginLeft: "46px" }}>:</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div className="form-check form-check-inline col-sm-3 mt-2" style={{ marginLeft: '-28px' }}>
|
<div
|
||||||
|
className="form-check form-check-inline col-sm-3 mt-2"
|
||||||
|
style={{ marginLeft: "-28px" }}
|
||||||
|
>
|
||||||
<Controller
|
<Controller
|
||||||
name="plannedTask"
|
name="plannedTask"
|
||||||
control={control}
|
control={control}
|
||||||
@ -455,10 +482,18 @@ const AssignRoleModel = ({ assignData, onClose }) => {
|
|||||||
id="defaultFormControlInput"
|
id="defaultFormControlInput"
|
||||||
aria-describedby="defaultFormControlHelp"
|
aria-describedby="defaultFormControlHelp"
|
||||||
/>
|
/>
|
||||||
<span style={{ paddingLeft: '6px' }}>
|
<span style={{ paddingLeft: "6px" }}>
|
||||||
{assignData?.workItem?.workItem?.activityMaster?.unitOfMeasurement}
|
{
|
||||||
|
assignData?.workItem?.workItem?.activityMaster
|
||||||
|
?.unitOfMeasurement
|
||||||
|
}
|
||||||
</span>
|
</span>
|
||||||
<div style={{ display: "flex", alignItems: "center" }}>
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
ref={infoRef1}
|
ref={infoRef1}
|
||||||
tabIndex="0"
|
tabIndex="0"
|
||||||
@ -489,16 +524,20 @@ const AssignRoleModel = ({ assignData, onClose }) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{errors.plannedTask && (
|
{errors.plannedTask && (
|
||||||
<div className="danger-text mt-1">{errors.plannedTask.message}</div>
|
<div className="danger-text mt-1">
|
||||||
|
{errors.plannedTask.message}
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{isHelpVisible && (
|
{isHelpVisible && (
|
||||||
<div
|
<div
|
||||||
className="position-absolute bg-white border p-2 rounded shadow"
|
className="position-absolute bg-white border p-2 rounded shadow"
|
||||||
style={{ zIndex: 10, marginLeft: '10px' }}
|
style={{ zIndex: 10, marginLeft: "10px" }}
|
||||||
>
|
>
|
||||||
{/* Add your help content here */}
|
{/* Add your help content here */}
|
||||||
<p className="mb-0">Enter the target value for today's task.</p>
|
<p className="mb-0">
|
||||||
|
Enter the target value for today's task.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -25,7 +25,7 @@ const Floor = ({ floor, workAreas, forBuilding }) => {
|
|||||||
</div> */}
|
</div> */}
|
||||||
<div className="col-12 ps-8">
|
<div className="col-12 ps-8">
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col">
|
<div className="d-flex col-5">
|
||||||
{" "}
|
{" "}
|
||||||
<span className="fw-semibold text-primary">
|
<span className="fw-semibold text-primary">
|
||||||
Floor:
|
Floor:
|
||||||
@ -34,6 +34,13 @@ const Floor = ({ floor, workAreas, forBuilding }) => {
|
|||||||
{floor.floorName}
|
{floor.floorName}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="text-start col-5">
|
||||||
|
{" "}
|
||||||
|
<span className="fw-semibold text-primary">
|
||||||
|
Work Area:
|
||||||
|
</span>{" "}
|
||||||
|
<span className="fw-normal text-danger">Not Available</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -68,7 +68,6 @@ const InfraTable = ({ buildings }) => {
|
|||||||
showToast("Failed to save floor", "error");
|
showToast("Failed to save floor", "error");
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
||||||
showToast("Error occurred while saving floor", "error");
|
showToast("Error occurred while saving floor", "error");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -95,14 +94,14 @@ const InfraTable = ({ buildings }) => {
|
|||||||
No floors have been added yet. Start by adding floors to manage
|
No floors have been added yet. Start by adding floors to manage
|
||||||
this building.
|
this building.
|
||||||
</p>
|
</p>
|
||||||
<button
|
{/* <button
|
||||||
type="button"
|
type="button"
|
||||||
className="btn btn-xs btn-primary"
|
className="btn btn-xs btn-primary"
|
||||||
onClick={() => handleAddFloor(building)}
|
onClick={() => handleAddFloor(building)}
|
||||||
>
|
>
|
||||||
<i className="bx bx-plus-circle me-2"></i>
|
<i className="bx bx-plus-circle me-2"></i>
|
||||||
Add Floors
|
Add Floors
|
||||||
</button>
|
</button> */}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@ -7,8 +7,15 @@ import { refreshData } from "../../../slices/localVariablesSlice";
|
|||||||
import ProjectRepository from "../../../repositories/ProjectRepository";
|
import ProjectRepository from "../../../repositories/ProjectRepository";
|
||||||
import showToast from "../../../services/toastService";
|
import showToast from "../../../services/toastService";
|
||||||
import { useHasUserPermission } from "../../../hooks/useHasUserPermission";
|
import { useHasUserPermission } from "../../../hooks/useHasUserPermission";
|
||||||
import {ASSIGN_REPORT_TASK, MANAGE_PROJECT_INFRA, MANAGE_TASK} from "../../../utils/constants";
|
import {
|
||||||
|
ASSIGN_REPORT_TASK,
|
||||||
|
MANAGE_PROJECT_INFRA,
|
||||||
|
MANAGE_TASK,
|
||||||
|
} from "../../../utils/constants";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
|
import ProgressDonutChart from "../../Charts/ProgressDonutChart";
|
||||||
|
import ProgressBar from "../../common/ProgressBar";
|
||||||
|
import { componentsToColor } from "pdf-lib";
|
||||||
|
|
||||||
const WorkArea = ({ workArea, floor, forBuilding }) => {
|
const WorkArea = ({ workArea, floor, forBuilding }) => {
|
||||||
const [workItems, setWorkItems] = useState([]);
|
const [workItems, setWorkItems] = useState([]);
|
||||||
@ -20,6 +27,25 @@ const WorkArea = ({ workArea, floor, forBuilding }) => {
|
|||||||
const ManageInfra = useHasUserPermission(MANAGE_PROJECT_INFRA);
|
const ManageInfra = useHasUserPermission(MANAGE_PROJECT_INFRA);
|
||||||
const ManageAndAssignTak = useHasUserPermission(ASSIGN_REPORT_TASK);
|
const ManageAndAssignTak = useHasUserPermission(ASSIGN_REPORT_TASK);
|
||||||
|
|
||||||
|
const [workAreaStatus, setWorkAreaStatus] = useState({
|
||||||
|
completed: 0,
|
||||||
|
planned: 100,
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const totalCompleted = workItems.reduce(
|
||||||
|
(sum, i) => sum + (i.workItem?.completedWork || 0),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
const totalPlanned = workItems.reduce(
|
||||||
|
(sum, i) => sum + (i.workItem?.plannedWork || 0),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
const percent =
|
||||||
|
totalPlanned > 0 ? (totalCompleted / totalPlanned) * 100 : 0;
|
||||||
|
//setPercentComplete(Math.min(percent, 100)); // cap at 100%
|
||||||
|
setWorkAreaStatus({ completed: totalCompleted, planned: totalPlanned });
|
||||||
|
}, [workItems]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const project = getCachedData("projectInfo");
|
const project = getCachedData("projectInfo");
|
||||||
@ -153,21 +179,32 @@ const WorkArea = ({ workArea, floor, forBuilding }) => {
|
|||||||
}}
|
}}
|
||||||
></i>
|
></i>
|
||||||
|
|
||||||
<div className="d-flex justify-content-start gap-12">
|
<div className="d-flex justify-content-start row w-100 align-items-center">
|
||||||
<div className="d-flex">
|
<div className="d-flex col-5">
|
||||||
<span className="fw-semibold small">Floor: </span>
|
<span className="fw-semibold text-primary small">
|
||||||
<span className="fw-normal text-darkgreen small">
|
Floor:
|
||||||
|
</span>
|
||||||
|
<span className="fw-normal text-darkgreen small px-2">
|
||||||
{floor.floorName}
|
{floor.floorName}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-start ">
|
<div className="text-start col-5">
|
||||||
<span className="fw-semibold text-primary small">
|
<span className="fw-semibold text-primary small">
|
||||||
Work Area:
|
Work Area:
|
||||||
</span>
|
</span>
|
||||||
<span className="fw-normal text-darkgreen small">
|
<span className="fw-normal text-darkgreen small px-2">
|
||||||
{workArea.areaName}
|
{workArea.areaName}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
{workArea?.workItems?.length > 0 && (
|
||||||
|
<div className="col-2">
|
||||||
|
<ProgressBar
|
||||||
|
completedWork={workAreaStatus.completed}
|
||||||
|
plannedWork={workAreaStatus.planned}
|
||||||
|
className="m-0 text-info"
|
||||||
|
></ProgressBar>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</p>
|
</p>
|
||||||
@ -195,10 +232,14 @@ const WorkArea = ({ workArea, floor, forBuilding }) => {
|
|||||||
<th className="infra-activity-table-header d-none d-md-table-cell">
|
<th className="infra-activity-table-header d-none d-md-table-cell">
|
||||||
Completed/Planned
|
Completed/Planned
|
||||||
</th>
|
</th>
|
||||||
|
<th className="infra-activity-table-header d-none d-md-table-cell">
|
||||||
|
Today's Planned
|
||||||
|
</th>
|
||||||
<th className="infra-activity-table-header">
|
<th className="infra-activity-table-header">
|
||||||
Progress
|
Progress
|
||||||
</th>
|
</th>
|
||||||
{( ManageInfra || ( !projectId && ManageAndAssignTak ) ) && (
|
{(ManageInfra ||
|
||||||
|
(!projectId && ManageAndAssignTak)) && (
|
||||||
<th className="infra-activity-table-header text-end">
|
<th className="infra-activity-table-header text-end">
|
||||||
<span className="px-2">Actions</span>
|
<span className="px-2">Actions</span>
|
||||||
</th>
|
</th>
|
||||||
|
|||||||
@ -21,7 +21,6 @@ import { useDispatch } from "react-redux";
|
|||||||
import { refreshData } from "../../../slices/localVariablesSlice";
|
import { refreshData } from "../../../slices/localVariablesSlice";
|
||||||
|
|
||||||
const WorkItem = ({
|
const WorkItem = ({
|
||||||
key,
|
|
||||||
workItem,
|
workItem,
|
||||||
forBuilding,
|
forBuilding,
|
||||||
forFloor,
|
forFloor,
|
||||||
@ -55,6 +54,15 @@ const WorkItem = ({
|
|||||||
setNewWorkItem(workItem);
|
setNewWorkItem(workItem);
|
||||||
}, [workItem]);
|
}, [workItem]);
|
||||||
|
|
||||||
|
const refreshWorkItem = (plannedTask) =>{
|
||||||
|
if (workItem) {
|
||||||
|
const updated = {
|
||||||
|
...workItem,
|
||||||
|
todaysAssigned: (workItem.todaysAssigned || 0) + plannedTask,
|
||||||
|
};
|
||||||
|
setNewWorkItem(updated);
|
||||||
|
}
|
||||||
|
}
|
||||||
let assigndata = {
|
let assigndata = {
|
||||||
building: forBuilding,
|
building: forBuilding,
|
||||||
floor: forFloor,
|
floor: forFloor,
|
||||||
@ -97,7 +105,7 @@ const WorkItem = ({
|
|||||||
style={{ display: isModalOpen ? "block" : "none" }}
|
style={{ display: isModalOpen ? "block" : "none" }}
|
||||||
aria-hidden={!isModalOpen}
|
aria-hidden={!isModalOpen}
|
||||||
>
|
>
|
||||||
<AssignRoleModel assignData={assigndata} onClose={closeModal} />
|
<AssignRoleModel assignData={assigndata} onClose={closeModal} setAssigned={refreshWorkItem} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@ -141,7 +149,7 @@ const WorkItem = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<tr key={key}>
|
<tr key={NewWorkItem?.workItemId}>
|
||||||
{/* Activity Name - always visible */}
|
{/* Activity Name - always visible */}
|
||||||
<td className="text-start table-cell-small">
|
<td className="text-start table-cell-small">
|
||||||
<i className="bx bx-right-arrow-alt"></i>
|
<i className="bx bx-right-arrow-alt"></i>
|
||||||
@ -191,6 +199,16 @@ const WorkItem = ({
|
|||||||
: "NA"}
|
: "NA"}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
|
<td className="text-center d-none d-md-table-cell">
|
||||||
|
{hasWorkItem
|
||||||
|
? `${
|
||||||
|
NewWorkItem?.todaysAssigned ??
|
||||||
|
workItem?.todaysAssigned ??
|
||||||
|
"0"
|
||||||
|
}`
|
||||||
|
: "NA"}
|
||||||
|
</td>
|
||||||
|
|
||||||
{/* Progress Bar - always visible */}
|
{/* Progress Bar - always visible */}
|
||||||
<td className="text-center " style={{ width: "15%" }}>
|
<td className="text-center " style={{ width: "15%" }}>
|
||||||
<div className="progress p-0">
|
<div className="progress p-0">
|
||||||
|
|||||||
@ -101,8 +101,16 @@ const Teams = ({ project }) => {
|
|||||||
|
|
||||||
submitAllocations(items, true);
|
submitAllocations(items, true);
|
||||||
|
|
||||||
|
// Force switch to active view after assignment
|
||||||
|
setActiveEmployee(true);
|
||||||
|
setFilteredEmployees(employees.filter((emp) => emp.isActive));
|
||||||
|
|
||||||
|
// Also update dropdown select if needed
|
||||||
|
const dropdown = document.querySelector('select[name="DataTables_Table_0_length"]');
|
||||||
|
if (dropdown) dropdown.value = "true";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const getRole = (jobRoleId) => {
|
const getRole = (jobRoleId) => {
|
||||||
if (loading) return "Loading...";
|
if (loading) return "Loading...";
|
||||||
if (!Array.isArray(empJobRoles)) return "Unassigned";
|
if (!Array.isArray(empJobRoles)) return "Unassigned";
|
||||||
@ -333,8 +341,12 @@ const Teams = ({ project }) => {
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
)}
|
)}
|
||||||
{(!employeeLodaing && employees.length == 0 )&& (
|
{!employeeLodaing && filteredEmployees.length === 0 && (
|
||||||
<span>No employees assigned to the project</span>
|
<div className="text-center text-muted py-3">
|
||||||
|
{activeEmployee
|
||||||
|
? "No active employees assigned to the project"
|
||||||
|
: "No inactive employees assigned to the project"}
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -25,7 +25,6 @@ const MasterModal = ({ modaldata, closeModal }) => {
|
|||||||
const handleSelectedMasterDeleted = async () =>
|
const handleSelectedMasterDeleted = async () =>
|
||||||
{
|
{
|
||||||
const deleteFn = MasterRespository[modaldata.masterType];
|
const deleteFn = MasterRespository[modaldata.masterType];
|
||||||
|
|
||||||
if (!deleteFn) {
|
if (!deleteFn) {
|
||||||
showToast(`No delete strategy defined for master type`,"error");
|
showToast(`No delete strategy defined for master type`,"error");
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -59,13 +59,28 @@ const AttendancesEmployeeRecords = ({ employee }) => {
|
|||||||
.sort(sortByName);
|
.sort(sortByName);
|
||||||
const group5 = data.filter((d) => d.activity === 5).sort(sortByName);
|
const group5 = data.filter((d) => d.activity === 5).sort(sortByName);
|
||||||
|
|
||||||
const sortedFinalList = [
|
// const sortedFinalList = [
|
||||||
...group1,
|
// ...group1,
|
||||||
...group2,
|
// ...group2,
|
||||||
...group3,
|
// ...group3,
|
||||||
...group4,
|
// ...group4,
|
||||||
...group5,
|
// ...group5,
|
||||||
];
|
// ];
|
||||||
|
|
||||||
|
const uniqueMap = new Map();
|
||||||
|
|
||||||
|
[...group1, ...group2, ...group3, ...group4, ...group5].forEach((rec) => {
|
||||||
|
const date = moment(rec.checkInTime || rec.checkOutTime).format("YYYY-MM-DD");
|
||||||
|
const key = `${rec.employeeId}-${date}`;
|
||||||
|
const existing = uniqueMap.get(key);
|
||||||
|
if (!existing || new Date(rec.checkInTime || rec.checkOutTime) > new Date(existing.checkInTime || existing.checkOutTime)) {
|
||||||
|
uniqueMap.set(key, rec);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const sortedFinalList = [...uniqueMap.values()].sort((a, b) =>
|
||||||
|
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");
|
||||||
const { currentPage, totalPages, currentItems, paginate } = usePagination(
|
const { currentPage, totalPages, currentItems, paginate } = usePagination(
|
||||||
|
|||||||
@ -398,7 +398,7 @@ const EmployeeList = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-end mb-2">
|
<div className={`text-end mb-2 ${selectedProject ? 'd-none' : ''}`}>
|
||||||
<label className="switch switch-primary">
|
<label className="switch switch-primary">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
|
|||||||
@ -41,7 +41,7 @@ export const MasterRespository = {
|
|||||||
"Activity": ( id ) => api.delete( `/api/master/activity/delete/${ id }` ),
|
"Activity": ( id ) => api.delete( `/api/master/activity/delete/${ id }` ),
|
||||||
"Application Role":(id)=>api.delete(`/api/roles/${id}`),
|
"Application Role":(id)=>api.delete(`/api/roles/${id}`),
|
||||||
"Work Category": ( id ) => api.delete( `api/master/work-category/${ id }` ),
|
"Work Category": ( id ) => api.delete( `api/master/work-category/${ id }` ),
|
||||||
"Contact Category": ( id ) => api.delete( `/api/master/contact-category/${id}` ),
|
"Contact Category": ( id ) => api.delete( `/api/master/contact-category` ),
|
||||||
"Contact Tag" :(id)=>api.delete(`/api/master/contact-tag/${id}`),
|
"Contact Tag" :(id)=>api.delete(`/api/master/contact-tag/${id}`),
|
||||||
|
|
||||||
getWorkCategory:() => api.get(`/api/master/work-categories`),
|
getWorkCategory:() => api.get(`/api/master/work-categories`),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user