diff --git a/public/img/hero/bg-01.jpg b/public/img/hero/bg-01.jpg index 0ea8eebf..1303bc55 100644 Binary files a/public/img/hero/bg-01.jpg and b/public/img/hero/bg-01.jpg differ diff --git a/public/img/hero/bg-011.jpg b/public/img/hero/bg-011.jpg new file mode 100644 index 00000000..0ea8eebf Binary files /dev/null and b/public/img/hero/bg-011.jpg differ diff --git a/public/img/hero/bg-02.png b/public/img/hero/bg-02.png index e6acaea7..459984d6 100644 Binary files a/public/img/hero/bg-02.png and b/public/img/hero/bg-02.png differ diff --git a/public/img/hero/bg-03.png b/public/img/hero/bg-03.png index 622a1104..4db54e0c 100644 Binary files a/public/img/hero/bg-03.png and b/public/img/hero/bg-03.png differ diff --git a/src/components/Dashboard/ExpenseAnalysis.jsx b/src/components/Dashboard/ExpenseAnalysis.jsx index 69797733..4fee4cde 100644 --- a/src/components/Dashboard/ExpenseAnalysis.jsx +++ b/src/components/Dashboard/ExpenseAnalysis.jsx @@ -53,17 +53,17 @@ const ExpenseAnalysis = () => { dataLabels: { enabled: true, formatter: (val) => `${val.toFixed(0)}%` }, colors: flatColors, tooltip: { - y: { - formatter: function (value) { - return formatCurrency(value); + y: { + formatter: function (value) { + return formatCurrency(value); + }, + }, + x: { + formatter: function (label) { + return label; + }, }, }, - x: { - formatter: function (label) { - return label; - }, - }, - }, plotOptions: { pie: { donut: { @@ -100,7 +100,7 @@ const ExpenseAnalysis = () => {
- +
@@ -152,7 +152,9 @@ const ExpenseAnalysis = () => { className="col-6" key={idx} style={{ - borderLeft: `3px solid ${flatColors[idx % flatColors.length]}`, + borderLeft: `3px solid ${ + flatColors[idx % flatColors.length] + }`, }} >
@@ -177,7 +179,6 @@ const ExpenseAnalysis = () => {
- ))} diff --git a/src/components/Dashboard/ProjectWiseTeamCount.jsx b/src/components/Dashboard/ProjectWiseTeamCount.jsx index 3e5abb8f..c21c4bf5 100644 --- a/src/components/Dashboard/ProjectWiseTeamCount.jsx +++ b/src/components/Dashboard/ProjectWiseTeamCount.jsx @@ -7,8 +7,14 @@ import DatePicker from "../common/DatePicker"; import { useAppForm, useAppWatch } from "../../hooks/appHooks/useAppForm"; import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; +import { setProjectId } from "../../slices/localVariablesSlice"; +import { useDispatch } from "react-redux"; +import { useNavigate } from "react-router-dom"; const ProjectWiseTeamCount = () => { + const dispatch = useDispatch(); + const navigate = useNavigate(); + const { control } = useAppForm({ resolver: zodResolver( z.object({ @@ -20,6 +26,11 @@ const ProjectWiseTeamCount = () => { }, }); + const goToProject = (projectId) => () => { + dispatch(setProjectId(projectId)); + navigate(`/projects/details`); + }; + const selectedDate = useAppWatch({ control, name: "date" }); const { data, isLoading, isFetching, isError, error } = @@ -33,7 +44,7 @@ const ProjectWiseTeamCount = () => {
{/* Header */}
-
Project wise Employee
+
Attendance by Project
@@ -72,11 +83,21 @@ const ProjectWiseTeamCount = () => { className="d-flex align-items-center text-wrap my-2 text-start" style={{ width: "180px" }} > - {item.projectName} + + {" "} + {item.projectName} +
- {item.teamCount} - {item.attendanceCount} + + {item.teamCount} + + + {item.attendanceCount} + {/* {percent(item.teamCount, item.attendanceCount)}% */} ))} diff --git a/src/components/Dashboard/ServiceJobs.jsx b/src/components/Dashboard/ServiceJobs.jsx index d69a2faa..35ee2365 100644 --- a/src/components/Dashboard/ServiceJobs.jsx +++ b/src/components/Dashboard/ServiceJobs.jsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useEffect, useRef, useState } from "react"; import { useParams } from "react-router-dom"; import { useJobsProgression } from "../../hooks/useDashboard_Data"; import { SpinnerLoader } from "../common/Loader"; @@ -7,55 +7,90 @@ import { useServiceProject } from "../../hooks/useServiceProject"; const ServiceJobs = () => { const { projectId } = useParams(); + const { data, isLoading, isError } = useJobsProgression(projectId); const jobs = data || {}; - const { data: projectData, isLoading: projectLoading } = useServiceProject(projectId); + + const { data: projectData, isLoading: projectLoading } = + useServiceProject(projectId); + + const [activeTab, setActiveTab] = useState("tab-new"); + + // 👇 prevents re-running auto logic after first load + const hasInitializedTab = useRef(false); + const tabMapping = [ { id: "tab-new", label: "My Jobs", key: "myJobs" }, - { id: "tab-preparing", label: "Assigned", key: "assignedJobs" }, { id: "tab-shipping", label: "In Progress", key: "inProgressJobs" }, + { id: "tab-preparing", label: "Assigned", key: "assignedJobs" }, ]; + /* ---------- INITIAL TAB SELECTION ONLY ---------- */ + useEffect(() => { + if (hasInitializedTab.current || !jobs) return; + + if (jobs.myJobs?.length > 0) { + setActiveTab("tab-new"); + } else if (jobs.inProgressJobs?.length > 0) { + setActiveTab("tab-shipping"); + } else { + setActiveTab("tab-preparing"); + } + + hasInitializedTab.current = true; +}, [jobs]); + + return ( -
+
+ {/* Header */}
Service Jobs

- {projectLoading ? "Loading..." : projectData?.name || "All Projects"} + {projectLoading + ? "Loading..." + : projectData?.name || "All Projects"}

- - {/* ---------------- Tabs ---------------- */} -
    - {tabMapping.map((t, index) => ( -
  • + {/* Tabs */} +
      + {tabMapping.map((tab) => ( +
    • ))}
    - {/* ---------------- Tab Content ---------------- */} + {/* Content */}
    - {isLoading && ( -
    +
    )} - {isError && (

    { > No data found

    - )} {!isLoading && !isError && - tabMapping.map((t, index) => { - const list = jobs[t.key] || []; + tabMapping.map((tab) => { + const list = jobs[tab.key] || []; return (
    {list.length === 0 ? (

    { > No jobs found

    - ) : (
    - {list.map((job, i) => ( - + {list.map((job, index) => ( +
      - - {/* Assigned By */}
    • -
      - - Assigned By - -
      + + Assigned By +
      {job.assignedBy}

      {formatUTCToLocalTime(job.assignedAt)} @@ -121,23 +151,23 @@ const ServiceJobs = () => {

    • - {/* Project */}
    • -
      - Project -
      + + Project +
      {job.project}
      -

      {job.title}

      +

      + {job.title} +

    - {/* Divider */} - {i < list.length - 1 && ( + {index < list.length - 1 && (
    )}
    diff --git a/src/components/Layout/Sidebar.jsx b/src/components/Layout/Sidebar.jsx index 533de63b..f1daa0c8 100644 --- a/src/components/Layout/Sidebar.jsx +++ b/src/components/Layout/Sidebar.jsx @@ -13,22 +13,12 @@ const Sidebar = () => { id="layout-menu" className="layout-menu menu-vertical menu bg-menu-theme " > -
    +
    - {/* - logo - */} - OnFieldWork logo diff --git a/src/components/Project/ProjectInfra.jsx b/src/components/Project/ProjectInfra.jsx index cd817a77..2c1c4749 100644 --- a/src/components/Project/ProjectInfra.jsx +++ b/src/components/Project/ProjectInfra.jsx @@ -55,7 +55,7 @@ const ProjectInfra = ({ data, onDataChange, eachSiteEngineer }) => { const { data: assignedServices, isLoading: servicesLoading } = useProjectAssignedServices(projectId); - const { control } = useForm({ + const { control, setValue } = useForm({ defaultValues: { serviceId: selectedService || "", }, @@ -74,6 +74,22 @@ const ProjectInfra = ({ data, onDataChange, eachSiteEngineer }) => { }; + useEffect(() => { + if (!servicesLoading && assignedServices?.length === 1) { + const serviceId = assignedServices[0].id; + + // set form value + setValue("serviceId", serviceId, { + shouldDirty: true, + shouldValidate: true, + }); + + // sync redux + dispatch(setService(serviceId)); + } + }, [assignedServices, servicesLoading, setValue, dispatch]); + + return ( <> {showModalBuilding && ( @@ -132,31 +148,27 @@ const ProjectInfra = ({ data, onDataChange, eachSiteEngineer }) => {
    {!servicesLoading && assignedServices?.length > 0 && ( - assignedServices.length > 1 ? ( - ( - { - field.onChange(val); - handleServiceChange(val); - }} - isLoading={servicesLoading} - /> - )} - /> - ) : ( -
    {assignedServices[0].name}
    - ) + ( + { + field.onChange(val); + dispatch(setService(val)); + }} + isLoading={servicesLoading} + /> + )} + /> )} +
    diff --git a/src/components/Project/Team/TeamAssignToProject.jsx b/src/components/Project/Team/TeamAssignToProject.jsx index 9c99333a..45673f9d 100644 --- a/src/components/Project/Team/TeamAssignToProject.jsx +++ b/src/components/Project/Team/TeamAssignToProject.jsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import TeamEmployeeList from "./TeamEmployeeList"; import { useOrganization } from "../../../hooks/useDirectory"; import { useOrganizationsList } from "../../../hooks/useOrganization"; @@ -14,56 +14,48 @@ const TeamAssignToProject = ({ closeModal }) => { const project = useSelectedProject(); const { data, isLoading, isError, error } = useProjectAssignedOrganizationsName(project); - const { control, watch, formState: { errors } } = useForm({ + const { control, watch, setValue, formState: { errors } } = useForm({ defaultValues: { organizationId: "" }, }); + + useEffect(() => { + if (data?.length === 1) { + setValue("organizationId", data[0].id, { + shouldValidate: true, + shouldDirty: true, + }); + } + }, [data, setValue]); + return (
    {/*

    Assign Employee To Project

    */}
    Assign Employee To Project
    -
    - - {!isLoading && data && ( - <> - {data.length === 1 && ( -
    {data[0].name}
    - )} - - {/* If multiple organizations → show dropdown */} - {data.length > 1 && ( -
    - ( - - )} - /> - {errors.organizationId && ( - - {errors.organizationId.message} - - )} -
    - )} - +
    + ( + + )} + /> + {errors.organizationId && ( + {errors.organizationId.message} )} - {/*
    */} -
    diff --git a/src/components/Project/Team/Teams.jsx b/src/components/Project/Team/Teams.jsx index ff919a69..e91a5dbf 100644 --- a/src/components/Project/Team/Teams.jsx +++ b/src/components/Project/Team/Teams.jsx @@ -34,7 +34,7 @@ const Teams = () => { const [selectedEmployee, setSelectedEmployee] = useState(null); const [deleteEmployee, setDeleteEmplyee] = useState(null); const [activeEmployee, setActiveEmployee] = useState(false); - const { control, watch } = useForm({ + const { control, watch, setValue } = useForm({ defaultValues: { selectedService: "", searchTerm: "", @@ -136,6 +136,18 @@ const Teams = () => { return () => eventBus.off("employee", employeeHandler); }, [employeeHandler]); + useEffect(() => { + if (!servicesLoading && assignedServices?.length === 1) { + const serviceId = assignedServices[0].id; + + setValue("selectedService", serviceId, { + shouldDirty: true, + shouldValidate: true, + }); + } + }, [assignedServices, servicesLoading, setValue]); + + return ( <> {AssigTeam && ( @@ -162,37 +174,30 @@ const Teams = () => {
    - {!servicesLoading && assignedServices && ( - <> - {assignedServices.length === 1 && ( -
    {assignedServices[0].name}
    - )} - - {assignedServices.length > 1 && ( -
    - ( - - )} + {!servicesLoading && assignedServices?.length > 0 && ( +
    + ( + -
    - )} - + )} + /> +
    )} +
    { const inputRef = useRef(null); @@ -105,7 +106,7 @@ export const DateRangePicker1 = ({ const applyDefaultDates = () => { const today = new Date(); const past = new Date(); - past.setDate(today.getDate() - 6); + past.setDate(today.getDate() - pastDays); const format = (d) => flatpickr.formatDate(d, "d-m-Y"); const formattedStart = format(past); diff --git a/src/components/reports/Progress.jsx b/src/components/reports/Progress.jsx index 89d1dfca..3625ff19 100644 --- a/src/components/reports/Progress.jsx +++ b/src/components/reports/Progress.jsx @@ -8,7 +8,7 @@ const Progress = ({ total = 0, height = 100, width = 100, - completed =0, + completed = 0, }) => { const options = { chart: { @@ -24,16 +24,19 @@ const Progress = ({ value: { show: true, fontSize: "13px", - width:"12px", - textWrap:"wrap", + width: "12px", + textWrap: "wrap", color: color, fontWeight: 400, offsetY: 7, - formatter: () => `${formatFigure(completed,{notation:"compact"})} / ${formatFigure(total,{notation:"compact"})}`, + formatter: () => + `${formatFigure(completed, { + notation: "compact", + })} / ${formatFigure(total, { notation: "compact" })}`, + }, + style: { + textWrap: "wrap", }, - style:{ - textWrap:"wrap", - } }, }, }, @@ -54,7 +57,6 @@ const Progress = ({ }; export default Progress; - // const Progress = ({ // completed = 0, // inProgress = 0, diff --git a/src/components/reports/ReportsDonutCard.jsx b/src/components/reports/ReportsDonutCard.jsx index d922c4cc..a6d0dcdb 100644 --- a/src/components/reports/ReportsDonutCard.jsx +++ b/src/components/reports/ReportsDonutCard.jsx @@ -9,9 +9,11 @@ const ReportsDonutCard = ({ donutClass = "", footer = "Team members present on the site", chartColor, + legend1 = "Completed", + legend2 = "Pending", }) => { return ( -
    +

    {title}

    @@ -24,7 +26,7 @@ const ReportsDonutCard = ({ completed={value} total={total} /> - +
    @@ -51,7 +53,6 @@ export const ReportsCard = ({
    -
    @@ -62,5 +63,3 @@ export const ReportsCard = ({
    ); }; - - diff --git a/src/components/reports/ReportsLegend.jsx b/src/components/reports/ReportsLegend.jsx index cd2a533c..daea7b0a 100644 --- a/src/components/reports/ReportsLegend.jsx +++ b/src/components/reports/ReportsLegend.jsx @@ -1,19 +1,14 @@ -const ReportsLegend = () => { +const ReportsLegend = ({legend1, legend2}) => { return (
    - Completed + {legend1}
    - In Progress -
    - -
    - - Pending + {legend2}
    ); diff --git a/src/components/reports/report-dpr.jsx b/src/components/reports/report-dpr.jsx index 4ecc0073..adcfc8cf 100644 --- a/src/components/reports/report-dpr.jsx +++ b/src/components/reports/report-dpr.jsx @@ -4,6 +4,7 @@ import Progress from "./Progress"; import { formatUTCToLocalTime } from "../../utils/dateUtils"; import { localToUtc } from "../../utils/appUtils"; import ReportsDonutCard, { ReportsCard } from "./ReportsDonutCard"; +import { SpinnerLoader } from "../common/Loader"; const ReportDPR = ({ project, date }) => { const { data, isLoading, isError, error } = useProjectReportByProject( @@ -12,88 +13,117 @@ const ReportDPR = ({ project, date }) => { ); return ( <> -
    +
    Project Status Reported - Generated at{" "} {formatUTCToLocalTime(data?.date, true)}
    {/* */} diff --git a/src/pages/Home/SubscriptionPlans.jsx b/src/pages/Home/SubscriptionPlans.jsx index 59ef4a7e..6f62eba3 100644 --- a/src/pages/Home/SubscriptionPlans.jsx +++ b/src/pages/Home/SubscriptionPlans.jsx @@ -9,7 +9,8 @@ const SubscriptionPlans = () => { const [frequency, setFrequency] = useState(1); const { data, isLoading, isError, error } = useSubscription(frequency); const [loading, setLoading] = useState(false); - + const [isOpen, setIsOpen] = useState(true); + console.log(data); const frequencyLabel = (freq) => { switch (freq) { case 0: @@ -35,9 +36,8 @@ const SubscriptionPlans = () => {
    ) : ( - data.map((plan) => ( + data.map((plan, index) => (
    {/* Header */} @@ -102,24 +102,69 @@ const SubscriptionPlans = () => {
    Features
    -
      + +
      {plan.features?.modules && - Object.values(plan.features.modules).map((mod) => - mod && mod.name ? ( -
    • - {mod.enabled ? ( - - ) : ( - - )} - {mod.name} -
    • - ) : null - )} -
    + Object.entries(plan.features.modules) + .sort(([, a], [, b]) => Number(b.enabled) - Number(a.enabled)) + .map(([key, mod]) => { + + if (!mod || !mod.name) return null; + const isFirst = index === 0; + + return ( +
    +

    + +

    + +
    +
    + {mod.features?.length > 0 ? ( +
      + {mod.features.map((feat) => ( +
    • + + {feat.name} +
    • + ))} +
    + ) : ( +

    No additional features

    + )} +
    +
    +
    + + ); + })} +
    {/* Button */}
    @@ -138,6 +183,7 @@ const SubscriptionPlans = () => {
    + )) )}
    diff --git a/src/pages/authentication/MainLoginWithOTPPage.jsx b/src/pages/authentication/MainLoginWithOTPPage.jsx index 53b9fec7..872f39cf 100644 --- a/src/pages/authentication/MainLoginWithOTPPage.jsx +++ b/src/pages/authentication/MainLoginWithOTPPage.jsx @@ -1,5 +1,5 @@ -import React from 'react' -import LoginWithOtp from './LoginWithOtp' +import React from "react"; +import LoginWithOtp from "./LoginWithOtp"; const MainLoginWithOTPPage = () => { return ( @@ -8,7 +8,7 @@ const MainLoginWithOTPPage = () => {
    Login image {
    - ) -} + ); +}; -export default MainLoginWithOTPPage \ No newline at end of file +export default MainLoginWithOTPPage; diff --git a/src/pages/authentication/MainResetPasswordPage.jsx b/src/pages/authentication/MainResetPasswordPage.jsx index 36fd71e6..98d2bba9 100644 --- a/src/pages/authentication/MainResetPasswordPage.jsx +++ b/src/pages/authentication/MainResetPasswordPage.jsx @@ -1,14 +1,14 @@ -import React from 'react' -import ResetPasswordPage from './ResetPassword' +import React from "react"; +import ResetPasswordPage from "./ResetPassword"; const MainResetPasswordPage = () => { return ( - <> + <>
    Login image {
    - ) -} + ); +}; -export default MainResetPasswordPage \ No newline at end of file +export default MainResetPasswordPage;