Merge branch 'Issue_May_2W' of https://git.marcoaiot.com/admin/marco.pms.web into pramod_Bug#221
This commit is contained in:
commit
31286eff0a
@ -189,3 +189,7 @@
|
||||
text-align: left;
|
||||
padding-left: 50px;
|
||||
} */
|
||||
|
||||
.small-text{
|
||||
font-size: 12px;
|
||||
}
|
2
public/assets/vendor/css/core.css
vendored
2
public/assets/vendor/css/core.css
vendored
@ -29002,7 +29002,6 @@ li:not(:first-child) .dropdown-item,
|
||||
/* Only for menu example */
|
||||
.menu-collapsed:not(:hover) {
|
||||
inline-size: var(--bs-menu-collapsed-width);
|
||||
/* Custom for sneat only */
|
||||
}
|
||||
.menu-collapsed:not(:hover) .menu-inner > .menu-item {
|
||||
inline-size: var(--bs-menu-collapsed-width);
|
||||
@ -29682,7 +29681,6 @@ li:not(:first-child) .dropdown-item,
|
||||
)
|
||||
.layout-menu.menu-vertical {
|
||||
inline-size: var(--bs-menu-collapsed-width);
|
||||
/* Custom for sneat only */
|
||||
}
|
||||
.layout-menu-collapsed:not(
|
||||
.layout-menu-hover,
|
||||
|
@ -186,7 +186,6 @@
|
||||
|
||||
> .menu-item {
|
||||
margin: $menu-item-spacer 0;
|
||||
// Sneat menu-link spacing
|
||||
.menu-link {
|
||||
margin: $menu-vertical-link-margin-y $menu-vertical-link-margin-x;
|
||||
}
|
||||
@ -197,7 +196,6 @@
|
||||
.menu-block {
|
||||
padding: $menu-vertical-link-padding-y $menu-vertical-link-padding-x;
|
||||
}
|
||||
// Sneat menu-header spacing
|
||||
.menu-header {
|
||||
margin: $menu-vertical-header-margin-y 0 $menu-vertical-header-margin-y * 0.5 0;
|
||||
padding: $menu-vertical-link-padding-y $menu-vertical-link-padding-x * 2 $menu-vertical-link-padding-y
|
||||
@ -276,7 +274,7 @@
|
||||
|
||||
// Vertical Menu Collapsed
|
||||
// *******************************************************************************
|
||||
// ! Updated menu collapsed styles for sneat in this mixin
|
||||
// ! Updated menu collapsed styles for in this mixin
|
||||
@mixin layout-menu-collapsed() {
|
||||
width: $menu-collapsed-width;
|
||||
|
||||
@ -312,7 +310,6 @@
|
||||
top: 1.1875rem;
|
||||
}
|
||||
}
|
||||
// Custom for sneat only
|
||||
.menu-block {
|
||||
&::before {
|
||||
bottom: 0.75rem;
|
||||
|
@ -27,15 +27,21 @@ const ReportTaskComments = ({ commentsData, closeModal }) => {
|
||||
});
|
||||
|
||||
const containerRef = useRef(null);
|
||||
const firstRender = useRef(true);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
setComment(commentsData?.comments);
|
||||
}, [commentsData]);
|
||||
|
||||
// Scroll logic: scroll to bottom when new comments are added
|
||||
useEffect(() => {
|
||||
if (containerRef.current) {
|
||||
if (!firstRender.current && containerRef.current) {
|
||||
containerRef.current.scrollTop = containerRef.current.scrollHeight;
|
||||
} else {
|
||||
firstRender.current = false; // Mark the first render as complete
|
||||
}
|
||||
}, [comments]);
|
||||
}, [comments]); // Run this when comments array is updated
|
||||
|
||||
const onSubmit = async (data) => {
|
||||
let sendComment = {
|
||||
@ -70,9 +76,10 @@ const ReportTaskComments = ({ commentsData, closeModal }) => {
|
||||
// closeModal();
|
||||
} catch (error) {
|
||||
setloading(false);
|
||||
showToast(error.response.data?.message || "Something wrong", "error");
|
||||
showToast(error.response.data?.message || "Something went wrong", "error");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className="modal-dialog modal-lg modal-simple report-task-comments-modal mx-sm-auto mx-1"
|
||||
@ -86,61 +93,56 @@ const ReportTaskComments = ({ commentsData, closeModal }) => {
|
||||
onClick={closeModal}
|
||||
aria-label="Close"
|
||||
></button>
|
||||
<p className="fs-6 text-dark text-start">
|
||||
{`${commentsData?.workItem?.workArea?.floor?.building?.name}`}{" "}
|
||||
<i className="bx bx-chevron-right"></i>{" "}
|
||||
{`${commentsData?.workItem?.workArea?.floor?.floorName} `}{" "}
|
||||
<i className="bx bx-chevron-right"></i>
|
||||
{`${commentsData?.workItem?.workArea?.areaName}`}
|
||||
<i className="bx bx-chevron-right"></i>
|
||||
{` ${commentsData?.workItem?.activityMaster?.activityName}`}
|
||||
<p className="fs-6 text-dark text-start m-0">Activity Summary</p>
|
||||
<p className="small-text text-start my-2">
|
||||
{comments && comments[0]?.comment}
|
||||
</p>
|
||||
<p className="fw-bold my-2 text-start">
|
||||
Assigned By :
|
||||
<span className=" ms-2">
|
||||
{commentsData?.assignedBy.firstName +
|
||||
" " +
|
||||
commentsData?.assignedBy.lastName}
|
||||
</span>{" "}
|
||||
</p>
|
||||
|
||||
<ul
|
||||
className="list-grouph px-0 mx-0 overflow-auto"
|
||||
ref={containerRef}
|
||||
style={{ maxHeight: "400px" }}
|
||||
>
|
||||
{comments &&
|
||||
comments?.map((data) => {
|
||||
const fullName = `${data?.employee?.firstName} ${data?.employee?.lastName}`;
|
||||
const bgClass = getBgClassFromHash(fullName);
|
||||
return (
|
||||
<li
|
||||
className={`list-group-item list-group-item-action my-2 p-1`}
|
||||
>
|
||||
<div
|
||||
className={`li-wrapper d-flex justify-content-start align-items-start my-0 `}
|
||||
>
|
||||
<div className="avatar avatar-xs me-1">
|
||||
<span
|
||||
className={`avatar-initial rounded-circle bg-label-primary}`}
|
||||
>
|
||||
{`${data?.employee?.firstName?.slice(
|
||||
0,
|
||||
1
|
||||
)} ${data?.employee?.lastName?.slice(0, 1)}`}
|
||||
</span>
|
||||
</div>
|
||||
<p className="fw-bold my-2 text-start">
|
||||
Loaction :
|
||||
<span className="fw-normal ms-2 text-start">
|
||||
{`${commentsData?.workItem?.workArea?.floor?.building?.name}`}{" "}
|
||||
<i className="bx bx-chevron-right"></i>{" "}
|
||||
{`${commentsData?.workItem?.workArea?.floor?.floorName} `}{" "}
|
||||
<i className="bx bx-chevron-right"></i>
|
||||
{`${commentsData?.workItem?.workArea?.areaName}`}
|
||||
<i className="bx bx-chevron-right"></i>
|
||||
{` ${commentsData?.workItem?.activityMaster?.activityName}`}
|
||||
</span>
|
||||
</p>
|
||||
<p className="fw-bold my-2 text-start">
|
||||
Planned Work: {commentsData?.plannedTask}
|
||||
</p>
|
||||
<p className="fw-bold my-2 text-start">
|
||||
{" "}
|
||||
Completed Work : {commentsData?.completedTask}
|
||||
</p>
|
||||
<div className="d-flex align-items-center flex-wrap">
|
||||
<p className="fw-bold text-start m-0 me-1">Team:</p>
|
||||
<div className="d-flex flex-wrap align-items-center gap-2">
|
||||
{commentsData?.teamMembers?.map((member, idx) => (
|
||||
<span key={idx} className="d-flex align-items-center">
|
||||
<Avatar
|
||||
firstName={member?.firstName}
|
||||
lastName={member?.lastName}
|
||||
size="xs"
|
||||
/>
|
||||
{member?.firstName + " " + member?.lastName}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={` text-start py-0 `}>
|
||||
<p className={`mb-0 text-${bgClass}`}>{fullName}</p>
|
||||
<p
|
||||
className=" text-muted m-0 "
|
||||
style={{ fontSize: "10px" }}
|
||||
>
|
||||
{moment.utc(data?.commentDate).local().fromNow()}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<p className={`ms-6 text-start mb-0 text-body`}>
|
||||
{data?.comment}
|
||||
</p>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<form onSubmit={handleSubmit(onSubmit)} className="text-start">
|
||||
<label className="fw-bold text-start my-1">Add comment :</label>
|
||||
<textarea
|
||||
{...register("comment")}
|
||||
className="form-control"
|
||||
@ -165,6 +167,47 @@ const ReportTaskComments = ({ commentsData, closeModal }) => {
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<ul
|
||||
className="list-group px-0 mx-0 overflow-auto border-0"
|
||||
// ref={containerRef} // auto scroll according data
|
||||
style={{ maxHeight: "200px" }}
|
||||
>
|
||||
{comments &&
|
||||
comments
|
||||
?.slice()
|
||||
.reverse()
|
||||
.map((data, idx) => {
|
||||
const fullName = `${data?.employee?.firstName} ${data?.employee?.lastName}`;
|
||||
const bgClass = getBgClassFromHash(fullName);
|
||||
return (
|
||||
<li
|
||||
className={`list-group-item list-group-item-action border-none my-1 p-1`}
|
||||
key={idx}
|
||||
>
|
||||
<div
|
||||
className={`li-wrapper d-flex justify-content-start align-items-start my-0`}
|
||||
>
|
||||
<div className="avatar avatar-xs me-1">
|
||||
<span
|
||||
className={`avatar-initial rounded-circle bg-label-primary`}
|
||||
>
|
||||
{`${data?.employee?.firstName?.slice(0, 1)} ${data?.employee?.lastName?.slice(0, 1)}`}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className={`text-start py-0`}>
|
||||
<p className={`mb-0 text-${bgClass}`}>{fullName}</p>
|
||||
<p className="text-muted m-0" style={{ fontSize: "10px" }}>
|
||||
{moment.utc(data?.commentDate).local().fromNow()}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<p className={`ms-6 text-start mb-0 text-body`}>{data?.comment}</p>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -10,7 +10,7 @@ import { changeMaster } from "../../slices/localVariablesSlice";
|
||||
import { Link, useNavigate, useParams } from "react-router-dom";
|
||||
import { formatDate } from "../../utils/dateUtils";
|
||||
import { useEmployeeProfile } from "../../hooks/useEmployees";
|
||||
import { clearCacheKey, getCachedData } from "../../slices/apiDataManager";
|
||||
import { cacheData, clearCacheKey, getCachedData } from "../../slices/apiDataManager";
|
||||
import { clearApiCacheKey } from "../../slices/apiCacheSlice";
|
||||
|
||||
const mobileNumberRegex = /^[0-9]\d{9}$/;
|
||||
@ -166,6 +166,7 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
|
||||
}
|
||||
EmployeeRepository.manageEmployee(data)
|
||||
.then((response) => {
|
||||
cacheData("employeeProfileInfo", data);
|
||||
showToast(
|
||||
`Employee details ${
|
||||
data.id == null ? "created" : "updated"
|
||||
@ -176,6 +177,7 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
|
||||
clearCacheKey("allEmployeeList");
|
||||
clearCacheKey("allInactiveEmployeeList");
|
||||
clearCacheKey("employeeProfile");
|
||||
|
||||
|
||||
setLoading(false);
|
||||
reset();
|
||||
|
@ -58,7 +58,7 @@ const LayoutMenu = () => {
|
||||
</g>
|
||||
</svg>
|
||||
</span>
|
||||
<span className="app-brand-text demo menu-text fw-bolder ms-2">Sneat</span>
|
||||
<span className="app-brand-text demo menu-text fw-bolder ms-2">Marco</span>
|
||||
</a>
|
||||
|
||||
<a href="javascript:void(0);" className="layout-menu-toggle menu-link text-large ms-auto d-block d-xl-none">
|
||||
|
@ -3,7 +3,7 @@ import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { useActivitiesMaster } from "../../../hooks/masterHook/useMaster";
|
||||
import { useActivitiesMaster, useWorkCategoriesMaster } from "../../../hooks/masterHook/useMaster";
|
||||
import { useProjectDetails } from "../../../hooks/useProjects";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import ProjectRepository from "../../../repositories/ProjectRepository";
|
||||
@ -18,6 +18,7 @@ import showToast from "../../../services/toastService";
|
||||
const taskSchema = z
|
||||
.object({
|
||||
activityID: z.string().min(1, "Activity is required"),
|
||||
workCategoryId: z.string().min(1, "Work Category is required"),
|
||||
plannedWork: z.number().min(1, "Planned Work must be greater than 0"),
|
||||
completedWork: z.number().min(0, "Completed Work must be greater than 0"),
|
||||
})
|
||||
@ -43,17 +44,21 @@ const EditActivityModal = ({
|
||||
);
|
||||
const defaultModel = {
|
||||
activityID: 0,
|
||||
workCategoryId: 0,
|
||||
plannedWork: 0,
|
||||
completedWork: 0,
|
||||
};
|
||||
|
||||
const {projects_Details, refetch} = useProjectDetails( selectedProject );
|
||||
const [ActivityUnit,setActivityUnit]= useState("")
|
||||
const { projects_Details, refetch } = useProjectDetails(selectedProject);
|
||||
const [ActivityUnit, setActivityUnit] = useState("");
|
||||
const { activities, loading, error } = useActivitiesMaster();
|
||||
const { categories, categoryLoading, categoryError } =
|
||||
useWorkCategoriesMaster();
|
||||
const [formData, setFormData] = useState(defaultModel);
|
||||
const [selectedActivity, setSelectedActivity] = useState(null);
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [activityData, setActivityData] = useState([]);
|
||||
const [categoryData, setCategoryData] = useState([]);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const {
|
||||
@ -70,12 +75,19 @@ const EditActivityModal = ({
|
||||
});
|
||||
|
||||
const handleActivityChange = (e) => {
|
||||
const selectedId = Number(e.target.value);
|
||||
const selected = activityData.find( ( a ) => a.id === selectedId );
|
||||
const selectedId = String(e.target.value);
|
||||
const selected = activityData.find((a) => a.id === selectedId);
|
||||
setSelectedActivity(selected || null);
|
||||
setValue("activityID", selectedId);
|
||||
};
|
||||
|
||||
const handleCategoryChange = (e) => {
|
||||
const selectedId = String(e.target.value);
|
||||
const category = categoryData.find((b) => b.id === selectedId);
|
||||
setSelectedCategory(category || null);
|
||||
setValue("workCategoryId", selectedId);
|
||||
};
|
||||
|
||||
const onSubmitForm = async ( data ) =>
|
||||
{
|
||||
setIsSubmitting(true)
|
||||
@ -167,6 +179,8 @@ const EditActivityModal = ({
|
||||
useEffect(() => {
|
||||
reset({
|
||||
activityID: workItem?.workItem?.activityId || workItem?.activityId || 0,
|
||||
workCategoryId:
|
||||
workItem?.workItem?.workCategoryId || workItem?.workCategoryId || 0,
|
||||
plannedWork:
|
||||
workItem?.workItem?.plannedWork || workItem?.plannedWork || 0,
|
||||
completedWork:
|
||||
@ -177,14 +191,13 @@ const EditActivityModal = ({
|
||||
|
||||
const ISselectedActivity = watch("activityID");
|
||||
useEffect(() => {
|
||||
if( ISselectedActivity ){
|
||||
if (ISselectedActivity) {
|
||||
const selected = activities.find((a) => a.id === ISselectedActivity);
|
||||
setSelectedActivity( selected || null );
|
||||
setActivityUnit(selected?.unitOfMeasurement)
|
||||
}
|
||||
}, [ ISselectedActivity,activities] );
|
||||
|
||||
|
||||
setSelectedActivity(selected || null);
|
||||
setActivityUnit(selected?.unitOfMeasurement);
|
||||
}
|
||||
}, [ISselectedActivity, activities]);
|
||||
|
||||
return (
|
||||
<div className="modal-dialog modal-lg modal-simple modal-edit-user">
|
||||
<div className="modal-content">
|
||||
@ -279,6 +292,45 @@ const EditActivityModal = ({
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Select Category */}
|
||||
<div className="col-12 col-md-12">
|
||||
<label className="form-label" htmlFor="activityID">
|
||||
Select Work Category
|
||||
</label>
|
||||
<select
|
||||
id="workCategoryId"
|
||||
className="form-select form-select-sm"
|
||||
{...register("workCategoryId")}
|
||||
>
|
||||
{loading ? (
|
||||
<option value="">Loading...</option>
|
||||
) : (
|
||||
<option disabled>Select Category</option>
|
||||
)}
|
||||
{categories &&
|
||||
categories.length > 0 &&
|
||||
categories
|
||||
.slice()
|
||||
.sort((a, b) =>
|
||||
(a.name || "").localeCompare(
|
||||
b.name || ""
|
||||
)
|
||||
)
|
||||
.map((category) => (
|
||||
<option key={category.id} value={category.id}>
|
||||
{category.name}
|
||||
</option>
|
||||
))}
|
||||
{!loading && categories.length === 0 && (
|
||||
<option disabled>No categories available</option>
|
||||
)}
|
||||
</select>
|
||||
|
||||
{errors.workCategoryId && (
|
||||
<p className="danger-text">{errors.workCategoryId.message}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Planned Work */}
|
||||
{/* {ISselectedActivity && ( */}
|
||||
<div className="col-5 col-md-5">
|
||||
|
@ -2,23 +2,28 @@ import React, { useState, useEffect } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { z } from "zod";
|
||||
import {useActivitiesMaster} from "../../../hooks/masterHook/useMaster";
|
||||
import {
|
||||
useActivitiesMaster,
|
||||
useWorkCategoriesMaster,
|
||||
} from "../../../hooks/masterHook/useMaster";
|
||||
|
||||
const taskSchema = z.object({
|
||||
buildingID: z.string().min(1, "Building is required"),
|
||||
floorId: z.string().min(1, "Floor is required"),
|
||||
workAreaId: z.string().min(1, "Work Area is required"),
|
||||
activityID: z.string().min(1, "Activity is required"),
|
||||
workCategoryId: z.string().min(1, "Work Category is required"),
|
||||
plannedWork: z.number().min(1, "Planned Work must be greater than 0"),
|
||||
completedWork: z.number().min(0, "Completed Work must be greater than 0"),
|
||||
});
|
||||
|
||||
const defaultModel = {
|
||||
id: null,
|
||||
buildingID:"0",
|
||||
buildingID: "0",
|
||||
floorId: "0",
|
||||
workAreaId: "0",
|
||||
activityID: null,
|
||||
workCategoryId: "",
|
||||
plannedWork: 0,
|
||||
completedWork: 0,
|
||||
};
|
||||
@ -30,15 +35,18 @@ const TaskModel = ({
|
||||
onClearComplete,
|
||||
onClose,
|
||||
}) => {
|
||||
|
||||
const [formData, setFormData] = useState(defaultModel);
|
||||
const [selectedBuilding, setSelectedBuilding] = useState(null);
|
||||
const [selectedFloor, setSelectedFloor] = useState(null);
|
||||
const [selectedWorkArea, setSelectedWorkArea] = useState(null);
|
||||
const [selectedActivity, setSelectedActivity] = useState(null);
|
||||
const [selectedCategory, setSelectedCategory] = useState(null);
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [activityData, setActivityData] = useState([]);
|
||||
const {activities, loading, error} = useActivitiesMaster();
|
||||
const [categoryData, setCategoryData] = useState([]);
|
||||
const { activities, loading, error } = useActivitiesMaster();
|
||||
const { categories, categoryLoading, categoryError } =
|
||||
useWorkCategoriesMaster();
|
||||
|
||||
const {
|
||||
register,
|
||||
@ -79,6 +87,7 @@ const TaskModel = ({
|
||||
floorId: value,
|
||||
workAreaId: 0,
|
||||
activityID: 0,
|
||||
workCategoryId: categoryData?.[0]?.id?.toString() ?? "",
|
||||
}));
|
||||
};
|
||||
|
||||
@ -104,13 +113,24 @@ const TaskModel = ({
|
||||
}));
|
||||
};
|
||||
|
||||
const onSubmitForm = async ( data ) =>
|
||||
{
|
||||
const handleCategoryChange = (e) => {
|
||||
const { value } = e.target;
|
||||
const category = categoryData.find((b) => b.id === String(value));
|
||||
setSelectedCategory(category);
|
||||
reset((prev) => ({
|
||||
...prev,
|
||||
workCategoryId: String(value),
|
||||
}));
|
||||
};
|
||||
|
||||
const onSubmitForm = async (data) => {
|
||||
console.log(data);
|
||||
setIsSubmitting(true);
|
||||
await onSubmit(data);
|
||||
setValue("plannedWork", 0);
|
||||
setValue( "completedWork", 0 );
|
||||
setValue("activityID",0)
|
||||
setValue("completedWork", 0);
|
||||
setValue("activityID", 0);
|
||||
setValue("workCategoryId", categoryData?.[0]?.id?.toString() ?? "");
|
||||
setIsSubmitting(false);
|
||||
};
|
||||
|
||||
@ -120,15 +140,32 @@ const TaskModel = ({
|
||||
setSelectedFloor(null);
|
||||
setSelectedWorkArea(null);
|
||||
setSelectedActivity(null);
|
||||
setSelectedCategory(categoryData?.[0]?.id?.toString() ?? "");
|
||||
reset(defaultModel);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!loading && Array.isArray(activities) && activities.length > 0) {
|
||||
|
||||
setActivityData(activities);
|
||||
}
|
||||
}, [activities, loading]);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
!categoryLoading &&
|
||||
Array.isArray(categories) &&
|
||||
categories.length > 0
|
||||
) {
|
||||
const newCategories = categories?.slice()?.sort((a, b) => {
|
||||
const nameA = a?.name || "";
|
||||
const nameB = b?.name || "";
|
||||
return nameA.localeCompare(nameB);
|
||||
});
|
||||
setCategoryData(newCategories);
|
||||
setSelectedCategory(newCategories[0])
|
||||
}
|
||||
}, [categories, categoryLoading]);
|
||||
|
||||
return (
|
||||
<div className="modal-dialog modal-lg modal-simple modal-edit-user">
|
||||
<div className="modal-content">
|
||||
@ -247,9 +284,7 @@ const TaskModel = ({
|
||||
|
||||
{selectedWorkArea && (
|
||||
<div className="col-12 col-md-12">
|
||||
<label className="form-label" >
|
||||
Select Activity
|
||||
</label>
|
||||
<label className="form-label">Select Activity</label>
|
||||
<select
|
||||
id="activityID"
|
||||
className="form-select form-select-sm"
|
||||
@ -257,28 +292,25 @@ const TaskModel = ({
|
||||
onChange={handleActivityChange}
|
||||
>
|
||||
<option value="0">Select Activity</option>
|
||||
{activityData && activityData.length > 0 && (
|
||||
{activityData &&
|
||||
activityData.length > 0 &&
|
||||
activityData
|
||||
?.slice()
|
||||
?.sort( ( a, b ) =>
|
||||
{
|
||||
?.sort((a, b) => {
|
||||
const nameA = a?.activityName || "";
|
||||
const nameB = b?.activityName || "";
|
||||
return nameA.localeCompare( nameB );
|
||||
} )
|
||||
?.map( ( activity ) => (
|
||||
return nameA.localeCompare(nameB);
|
||||
})
|
||||
?.map((activity) => (
|
||||
<option key={activity.id} value={activity.id}>
|
||||
{
|
||||
activity.activityName ||
|
||||
|
||||
`Unnamed (id: ${ activity.id })`}
|
||||
{activity.activityName ||
|
||||
`Unnamed (id: ${activity.id})`}
|
||||
</option>
|
||||
) )
|
||||
) }
|
||||
{(!loading && activities.length === 0 )&& (
|
||||
))}
|
||||
{!loading && activities.length === 0 && (
|
||||
<option disabled>No activities available</option>
|
||||
)}
|
||||
{loading && ( <option disabled>Loading...</option>)}
|
||||
{loading && <option disabled>Loading...</option>}
|
||||
</select>
|
||||
|
||||
{errors.activityID && (
|
||||
@ -287,7 +319,38 @@ const TaskModel = ({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{selectedActivity && (
|
||||
{selectedWorkArea && (
|
||||
<div className="col-12 col-md-12">
|
||||
<label className="form-label">Select Work Category</label>
|
||||
<select
|
||||
id="workCategoryId"
|
||||
className="form-select form-select-sm"
|
||||
{...register("workCategoryId")}
|
||||
onChange={handleCategoryChange}
|
||||
>
|
||||
{categoryData &&
|
||||
categoryData.length > 0 &&
|
||||
categoryData
|
||||
?.map((category) => (
|
||||
<option key={category.id} value={category.id}>
|
||||
{category.name || `Unnamed (id: ${category.id})`}
|
||||
</option>
|
||||
))}
|
||||
{!categoryLoading && categories.length === 0 && (
|
||||
<option disabled>No activities available</option>
|
||||
)}
|
||||
{categoryLoading && <option disabled>Loading...</option>}
|
||||
</select>
|
||||
|
||||
{errors.workCategoryId && (
|
||||
<p className="danger-text">
|
||||
{errors.workCategoryId.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{selectedActivity && selectedCategory && (
|
||||
<div className="col-5 col-md-5">
|
||||
<label className="form-label" htmlFor="plannedWork">
|
||||
{formData.id !== "0" ? "Modify " : "Enter "} Planned Work
|
||||
@ -304,7 +367,7 @@ const TaskModel = ({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{selectedActivity && (
|
||||
{selectedActivity && selectedCategory && (
|
||||
<div className="col-5 col-md-5">
|
||||
<label className="form-label" htmlFor="completedWork">
|
||||
{formData.id !== "0" ? "Modify " : "Enter "} Completed Work
|
||||
@ -324,7 +387,7 @@ const TaskModel = ({
|
||||
)}
|
||||
|
||||
{/* Unit */}
|
||||
{selectedActivity && (
|
||||
{selectedActivity && selectedCategory && (
|
||||
<div className="col-2 col-md-2">
|
||||
<label className="form-label" htmlFor="unit">
|
||||
Unit
|
||||
@ -340,9 +403,7 @@ const TaskModel = ({
|
||||
|
||||
<div className="col-12 text-center">
|
||||
<button type="submit" className="btn btn-sm btn-primary me-3">
|
||||
{isSubmitting
|
||||
? "Please Wait.."
|
||||
: "Add Task"}
|
||||
{isSubmitting ? "Please Wait.." : "Add Task"}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
|
@ -121,6 +121,9 @@ const WorkArea = ({ workArea, floor, forBuilding }) => {
|
||||
<th className="infra-activity-table-header d-sm-none d-sm-table-cell">
|
||||
Status
|
||||
</th>
|
||||
<th className="infra-activity-table-header-first">
|
||||
Category
|
||||
</th>
|
||||
{/* for greather than mobile view ************* */}
|
||||
<th className="infra-activity-table-header d-none d-md-table-cell">
|
||||
Planned
|
||||
|
@ -161,6 +161,15 @@ const WorkItem = ( {
|
||||
? NewWorkItem?.workItem?.plannedWork || workItem?.plannedWork
|
||||
: "NA"}
|
||||
</td>
|
||||
|
||||
<td className="text-start table-cell-small">
|
||||
<span className="fw-light">
|
||||
{hasWorkItem
|
||||
? NewWorkItem?.workItem?.workCategoryMaster?.name ||
|
||||
workItem.workCategoryMaster?.name || "NA"
|
||||
: "NA"}
|
||||
</span>
|
||||
</td>
|
||||
{/* for greather than mobile view ************* */}
|
||||
<td className="text-center d-none d-md-table-cell">
|
||||
{hasWorkItem
|
||||
|
@ -116,4 +116,37 @@ export const useActivitiesMaster = () =>
|
||||
}, [] )
|
||||
|
||||
return {activities,loading,error}
|
||||
}
|
||||
}
|
||||
|
||||
export const useWorkCategoriesMaster = () =>
|
||||
{
|
||||
const [ categories, setCategories ] = useState( [] )
|
||||
const [ categoryLoading, setloading ] = useState( false );
|
||||
const [ categoryError, setError ] = useState( "" )
|
||||
|
||||
const fetchCategories =async () => {
|
||||
const cacheddata = getCachedData("Work Category");
|
||||
|
||||
if (!cacheddata) {
|
||||
setloading(true);
|
||||
try {
|
||||
const response = await MasterRespository.getWorkCategory();
|
||||
setCategories(response.data);
|
||||
cacheData("Work Category", response.data);
|
||||
} catch (err) {
|
||||
setError(err);
|
||||
console.log(err);
|
||||
} finally {
|
||||
setloading(false);
|
||||
}
|
||||
} else {
|
||||
setCategories(cacheddata);
|
||||
}
|
||||
}
|
||||
useEffect( () =>
|
||||
{
|
||||
fetchCategories()
|
||||
}, [] )
|
||||
|
||||
return {categories,categoryLoading,categoryError}
|
||||
}
|
@ -15,11 +15,8 @@ export const AuthWrapper = ({ children }) => {
|
||||
className="app-brand-link gap-2"
|
||||
>
|
||||
<span className="app-brand-logo demo">
|
||||
<img src="/img/brand/marco.png" alt="sneat-logo" />
|
||||
<img src="/img/brand/marco.png" alt="marco-logo" />
|
||||
</span>
|
||||
{/* <span className="app-brand-text demo text-body fw-bold">
|
||||
Sneat
|
||||
</span> */}
|
||||
</Link>
|
||||
</div>
|
||||
{children}
|
||||
|
@ -16,6 +16,7 @@ import { ComingSoonPage } from "../Misc/ComingSoonPage";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import Avatar from "../../components/common/Avatar";
|
||||
import AttendancesEmployeeRecords from "./AttendancesEmployeeRecords";
|
||||
import ManageEmployee from "../../components/Employee/ManageEmployee";
|
||||
const EmployeeProfile = () => {
|
||||
const projectID = useSelector((store) => store.localVariables.projectId);
|
||||
const { employeeId } = useParams();
|
||||
@ -26,11 +27,18 @@ const EmployeeProfile = () => {
|
||||
const tab = SearchParams.get("for");
|
||||
const [activePill, setActivePill] = useState(tab);
|
||||
const [currentEmployee, setCurrentEmployee] = useState();
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
|
||||
const handlePillClick = (pillKey) => {
|
||||
setActivePill(pillKey);
|
||||
};
|
||||
|
||||
const closeModal = () => {
|
||||
setShowModal(false);
|
||||
fetchEmployeeProfile(employeeId);
|
||||
};
|
||||
const handleShow = () => setShowModal(true);
|
||||
|
||||
const fetchEmployeeProfile = async (employeeID) => {
|
||||
try {
|
||||
const resp = await EmployeeRepository.getEmployeeProfile(employeeID);
|
||||
@ -89,6 +97,26 @@ const EmployeeProfile = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<> {showModal && (<div
|
||||
className={`modal fade ${showModal ? "show" : ""} `}
|
||||
tabIndex="-1"
|
||||
role="dialog"
|
||||
style={{ display: showModal ? "block" : "none" }}
|
||||
aria-hidden={!showModal}
|
||||
>
|
||||
<div className="modal-dialog modal-xl modal-dialog-centered ">
|
||||
<div
|
||||
className="modal-content overflow-y-auto overflow-x-hidden"
|
||||
style={{ maxHeight: "90vh" }}
|
||||
>
|
||||
<ManageEmployee
|
||||
employeeId={employeeId}
|
||||
onClosed={closeModal}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>)}
|
||||
|
||||
<div className="container-xxl flex-grow-1 container-p-y">
|
||||
<Breadcrumb
|
||||
data={[
|
||||
@ -212,7 +240,7 @@ const EmployeeProfile = () => {
|
||||
<button
|
||||
className="btn btn-primary btn-block"
|
||||
onClick={() =>
|
||||
navigate(`/employee/manage/${currentEmployee?.id}`)
|
||||
handleShow()
|
||||
}
|
||||
>
|
||||
Edit Profile
|
||||
@ -238,6 +266,8 @@ const EmployeeProfile = () => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
||||
);
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user