Merge branch 'Service_Project_Managment' of https://git.marcoaiot.com/admin/marco.pms.web into Service_Project_Managment
This commit is contained in:
commit
9b7988d6d8
@ -83,9 +83,12 @@ const EmpDashboard = ({ profile }) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-12 col-sm-6 pt-5">
|
<div className="col-12 col-sm-6 pt-5">
|
||||||
{" "}
|
<EmpReportingManager
|
||||||
<EmpReportingManager employeeId={profile?.id}></EmpReportingManager>
|
employeeId={profile?.id}
|
||||||
|
employee={profile}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -2,61 +2,59 @@ import React, { useState } from "react";
|
|||||||
import { useOrganizationHierarchy } from "../../hooks/useEmployees";
|
import { useOrganizationHierarchy } from "../../hooks/useEmployees";
|
||||||
import GlobalModel from "../common/GlobalModel";
|
import GlobalModel from "../common/GlobalModel";
|
||||||
import ManageReporting from "./ManageReporting";
|
import ManageReporting from "./ManageReporting";
|
||||||
|
import Avatar from "../common/Avatar";
|
||||||
|
import { SpinnerLoader } from "../common/Loader";
|
||||||
|
|
||||||
const EmpReportingManager = ({ employeeId, employee }) => {
|
const EmpReportingManager = ({ employeeId, employee }) => {
|
||||||
const { data, isLoading } = useOrganizationHierarchy(employeeId);
|
const { data, isLoading } = useOrganizationHierarchy(employeeId);
|
||||||
const [showManageReportingModal, setShowManageReportingModal] = useState(false);
|
const [showManageReportingModal, setShowManageReportingModal] = useState(false);
|
||||||
|
|
||||||
if (isLoading) return <span>Loading...</span>;
|
if (isLoading)
|
||||||
|
return (
|
||||||
|
<div className="d-flex justify-content-center py-5">
|
||||||
|
<SpinnerLoader />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
const primary = data?.find((item) => item.isPrimary);
|
// Safe access to primary and secondary managers
|
||||||
const secondary = data?.filter((item) => !item.isPrimary);
|
const primaryManager = data?.find((d) => d.isPrimary)?.reportTo;
|
||||||
|
const secondaryManagers = data?.filter((d) => !d.isPrimary).map((d) => d.reportTo) || [];
|
||||||
// Create comma-separated string for secondary managers
|
|
||||||
const secondaryNames = secondary
|
|
||||||
?.map((item) => `${item.reportTo?.firstName || ""} ${item.reportTo?.lastName || ""}`.trim())
|
|
||||||
.join(", ");
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-12 mb-4">
|
<div className="col-12 mb-4">
|
||||||
<div className="card">
|
<div className="card">
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<h5 className="m-0 py-1 mb-3">
|
<small className="card-text text-uppercase text-body-secondary small d-block text-start mb-3">
|
||||||
Update Reporting Manager
|
Reporting Manager
|
||||||
|
</small>
|
||||||
|
|
||||||
</h5>
|
<div className="text-start">
|
||||||
|
{/* Primary Manager */}
|
||||||
|
<div className="row mb-2 align-items-start">
|
||||||
{/* Primary Reporting Manager */}
|
<div className="col-auto text-end pe-3"><i className="bx bx-user-circle me-1"></i>Primary Manager<span style={{ marginLeft: "50px" }}>:</span></div>
|
||||||
<div className="d-flex align-items-start mb-3">
|
<div className="col text-wrap">
|
||||||
<span className="d-flex">
|
{primaryManager
|
||||||
<i className="bx bx-user bx-xs me-2 mt-1"></i>
|
? `${primaryManager.firstName || ""} ${primaryManager.lastName || ""}`
|
||||||
<span>Primary Reporting Manager</span>
|
: "NA"}
|
||||||
</span>
|
</div>
|
||||||
<span style={{ marginLeft: "75px" }}>:</span>
|
|
||||||
<span className="ms-5">
|
|
||||||
{primary?.reportTo?.firstName || <em>NA</em>}{" "}
|
|
||||||
{primary?.reportTo?.lastName || ""}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Secondary Reporting Manager (comma-separated) */}
|
{/* Secondary Managers */}
|
||||||
{secondary?.length > 0 && (
|
{secondaryManagers?.length > 0 && (
|
||||||
<div className="d-flex align-items-start mb-3" style={{ textAlign: "left" }}>
|
<div className="row mb-3 align-items-start">
|
||||||
<span className="d-flex">
|
<div className="col-auto text-end pe-3"><i className="bx bx-group me-1"></i>Secondary Managers<span style={{ marginLeft: "25px" }}>:</span></div>
|
||||||
<i className="bx bx-user bx-xs me-2 mt-1"></i>
|
<div className="col text-wrap">
|
||||||
<span>Secondary Reporting Manager</span>
|
{secondaryManagers
|
||||||
</span>
|
.map((m) => `${m.firstName || ""} ${m.lastName || ""}`)
|
||||||
<span style={{ marginLeft: "57px" }}>:</span>
|
.join(", ")}
|
||||||
<span className="ms-5" >
|
</div>
|
||||||
{secondaryNames || <em>NA</em>}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Open Modal Button */}
|
{/* Manage Reporting Button */}
|
||||||
<div className="mt-3 text-end">
|
<div className="mt-5 text-end" >
|
||||||
<button
|
<button
|
||||||
className="btn btn-sm btn-primary"
|
className="btn btn-sm btn-primary"
|
||||||
onClick={() => setShowManageReportingModal(true)}
|
onClick={() => setShowManageReportingModal(true)}
|
||||||
@ -75,11 +73,10 @@ const EmpReportingManager = ({ employeeId, employee }) => {
|
|||||||
closeModal={() => setShowManageReportingModal(false)}
|
closeModal={() => setShowManageReportingModal(false)}
|
||||||
>
|
>
|
||||||
<ManageReporting
|
<ManageReporting
|
||||||
|
employee={employee}
|
||||||
employeeId={employeeId}
|
employeeId={employeeId}
|
||||||
employee={primary?.employee || {}}
|
|
||||||
onClosed={() => setShowManageReportingModal(false)}
|
onClosed={() => setShowManageReportingModal(false)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</GlobalModel>
|
</GlobalModel>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@ -87,3 +84,4 @@ const EmpReportingManager = ({ employeeId, employee }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default EmpReportingManager;
|
export default EmpReportingManager;
|
||||||
|
|
||||||
|
|||||||
@ -5,6 +5,8 @@ import Label from "../common/Label";
|
|||||||
import PmsEmployeeInputTag from "../common/PmsEmployeeInputTag";
|
import PmsEmployeeInputTag from "../common/PmsEmployeeInputTag";
|
||||||
import { useManageEmployeeHierarchy, useOrganizationHierarchy } from "../../hooks/useEmployees";
|
import { useManageEmployeeHierarchy, useOrganizationHierarchy } from "../../hooks/useEmployees";
|
||||||
import { ManageReportingSchema, defaultManageReporting } from "./EmployeeSchema";
|
import { ManageReportingSchema, defaultManageReporting } from "./EmployeeSchema";
|
||||||
|
import Avatar from "../common/Avatar";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
const ManageReporting = ({ onClosed, employee, employeeId }) => {
|
const ManageReporting = ({ onClosed, employee, employeeId }) => {
|
||||||
const {
|
const {
|
||||||
@ -17,6 +19,7 @@ const ManageReporting = ({ onClosed, employee, employeeId }) => {
|
|||||||
resolver: zodResolver(ManageReportingSchema),
|
resolver: zodResolver(ManageReportingSchema),
|
||||||
defaultValues: defaultManageReporting,
|
defaultValues: defaultManageReporting,
|
||||||
});
|
});
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const { data, isLoading } = useOrganizationHierarchy(employeeId);
|
const { data, isLoading } = useOrganizationHierarchy(employeeId);
|
||||||
|
|
||||||
@ -25,7 +28,6 @@ const ManageReporting = ({ onClosed, employee, employeeId }) => {
|
|||||||
employeeId,
|
employeeId,
|
||||||
onClosed
|
onClosed
|
||||||
);
|
);
|
||||||
|
|
||||||
const primaryValue = watch("primaryNotifyTo");
|
const primaryValue = watch("primaryNotifyTo");
|
||||||
const secondaryValue = watch("secondaryNotifyTo");
|
const secondaryValue = watch("secondaryNotifyTo");
|
||||||
|
|
||||||
@ -88,16 +90,48 @@ const ManageReporting = ({ onClosed, employee, employeeId }) => {
|
|||||||
manageHierarchy(payload);
|
manageHierarchy(payload);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
|
handleClose();
|
||||||
|
navigate(`/employee/${employee.id}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<form onSubmit={handleSubmit(onSubmit)} className="p-sm-0 p-2">
|
<form onSubmit={handleSubmit(onSubmit)} className="p-sm-0 p-2">
|
||||||
<h5 className="m-0 py-1 mb-3">
|
<h5 className="m-0 py-1 mb-4">Reporting Manager</h5>
|
||||||
Update Reporting Manager (
|
|
||||||
{`${employee.firstName || ""} ${employee.middleName || ""} ${employee.lastName || ""}`.trim()}
|
|
||||||
)
|
|
||||||
</h5>
|
|
||||||
|
|
||||||
{/* Primary */}
|
{/* Employee Info */}
|
||||||
|
<div className="d-flex align-items-center justify-content-start mb-4 ps-0">
|
||||||
|
<div className="me-1 mb-1">
|
||||||
|
<Avatar size="sm" firstName={employee.firstName} lastName={employee.lastName} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Employee Name + Role */}
|
||||||
|
<div className="d-flex flex-column">
|
||||||
|
<div className="d-flex align-items-center gap-2">
|
||||||
|
<span className="fw-semibold text-dark fs-6 me-1 cursor-pointer" onClick={handleClick}>
|
||||||
|
{`${employee.firstName || ""} ${employee.middleName || ""} ${employee.lastName || ""}`.trim() || "Employee Name NA"}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{/* External Link Icon (Navigate to Employee Profile) */}
|
||||||
|
<i
|
||||||
|
className="bx bx-link-external text-primary"
|
||||||
|
style={{ fontSize: "1rem", cursor: "pointer" }}
|
||||||
|
title="View Profile"
|
||||||
|
onClick={handleClick}
|
||||||
|
></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="text-start">
|
||||||
|
{employee.jobRole && (
|
||||||
|
<small className="text-muted">{employee.jobRole}</small>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Primary Reporting Manager */}
|
||||||
<div className="mb-4 text-start">
|
<div className="mb-4 text-start">
|
||||||
<Label className="form-label" required>
|
<Label className="form-label" required>
|
||||||
Primary Reporting Manager
|
Primary Reporting Manager
|
||||||
@ -105,7 +139,7 @@ const ManageReporting = ({ onClosed, employee, employeeId }) => {
|
|||||||
<PmsEmployeeInputTag
|
<PmsEmployeeInputTag
|
||||||
control={control}
|
control={control}
|
||||||
name="primaryNotifyTo"
|
name="primaryNotifyTo"
|
||||||
placeholder={primaryValue?.length > 0 ? "" : "Select primary report-to"}
|
placeholder={primaryValue?.length > 0 ? "" : "Search and select primary manager"}
|
||||||
forAll={true}
|
forAll={true}
|
||||||
disabled={primaryValue?.length > 0}
|
disabled={primaryValue?.length > 0}
|
||||||
/>
|
/>
|
||||||
@ -116,21 +150,18 @@ const ManageReporting = ({ onClosed, employee, employeeId }) => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Secondary Reporting Manager */}
|
||||||
{/* Secondary */}
|
|
||||||
<div className="mb-4 text-start">
|
<div className="mb-4 text-start">
|
||||||
<Label className="form-label">
|
<Label className="form-label">Secondary Reporting Manager</Label>
|
||||||
Secondary Reporting Manager
|
|
||||||
</Label>
|
|
||||||
<PmsEmployeeInputTag
|
<PmsEmployeeInputTag
|
||||||
control={control}
|
control={control}
|
||||||
name="secondaryNotifyTo"
|
name="secondaryNotifyTo"
|
||||||
placeholder="Select secondary report-to(s)"
|
placeholder="Search and add secondary managers"
|
||||||
forAll={true}
|
forAll={true}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Buttons */}
|
||||||
<div className="d-flex justify-content-end gap-3 mt-3 mb-3">
|
<div className="d-flex justify-content-end gap-3 mt-3 mb-3">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@ -44,8 +44,7 @@ const PaymentRequestList = ({ filters, groupBy = "submittedBy", search }) => {
|
|||||||
displayField = "Status";
|
displayField = "Status";
|
||||||
break;
|
break;
|
||||||
case "submittedBy":
|
case "submittedBy":
|
||||||
key = `${item?.createdBy?.firstName ?? ""} ${
|
key = `${item?.createdBy?.firstName ?? ""} ${item.createdBy?.lastName ?? ""
|
||||||
item.createdBy?.lastName ?? ""
|
|
||||||
}`.trim();
|
}`.trim();
|
||||||
displayField = "Submitted By";
|
displayField = "Submitted By";
|
||||||
break;
|
break;
|
||||||
@ -93,40 +92,52 @@ const PaymentRequestList = ({ filters, groupBy = "submittedBy", search }) => {
|
|||||||
align: "text-start",
|
align: "text-start",
|
||||||
getValue: (e) => e.title || "N/A",
|
getValue: (e) => e.title || "N/A",
|
||||||
},
|
},
|
||||||
// { key: "payee", label: "Payee", align: "text-start" },
|
// {
|
||||||
{
|
// key: "SubmittedBy",
|
||||||
key: "SubmittedBy",
|
// label: "Submitted By",
|
||||||
label: "Submitted By",
|
// align: "text-start",
|
||||||
align: "text-start",
|
// getValue: (e) =>
|
||||||
getValue: (e) =>
|
// `${e.createdBy?.firstName ?? ""} ${
|
||||||
`${e.createdBy?.firstName ?? ""} ${
|
// e.createdBy?.lastName ?? ""
|
||||||
e.createdBy?.lastName ?? ""
|
// }`.trim() || "N/A",
|
||||||
}`.trim() || "N/A",
|
// customRender: (e) => (
|
||||||
customRender: (e) => (
|
// <div
|
||||||
<div
|
// className="d-flex align-items-center cursor-pointer"
|
||||||
className="d-flex align-items-center cursor-pointer"
|
// onClick={() => navigate(`/employee/${e.createdBy?.id}`)}
|
||||||
onClick={() => navigate(`/employee/${e.createdBy?.id}`)}
|
// >
|
||||||
>
|
// <Avatar
|
||||||
<Avatar
|
// size="xs"
|
||||||
size="xs"
|
// classAvatar="m-0"
|
||||||
classAvatar="m-0"
|
// firstName={e.createdBy?.firstName}
|
||||||
firstName={e.createdBy?.firstName}
|
// lastName={e.createdBy?.lastName}
|
||||||
lastName={e.createdBy?.lastName}
|
// />
|
||||||
/>
|
// <span className="text-truncate">
|
||||||
<span className="text-truncate">
|
// {`${e.createdBy?.firstName ?? ""} ${
|
||||||
{`${e.createdBy?.firstName ?? ""} ${
|
// e.createdBy?.lastName ?? ""
|
||||||
e.createdBy?.lastName ?? ""
|
// }`.trim() || "N/A"}
|
||||||
}`.trim() || "N/A"}
|
// </span>
|
||||||
</span>
|
// </div>
|
||||||
</div>
|
// ),
|
||||||
),
|
// },
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: "createdAt",
|
key: "createdAt",
|
||||||
label: "Submitted On",
|
label: "Created At",
|
||||||
align: "text-start",
|
align: "text-start",
|
||||||
getValue: (e) => formatUTCToLocalTime(e?.createdAt),
|
getValue: (e) => formatUTCToLocalTime(e?.createdAt),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: "payee",
|
||||||
|
label: "Payee",
|
||||||
|
align: "text-start",
|
||||||
|
getValue: (e) => e.payee || "N/A",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "dueDate",
|
||||||
|
label: "Due Date",
|
||||||
|
align: "text-start",
|
||||||
|
getValue: (e) => formatUTCToLocalTime(e?.dueDate),
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
key: "amount",
|
key: "amount",
|
||||||
label: "Amount",
|
label: "Amount",
|
||||||
@ -143,8 +154,7 @@ const PaymentRequestList = ({ filters, groupBy = "submittedBy", search }) => {
|
|||||||
align: "text-center",
|
align: "text-center",
|
||||||
getValue: (e) => (
|
getValue: (e) => (
|
||||||
<span
|
<span
|
||||||
className={`badge bg-label-${
|
className={`badge bg-label-${getColorNameFromHex(e?.expenseStatus?.color) || "secondary"
|
||||||
getColorNameFromHex(e?.expenseStatus?.color) || "secondary"
|
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{e?.expenseStatus?.name || "Unknown"}
|
{e?.expenseStatus?.name || "Unknown"}
|
||||||
@ -171,8 +181,8 @@ const PaymentRequestList = ({ filters, groupBy = "submittedBy", search }) => {
|
|||||||
const header = [
|
const header = [
|
||||||
"Request ID",
|
"Request ID",
|
||||||
"Request Title",
|
"Request Title",
|
||||||
"Submitted By",
|
"Created At",
|
||||||
"Submitted On",
|
"Due Date",
|
||||||
"Amount",
|
"Amount",
|
||||||
"Status",
|
"Status",
|
||||||
"Action",
|
"Action",
|
||||||
|
|||||||
@ -199,7 +199,7 @@ const ViewPaymentRequest = ({ requestId }) => {
|
|||||||
<div className="row text-start">
|
<div className="row text-start">
|
||||||
<div className="col-6 mb-3">
|
<div className="col-6 mb-3">
|
||||||
<label className="form-label me-2 mb-0 fw-semibold text-start">
|
<label className="form-label me-2 mb-0 fw-semibold text-start">
|
||||||
Supplier:
|
Payee:
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-6 mb-3">
|
<div className="col-6 mb-3">
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user