diff --git a/src/components/DailyProgressRport/TaskReportFilterPanel.jsx b/src/components/DailyProgressRport/TaskReportFilterPanel.jsx index 8394a158..e682ad14 100644 --- a/src/components/DailyProgressRport/TaskReportFilterPanel.jsx +++ b/src/components/DailyProgressRport/TaskReportFilterPanel.jsx @@ -39,14 +39,12 @@ const TaskReportFilterPanel = ({ handleFilter }) => { dateTo: localToUtc(formData.dateTo), }; handleFilter(filterPayload); - closePanel(); }; const onClear = () => { setResetKey((prev) => prev + 1); handleFilter(TaskReportDefaultValue); reset(TaskReportDefaultValue); - closePanel(); }; return ( diff --git a/src/components/DailyProgressRport/TaskReportList.jsx b/src/components/DailyProgressRport/TaskReportList.jsx index 00cb064e..bcb4232b 100644 --- a/src/components/DailyProgressRport/TaskReportList.jsx +++ b/src/components/DailyProgressRport/TaskReportList.jsx @@ -204,24 +204,34 @@ const TaskReportList = () => { This shows the total pending tasks for each activity on that date.

} + content={ +
+ This shows the total pending tasks for each activity on that date. +
+ } >
+ Reported/Planned{" "} This shows the reported versus planned tasks for each activity on that date.

} + content={ +
+ This shows the reported versus planned tasks for each activity on that date. +
+ } >
+ Assign Date Team Actions diff --git a/src/components/Dashboard/AttendanceOverview.jsx b/src/components/Dashboard/AttendanceOverview.jsx index 77fbee51..e6fc0624 100644 --- a/src/components/Dashboard/AttendanceOverview.jsx +++ b/src/components/Dashboard/AttendanceOverview.jsx @@ -100,7 +100,7 @@ const AttendanceOverview = () => { }; return ( -
+
{/* Header */}
diff --git a/src/components/Dashboard/Dashboard.jsx b/src/components/Dashboard/Dashboard.jsx index ad5ead8c..e5ed7edc 100644 --- a/src/components/Dashboard/Dashboard.jsx +++ b/src/components/Dashboard/Dashboard.jsx @@ -17,12 +17,19 @@ import ExpenseAnalysis from "./ExpenseAnalysis"; import ExpenseStatus from "./ExpenseStatus"; import ExpenseByProject from "./ExpenseByProject"; import ProjectStatistics from "../Project/ProjectStatistics"; +import ServiceJobs from "./ServiceJobs"; +import { useHasUserPermission } from "../../hooks/useHasUserPermission"; +import { REGULARIZE_ATTENDANCE, SELF_ATTENDANCE, TEAM_ATTENDANCE } from "../../utils/constants"; const Dashboard = () => { // Get the selected project ID from Redux store const projectId = useSelector((store) => store.localVariables.projectId); const isAllProjectsSelected = projectId === null; + const canRegularize = useHasUserPermission(REGULARIZE_ATTENDANCE); + const canTeamAttendance = useHasUserPermission(TEAM_ATTENDANCE); + const canSelfAttendance = useHasUserPermission(SELF_ATTENDANCE); + return (
@@ -49,7 +56,7 @@ const Dashboard = () => {
- {!isAllProjectsSelected && ( + {!isAllProjectsSelected && (canRegularize || canTeamAttendance || canSelfAttendance) && (
@@ -57,7 +64,9 @@ const Dashboard = () => { {!isAllProjectsSelected && (
- +
+ +
)}
@@ -74,6 +83,9 @@ const Dashboard = () => {
+ {/*
+ +
*/}
); diff --git a/src/components/Dashboard/ServiceJobs.jsx b/src/components/Dashboard/ServiceJobs.jsx new file mode 100644 index 00000000..987addda --- /dev/null +++ b/src/components/Dashboard/ServiceJobs.jsx @@ -0,0 +1,237 @@ +import React from "react"; + +const ServiceJobs = () => { + return ( +
+
+
+
+
Service Jobs
+

All Projects

+
+
+ +
+
+ + {/* Tabs */} +
    +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+ + {/* Tab Content */} +
+ + {/* ---------------------- NEW TAB ---------------------- */} +
+ {/* Entry 1 */} +
    +
  • + + + +
    +
    + Sender +
    +
    Myrtle Ullrich
    +

    101 Boulder, California(CA), 95959

    +
    +
  • +
  • + + + +
    +
    + Receiver +
    +
    Barry Schowalter
    +

    939 Orange, California(CA), 92118

    +
    +
  • +
+ +
+ + {/* Entry 2 */} +
    +
  • + + + +
    +
    + Sender +
    +
    Veronica Herman
    +

    162 Windsor, California(CA), 95492

    +
    +
  • +
  • + + + +
    +
    + Receiver +
    +
    Helen Jacobs
    +

    487 Sunset, California(CA), 94043

    +
    +
  • +
+
+ + {/* ---------------------- PREPARING TAB ---------------------- */} +
+ + {/* Entry 1 */} +
    +
  • + + + +
    +
    + Sender +
    +
    Oliver Grant
    +

    220 Pine St, California(CA), 95765

    +
    +
  • + +
  • + + + +
    +
    + Receiver +
    +
    Samantha Lee
    +

    744 Bay Area, California(CA), 94016

    +
    +
  • +
+ +
+ + {/* Entry 2 */} +
    +
  • + + + +
    +
    + Sender +
    +
    Marcus Howard
    +

    58 Avenue, California(CA), 95376

    +
    +
  • + +
  • + + + +
    +
    + Receiver +
    +
    Daniel Foster
    +

    312 Marina, California(CA), 94109

    +
    +
  • +
+
+ + {/* ---------------------- SHIPPING TAB ---------------------- */} +
+ + {/* Entry 1 */} +
    +
  • + + + +
    +
    + Sender +
    +
    James Carter
    +

    441 Market St, California(CA), 94111

    +
    +
  • + +
  • + + + +
    +
    + Receiver +
    +
    Linda Moore
    +

    990 Willow Road, California(CA), 94025

    +
    +
  • +
+ +
+ + {/* Entry 2 */} +
    +
  • + + + +
    +
    + Sender +
    +
    Sarah Bennett
    +

    882 Canyon Rd, California(CA), 94704

    +
    +
  • + +
  • + + + +
    +
    + Receiver +
    +
    George Simmons
    +

    19 Palm St, California(CA), 93001

    +
    +
  • +
+
+ +
+
+
+ +
+
+ ); +}; + +export default ServiceJobs; diff --git a/src/components/Project/ProjectStatistics.jsx b/src/components/Project/ProjectStatistics.jsx index 7ec5dbd3..ac7a8f2a 100644 --- a/src/components/Project/ProjectStatistics.jsx +++ b/src/components/Project/ProjectStatistics.jsx @@ -165,7 +165,7 @@ const ProjectStatistics = ({ project }) => { }, [selectedProject]); return ( -
+ <>
{" "} @@ -242,8 +242,8 @@ const ProjectStatistics = ({ project }) => {
+ -
); }; diff --git a/src/components/RecurringExpense/ManageRecurringExpense.jsx b/src/components/RecurringExpense/ManageRecurringExpense.jsx index a399867d..2d29400a 100644 --- a/src/components/RecurringExpense/ManageRecurringExpense.jsx +++ b/src/components/RecurringExpense/ManageRecurringExpense.jsx @@ -252,16 +252,15 @@ const ManageRecurringExpense = ({ closeModal, requestToEdit = null }) => { -

- Choose whether the payment amount varies or remains fixed - each cycle. -
- Is Variable: Amount changes per cycle. -
- Fixed: Amount stays constant. -

+
+ Choose whether the payment amount varies or remains fixed + each cycle. +
+ Is Variable: Amount changes per cycle. +
+ Fixed: Amount stays constant.
} > @@ -476,10 +475,10 @@ const ManageRecurringExpense = ({ closeModal, requestToEdit = null }) => { title="Payment Buffer Days" id="payment_buffer_days" content={ -

+

Number of extra days allowed after the due date before payment is considered late. -

+
} > @@ -511,10 +510,11 @@ const ManageRecurringExpense = ({ closeModal, requestToEdit = null }) => { +
The date when the last payment in the recurrence occurs. -

+
} > @@ -592,8 +592,8 @@ const ManageRecurringExpense = ({ closeModal, requestToEdit = null }) => { {createPending || isPending ? "Please wait...." : requestToEdit - ? "Update" - : "Save as Draft"} + ? "Update" + : "Save as Draft"}
diff --git a/src/components/common/HoverPopup.jsx b/src/components/common/HoverPopup.jsx index 1063745b..232ced5d 100644 --- a/src/components/common/HoverPopup.jsx +++ b/src/components/common/HoverPopup.jsx @@ -58,139 +58,66 @@ const HoverPopup = ({ return () => document.removeEventListener("click", handler); }, [Mode, visible, dispatch, id]); - // Positioning effect: respects align prop and stays inside boundary (drawer) useEffect(() => { if (!visible || !popupRef.current || !triggerRef.current) return; - // run in next frame so DOM/layout settles requestAnimationFrame(() => { const popup = popupRef.current; - - // choose boundary: provided boundaryRef or nearest positioned parent (popup.parentElement) - const boundaryEl = - (boundaryRef && boundaryRef.current) || popup.parentElement; + const boundaryEl = (boundaryRef && boundaryRef.current) || popup.parentElement; if (!boundaryEl) return; const boundaryRect = boundaryEl.getBoundingClientRect(); const triggerRect = triggerRef.current.getBoundingClientRect(); - - // reset styles first popup.style.left = ""; popup.style.right = ""; popup.style.transform = ""; popup.style.top = ""; const popupRect = popup.getBoundingClientRect(); - const parentRect = boundaryRect; // alias + const triggerCenterX = triggerRect.left + triggerRect.width / 2 - boundaryRect.left; + let left = triggerCenterX - popupRect.width / 2; - // Convert trigger center to parent coordinates - const triggerCenterX = - triggerRect.left + triggerRect.width / 2 - parentRect.left; - - // preferred left so popup center aligns to trigger center: - const preferredLeft = triggerCenterX - popupRect.width / 2; - - // Helpers to set styles in parent's coordinate system: - const setLeft = (leftPx) => { - popup.style.left = `${leftPx}px`; - popup.style.right = "auto"; - popup.style.transform = "none"; - }; - const setRight = (rightPx) => { - popup.style.left = "auto"; - popup.style.right = `${rightPx}px`; - popup.style.transform = "none"; - }; - - // If user forced align: - if (align === "left") { - // align popup's left to parent's left (0) - setLeft(0); - return; - } - if (align === "right") { - // align popup's right to parent's right (0) - setRight(0); - return; - } - if (align === "center") { - popup.style.left = "50%"; - popup.style.right = "auto"; - popup.style.transform = "translateX(-50%)"; - return; - } - - // align === "auto": try preferred centered position, but flip fully if overflow - // clamp preferredLeft to boundaries so it doesn't render partially outside - const leftIfCentered = Math.max( - 0, - Math.min(preferredLeft, parentRect.width - popupRect.width) - ); - - // if centered fits, use it - if (leftIfCentered === preferredLeft) { - setLeft(leftIfCentered); - return; - } - - // if centering would overflow right -> stick popup fully to left (left=0) - if (preferredLeft > parentRect.width - popupRect.width) { - // place popup so its right aligns to parent's right - // i.e., left = parent width - popup width - setLeft(parentRect.width - popupRect.width); - return; - } - - // if centering would overflow left -> stick popup fully to left=0 - if (preferredLeft < 0) { - setLeft(0); - return; - } - - // fallback center - setLeft(leftIfCentered); + // Clamp to boundaries + left = Math.max(0, Math.min(left, boundaryRect.width - popupRect.width)); + popup.style.left = `${left}px`; }); }, [visible, align, boundaryRef]); - return ( -
+ return (
- {children} -
- - {visible && (
e.stopPropagation()} + + ref={triggerRef} + onMouseEnter={handleMouseEnter} + onMouseLeave={handleMouseLeave} + onClick={handleClick} + style={{ cursor: "pointer", display: "inline-block" }} > - {title &&
{title}
} -
{content}
+ {children}
- )} -
-); + + {visible && ( +
e.stopPropagation()} + > + {title &&
{title}
} +
{content}
+
+ )} +
+ ); }; diff --git a/src/pages/project/ProjectDetails.jsx b/src/pages/project/ProjectDetails.jsx index 298e95fb..b8ab45d6 100644 --- a/src/pages/project/ProjectDetails.jsx +++ b/src/pages/project/ProjectDetails.jsx @@ -24,6 +24,9 @@ import { useProjectAccess } from "../../hooks/useProjectAccess"; import "./ProjectDetails.css"; import ProjectOrganizations from "../../components/Project/ProjectOrganizations"; +import ProjectStatistics from "../../components/Project/ProjectStatistics"; +import { useHasUserPermission } from "../../hooks/useHasUserPermission"; +import { REGULARIZE_ATTENDANCE, SELF_ATTENDANCE, TEAM_ATTENDANCE } from "../../utils/constants"; const ProjectDetails = () => { const projectId = useSelectedProject(); @@ -34,6 +37,10 @@ const ProjectDetails = () => { useProjectDetails(projectId); const { canView, loading: permsLoading } = useProjectAccess(projectId); + const canRegularize = useHasUserPermission(REGULARIZE_ATTENDANCE); + const canTeamAttendance = useHasUserPermission(TEAM_ATTENDANCE); + const canSelfAttendance = useHasUserPermission(SELF_ATTENDANCE); + useEffect(() => { if (!projectId && projectNames.length > 0) { @@ -82,13 +89,16 @@ const ProjectDetails = () => {
- +
+
-
- -
+ {(canRegularize || canTeamAttendance || canSelfAttendance) && ( +
+ +
+ )}
);