Compare commits

...

11 Commits

Author SHA1 Message Date
9b2c27b903 Merge branch 'Ashutosh_Enhancement#205_Added_WorkCategory_Dropdown' of https://git.marcoaiot.com/admin/marco.pms.web into Ashutosh_Enhancement#205_Added_WorkCategory_Dropdown 2025-05-12 14:44:59 +05:30
e8ac267d46 Added a Work Category dropdown in task create/update forms and a new column to display the category in Project Infrastructure and Daily Task Planning views. 2025-05-12 14:40:13 +05:30
634dc12e5b Merge pull request 'Changed the first letter of all form field variables to lowercase to follow proper variable naming conventions.' (#98) from Ashutosh_Bug#216_Create_Employee_Popup_Typo into Issue_May_2W
Reviewed-on: #98
2025-05-12 07:58:33 +00:00
cf204f376d Changed the first letter of all form field variables to lowercase to follow proper variable naming conventions. 2025-05-12 07:58:33 +00:00
49f725b62d Merge pull request 'pramod_Task#207 Sync activity updates and deletions in Daily Task Planning view without page refresh' (#96) from pramod_Task#207 into Issue_May_2W
Reviewed-on: #96
2025-05-12 07:58:04 +00:00
8db6a16e15 revert 1827757f19bd15c05029e1ca9c72de3a65a68bf1
revert updated regularization logic based on 48-hour checkout threshold


- This update was mistakenly implemented in the wrong branch. Moving it here to align with the correct workflow.-  pramod_Bug#-27
2025-05-12 07:58:04 +00:00
Pramod Mahajan
2188f109cb disable Edit button and show "Please wait" message during activity update API call 2025-05-12 07:58:04 +00:00
Pramod Mahajan
292c920941 added loader during submitting form data. 2025-05-12 07:58:04 +00:00
Pramod Mahajan
af6a6faa46 ensure activity updates reflect in Daily Task Planning without page refresh 2025-05-12 07:58:04 +00:00
73152dbf0a Merge pull request 'Bug#215 updated regularization logic based on 48-hour checkout threshold for attendanceLogs.' (#97) from pramod_Bug-#215 into Issue_May_2W
Reviewed-on: #97
2025-05-12 07:57:40 +00:00
Pramod Mahajan
216e9b0db0 updated regularization logic based on 48-hour checkout threshold for attendanceLogs. 2025-05-12 07:57:40 +00:00
5 changed files with 103 additions and 75 deletions

View File

@ -13,7 +13,7 @@ import {useHasUserPermission} from "../../hooks/useHasUserPermission";
import {MANAGE_PROJECT_INFRA} from "../../utils/constants"; import {MANAGE_PROJECT_INFRA} from "../../utils/constants";
import {useDispatch, useSelector} from "react-redux"; import {useDispatch, useSelector} from "react-redux";
import {useProfile} from "../../hooks/useProfile"; import {useProfile} from "../../hooks/useProfile";
import {setProjectId} from "../../slices/localVariablesSlice"; import {refreshData, setProjectId} from "../../slices/localVariablesSlice";
import InfraTable from "../Project/Infrastructure/InfraTable"; import InfraTable from "../Project/Infrastructure/InfraTable";
@ -25,11 +25,23 @@ const InfraPlanning = () =>
const selectedProject = useSelector((store)=>store.localVariables.projectId) const selectedProject = useSelector((store)=>store.localVariables.projectId)
const ManageInfra = useHasUserPermission( MANAGE_PROJECT_INFRA ) const ManageInfra = useHasUserPermission( MANAGE_PROJECT_INFRA )
const {projects_Details, loading: project_deatilsLoader, error: project_error} = useProjectDetails(selectedProject) const {projects_Details, loading: project_deatilsLoader, error: project_error,refetch} = useProjectDetails( selectedProject )
const reloadedData = useSelector( ( store ) => store.localVariables.reload )
useEffect( () => useEffect( () =>
{ {
dispatch(setProjectId(projects[0]?.id)) dispatch(setProjectId(projects[0]?.id))
},[projects]) }, [ projects ] )
useEffect( () =>
{
if (reloadedData)
{
refetch()
dispatch( refreshData( false ) )
}
},[reloadedData])
return ( return (
<div className="col-md-12 col-lg-12 col-xl-12 order-0 mb-4"> <div className="col-md-12 col-lg-12 col-xl-12 order-0 mb-4">

View File

@ -33,7 +33,7 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
const { data: job_role, loading } = useMaster(); const { data: job_role, loading } = useMaster();
const [isloading, setLoading] = useState(false); const [isloading, setLoading] = useState(false);
const navigation = useNavigate(); const navigation = useNavigate();
const [currentEmployee, setCurrentEmployee] = useState(); const [currentEmployee, setCurrentEmployee] = useState(null);
const [currentAddressLength, setCurrentAddressLength] = useState(0); const [currentAddressLength, setCurrentAddressLength] = useState(0);
const [permanentAddressLength, setPermanentAddressLength] = useState(0); const [permanentAddressLength, setPermanentAddressLength] = useState(0);
@ -157,22 +157,30 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
mode: "onChange", mode: "onChange",
}); });
const AadharNumberValue = watch("AadharNumber") || ""; const AadharNumberValue = watch("aadharNumber") || "";
const onSubmit = (data) => { const onSubmit = (data) => {
setLoading(true); setLoading(true);
if (data.email == "") {
console.log(data); data.email = null;
}
EmployeeRepository.manageEmployee(data) EmployeeRepository.manageEmployee(data)
.then((response) => { .then((response) => {
showToast("Employee details updated successfully.", "success"); showToast(
`Employee details ${
data.id == null ? "created" : "updated"
} successfully.`,
"success"
);
clearCacheKey("employeeListByProject"); clearCacheKey("employeeListByProject");
clearCacheKey("allEmployeeList"); clearCacheKey("allEmployeeList");
clearCacheKey("allInactiveEmployeeList");
clearCacheKey("employeeProfile"); clearCacheKey("employeeProfile");
setLoading(false); setLoading(false);
reset(); reset();
navigation("/employees"); // navigation("/employees");
onClosed();
}) })
.catch((error) => { .catch((error) => {
const message = const message =
@ -232,7 +240,7 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
className="cursor-pointer fs-6" className="cursor-pointer fs-6"
onClick={() => onClosed()} onClick={() => onClosed()}
> >
<i className='bx bx-x'></i> <i className="bx bx-x"></i>
</span> </span>
</div> </div>
<div className="card-body"> <div className="card-body">
@ -250,15 +258,15 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
name="FirstName" name="FirstName"
{...register("firstName")} {...register("firstName")}
className="form-control form-control-sm" className="form-control form-control-sm"
id="FirstName" id="firstName"
placeholder="First Name" placeholder="First Name"
/> />
{errors.FirstName && ( {errors.firstName && (
<div <div
className="danger-text text-start" className="danger-text text-start"
style={{ fontSize: "12px" }} style={{ fontSize: "12px" }}
> >
{errors.FirstName.message} {errors.firstName.message}
</div> </div>
)} )}
</div>{" "} </div>{" "}
@ -269,15 +277,15 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
type="text" type="text"
{...register("middleName")} {...register("middleName")}
className="form-control form-control-sm" className="form-control form-control-sm"
id="MiddleName" id="middleName"
placeholder="Middle Name" placeholder="Middle Name"
/> />
{errors.MiddleName && ( {errors.middleName && (
<div <div
className="danger-text text-start " className="danger-text text-start "
style={{ fontSize: "12px" }} style={{ fontSize: "12px" }}
> >
{errors.MiddleName.message} {errors.middleName.message}
</div> </div>
)} )}
</div> </div>
@ -287,15 +295,15 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
type="text" type="text"
{...register("lastName")} {...register("lastName")}
className="form-control form-control-sm" className="form-control form-control-sm"
id="LastName" id="lastName"
placeholder="Last Name" placeholder="Last Name"
/> />
{errors.LastName && ( {errors.lastName && (
<div <div
className="danger-text text-start" className="danger-text text-start"
style={{ fontSize: "12px" }} style={{ fontSize: "12px" }}
> >
{errors.LastName.message} {errors.lastName.message}
</div> </div>
)} )}
</div> </div>
@ -305,7 +313,7 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
<div className="form-text text-start">Email</div> <div className="form-text text-start">Email</div>
<input <input
type="email" type="email"
id="Email" id="email"
{...register("email")} {...register("email")}
className="form-control form-control-sm" className="form-control form-control-sm"
placeholder="example@domain.com" placeholder="example@domain.com"
@ -313,12 +321,12 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
aria-describedby="Email" aria-describedby="Email"
disabled={!!currentEmployee?.email} disabled={!!currentEmployee?.email}
/> />
{errors.Email && ( {errors.email && (
<div <div
className="danger-text text-start" className="danger-text text-start"
style={{ fontSize: "12px" }} style={{ fontSize: "12px" }}
> >
{errors.Email.message} {errors.email.message}
</div> </div>
)} )}
</div> </div>
@ -327,19 +335,19 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
<input <input
type="text" type="text"
keyboardType="numeric" keyboardType="numeric"
id="PhoneNumber" id="phoneNumber"
{...register("phoneNumber")} {...register("phoneNumber")}
className="form-control form-control-sm" className="form-control form-control-sm"
placeholder="Phone Number" placeholder="Phone Number"
inputMode="numeric" inputMode="numeric"
maxLength={10} maxLength={10}
/> />
{errors.PhoneNumber && ( {errors.phoneNumber && (
<div <div
className="danger-text text-start" className="danger-text text-start"
style={{ fontSize: "12px" }} style={{ fontSize: "12px" }}
> >
{errors.PhoneNumber.message} {errors.phoneNumber.message}
</div> </div>
)} )}
</div> </div>
@ -353,7 +361,7 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
<select <select
className="form-select form-select-sm " className="form-select form-select-sm "
{...register("gender")} {...register("gender")}
id="Gender" id="gender"
aria-label="" aria-label=""
> >
<option disabled value=""> <option disabled value="">
@ -364,12 +372,12 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
<option value="Other">Other</option> <option value="Other">Other</option>
</select> </select>
</div> </div>
{errors.Gender && ( {errors.gender && (
<div <div
className="danger-text text-start" className="danger-text text-start"
style={{ fontSize: "12px" }} style={{ fontSize: "12px" }}
> >
{errors.Gender.message} {errors.gender.message}
</div> </div>
)} )}
</div> </div>
@ -381,15 +389,15 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
className="form-control form-control-sm" className="form-control form-control-sm"
type="date" type="date"
{...register("birthDate")} {...register("birthDate")}
id="BirthDate" id="birthDate"
/> />
</div> </div>
{errors.BirthDate && ( {errors.birthDate && (
<div <div
className="danger-text text-start" className="danger-text text-start"
style={{ fontSize: "12px" }} style={{ fontSize: "12px" }}
> >
{errors.BirthDate.message} {errors.birthDate.message}
</div> </div>
)} )}
</div> </div>
@ -401,15 +409,15 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
className="form-control form-control-sm" className="form-control form-control-sm"
type="date" type="date"
{...register("joiningDate")} {...register("joiningDate")}
id="JoiningDate" id="joiningDate"
/> />
</div> </div>
{errors.JoiningDate && ( {errors.joiningDate && (
<div <div
className="danger-text text-start" className="danger-text text-start"
style={{ fontSize: "12px" }} style={{ fontSize: "12px" }}
> >
{errors.JoiningDate.message} {errors.joiningDate.message}
</div> </div>
)} )}
</div> </div>
@ -419,7 +427,7 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
<div className="form-text text-start">Current Address</div> <div className="form-text text-start">Current Address</div>
<textarea <textarea
id="CurrentAddress" id="currentAddress"
className="form-control form-control-sm" className="form-control form-control-sm"
placeholder="Current Address" placeholder="Current Address"
aria-label="Current Address" aria-label="Current Address"
@ -429,7 +437,7 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
onChange={(e) => { onChange={(e) => {
setCurrentAddressLength(e.target.value.length); setCurrentAddressLength(e.target.value.length);
// let react-hook-form still handle it // let react-hook-form still handle it
register("CurrentAddress").onChange(e); register("currentAddress").onChange(e);
}} }}
></textarea> ></textarea>
<div className="text-end muted"> <div className="text-end muted">
@ -438,12 +446,12 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
{500 - currentAddressLength} characters left {500 - currentAddressLength} characters left
</small> </small>
</div> </div>
{errors.CurrentAddress && ( {errors.currentAddress && (
<div <div
className="danger-text text-start" className="danger-text text-start"
style={{ fontSize: "12px" }} style={{ fontSize: "12px" }}
> >
{errors.CurrentAddress.message} {errors.currentAddress.message}
</div> </div>
)} )}
</div> </div>
@ -453,7 +461,7 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
</div> </div>
<textarea <textarea
id="PermanentAddress" id="permanentAddress"
className="form-control form-control-sm" className="form-control form-control-sm"
placeholder="Permanent Address" placeholder="Permanent Address"
aria-label="Permanent Address" aria-label="Permanent Address"
@ -462,7 +470,7 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
maxLength={500} maxLength={500}
onChange={(e) => { onChange={(e) => {
setPermanentAddressLength(e.target.value.length); setPermanentAddressLength(e.target.value.length);
register("PermanentAddress").onChange(e); register("permanentAddress").onChange(e);
}} }}
></textarea> ></textarea>
<div className="text-end muted"> <div className="text-end muted">
@ -470,12 +478,12 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
{500 - permanentAddressLength} characters left {500 - permanentAddressLength} characters left
</small> </small>
</div> </div>
{errors.PermanentAddress && ( {errors.permanentAddress && (
<div <div
className="danger-text text-start" className="danger-text text-start"
style={{ fontSize: "12px" }} style={{ fontSize: "12px" }}
> >
{errors.PermanentAddress.message} {errors.permanentAddress.message}
</div> </div>
)} )}
</div> </div>
@ -493,7 +501,7 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
<select <select
className="form-select form-select-sm" className="form-select form-select-sm"
{...register("jobRoleId")} {...register("jobRoleId")}
id="JobRoleId" id="jobRoleId"
aria-label="" aria-label=""
> >
<option disabled value=""> <option disabled value="">
@ -506,12 +514,12 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
))} ))}
</select> </select>
</div> </div>
{errors.JobRoleId && ( {errors.jobRoleId && (
<div <div
className="danger-text text-start" className="danger-text text-start"
style={{ fontSize: "12px" }} style={{ fontSize: "12px" }}
> >
{errors.JobRoleId.message} {errors.jobRoleId.message}
</div> </div>
)} )}
</div> </div>
@ -523,16 +531,16 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
type="text" type="text"
{...register("emergencyContactPerson")} {...register("emergencyContactPerson")}
className="form-control form-control-sm" className="form-control form-control-sm"
id="EmergencyContactPerson" id="emergencyContactPerson"
maxLength={50} maxLength={50}
placeholder="Contact Person" placeholder="Contact Person"
/> />
{errors.EmergencyContactPerson && ( {errors.emergencyContactPerson && (
<div <div
className="danger-text text-start" className="danger-text text-start"
style={{ fontSize: "12px" }} style={{ fontSize: "12px" }}
> >
{errors.EmergencyContactPerson.message} {errors.emergencyContactPerson.message}
</div> </div>
)} )}
</div> </div>
@ -544,17 +552,17 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
type="text" type="text"
{...register("emergencyPhoneNumber")} {...register("emergencyPhoneNumber")}
className="form-control form-control-sm phone-mask" className="form-control form-control-sm phone-mask"
id="EmergencyPhoneNumber" id="emergencyPhoneNumber"
placeholder="Phone Number" placeholder="Phone Number"
inputMode="numeric" inputMode="numeric"
maxLength={10} maxLength={10}
/> />
{errors.EmergencyPhoneNumber && ( {errors.emergencyPhoneNumber && (
<div <div
className="danger-text text-start" className="danger-text text-start"
style={{ fontSize: "12px" }} style={{ fontSize: "12px" }}
> >
{errors.EmergencyPhoneNumber.message} {errors.emergencyPhoneNumber.message}
</div> </div>
)} )}
</div> </div>
@ -567,14 +575,14 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
type="text" type="text"
{...register("aadharNumber")} {...register("aadharNumber")}
className="form-control form-control-sm" className="form-control form-control-sm"
id="AadharNumber" id="aadharNumber"
placeholder="AADHAR Number" placeholder="AADHAR Number"
maxLength={12} maxLength={12}
inputMode="numeric" inputMode="numeric"
/> />
{errors.AadharNumber && ( {errors.aadharNumber && (
<div className="danger-text text-start"> <div className="danger-text text-start">
{errors.AadharNumber.message} {errors.aadharNumber.message}
</div> </div>
)} )}
</div> </div>
@ -585,16 +593,16 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
type="text" type="text"
{...register("panNumber")} {...register("panNumber")}
className="form-control form-control-sm" className="form-control form-control-sm"
id="PanNumber" id="panNumber"
placeholder="PAN Number" placeholder="PAN Number"
maxLength={10} maxLength={10}
/> />
{errors.PanNumber && ( {errors.panNumber && (
<div <div
className="danger-text text-start" className="danger-text text-start"
style={{ fontSize: "12px" }} style={{ fontSize: "12px" }}
> >
{errors.PanNumber.message} {errors.panNumber.message}
</div> </div>
)} )}
</div> </div>

View File

@ -88,7 +88,9 @@ const EditActivityModal = ({
setValue("workCategoryId", selectedId); setValue("workCategoryId", selectedId);
}; };
const onSubmitForm = async (data) => { const onSubmitForm = async ( data ) =>
{
setIsSubmitting(true)
const updatedProject = { ...projects_Details }; const updatedProject = { ...projects_Details };
const finalData = { const finalData = {
...data, ...data,
@ -153,14 +155,18 @@ const EditActivityModal = ({
data: newProject, data: newProject,
}); });
resetForm(); resetForm();
dispatch(refreshData(true)); dispatch( refreshData( true ) );
showToast("Activity Updated Successfully", "success"); setIsSubmitting(false)
showToast("Activity Updated Successfully","success")
onClose(); onClose();
} }
}) })
.catch((error) => { .catch( ( error ) =>
showToast(error?.response?.data?.message || error.message, "error"); {
setIsSubmitting(false)
const message = error.response.data.message || error.message || "Error Occured During Api Call"
showToast( message, "error" );
}); });
}; };
@ -379,11 +385,7 @@ const EditActivityModal = ({
{/* )} */} {/* )} */}
<div className="col-12 text-center"> <div className="col-12 text-center">
<button <button type="submit" className="btn btn-sm btn-primary me-3" disabled={activities.length === 0 || isSubmitting}>
type="submit"
className="btn btn-sm btn-primary me-3"
disabled={activities.length === 0}
>
{isSubmitting ? "Please Wait.." : "Edit Task"} {isSubmitting ? "Please Wait.." : "Edit Task"}
</button> </button>
<button <button

View File

@ -209,9 +209,15 @@ export const useEmployeesAllOrByProjectId = (projectId, showInactive) => {
export const useEmployeeProfile = (employeeId) => { export const useEmployeeProfile = (employeeId) => {
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [error, setError] = useState(); const [error, setError] = useState();
const [employee, setEmployees] = useState(); const [employee, setEmployees] = useState(null);
const fetchData = async () => { const fetchData = async () => {
if (!employeeId) {
// Reset the state if no employeeId (e.g., opening for 'add' mode)
setEmployees(null);
setLoading(false);
return;
}
const Employee_cache = getCachedData("employeeProfile"); const Employee_cache = getCachedData("employeeProfile");
if (!Employee_cache || Employee_cache.employeeId !== employeeId) { if (!Employee_cache || Employee_cache.employeeId !== employeeId) {
EmployeeRepository.getEmployeeProfile(employeeId) EmployeeRepository.getEmployeeProfile(employeeId)
@ -231,9 +237,7 @@ export const useEmployeeProfile = (employeeId) => {
}; };
useEffect(() => { useEffect(() => {
if (employeeId) { fetchData();
fetchData(employeeId);
}
}, [employeeId]); }, [employeeId]);
return { employee, loading, error }; return { employee, loading, error };

View File

@ -43,7 +43,7 @@ const EmployeeList = () => {
const [searchText, setSearchText] = useState(""); const [searchText, setSearchText] = useState("");
const [filteredData, setFilteredData] = useState([]); const [filteredData, setFilteredData] = useState([]);
const [showModal, setShowModal] = useState(false); const [showModal, setShowModal] = useState(false);
const [selectedEmployeeId, setSelecedEmployeeId] = useState(); const [selectedEmployeeId, setSelecedEmployeeId] = useState(null);
const [IsDeleteModalOpen, setIsDeleteModalOpen] = useState(false); const [IsDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [selectedEmpFordelete, setSelectedEmpFordelete] = useState(null); const [selectedEmpFordelete, setSelectedEmpFordelete] = useState(null);
const [employeeLodaing, setemployeeLodaing] = useState(false); const [employeeLodaing, setemployeeLodaing] = useState(false);
@ -111,6 +111,8 @@ const EmployeeList = () => {
document.querySelector(".modal-backdrop").remove(); document.querySelector(".modal-backdrop").remove();
} }
setShowModal(false); setShowModal(false);
clearCacheKey("employeeProfile");
recallEmployeeData(showInactive);
}; };
const handleShow = () => setShowModal(true); const handleShow = () => setShowModal(true);
const handleClose = () => setShowModal(false); const handleClose = () => setShowModal(false);
@ -193,7 +195,7 @@ const EmployeeList = () => {
{isCreateModalOpen && ( {isCreateModalOpen && (
<ManageEmp employeeId={modelConfig} onClosed={closeModal} /> <ManageEmp employeeId={modelConfig} onClosed={closeModal} />
)} )}
<div {showModal && (<div
className={`modal fade ${showModal ? "show" : ""} `} className={`modal fade ${showModal ? "show" : ""} `}
tabIndex="-1" tabIndex="-1"
role="dialog" role="dialog"
@ -211,7 +213,7 @@ const EmployeeList = () => {
/> />
</div> </div>
</div> </div>
</div> </div>)}
{IsDeleteModalOpen && ( {IsDeleteModalOpen && (
<div <div