From eea7252b9672c8dea4a51784c7c9d0287956140d Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Wed, 17 Sep 2025 16:10:49 +0530 Subject: [PATCH 1/7] Changes in UI of Dashboard getplans. --- src/pages/Home/SubscriptionPlans.jsx | 220 +++++++-------------------- 1 file changed, 59 insertions(+), 161 deletions(-) diff --git a/src/pages/Home/SubscriptionPlans.jsx b/src/pages/Home/SubscriptionPlans.jsx index 0d44472c..7c06a751 100644 --- a/src/pages/Home/SubscriptionPlans.jsx +++ b/src/pages/Home/SubscriptionPlans.jsx @@ -1,113 +1,3 @@ -// // src/components/SubscriptionPlans.jsx -// import React, { useState, useEffect } from "react"; -// import axios from "axios"; - -// const SubscriptionPlans = () => { -// const [plans, setPlans] = useState([]); -// const [frequency, setFrequency] = useState(1); // 1=Monthly, 2=Quarterly, 3=Half-Yearly, 4=Yearly -// const [loading, setLoading] = useState(false); - -// useEffect(() => { -// const fetchPlans = async () => { -// try { -// setLoading(true); -// const res = await axios.get( -// `/api/market/list/subscription-plan?frequency=${frequency}` -// ); -// setPlans(res.data?.data || []); -// } catch (err) { -// console.error("Error fetching plans:", err); -// } finally { -// setLoading(false); -// } -// }; - -// fetchPlans(); -// }, [frequency]); - -// return ( -//
-// {/* Frequency Switcher */} -//
-//
-// {["Monthly", "Quarterly", "Half-Yearly", "Yearly"].map((label, idx) => ( -// -// ))} -//
-//
- -// {/* Cards */} -//
-// {loading ? ( -//
Loading...
-// ) : plans.length === 0 ? ( -//
No plans found
-// ) : ( -// plans.map((plan) => ( -//
-//
-//
-//

{plan.planName}

-//

{plan.description}

-//
-// -// {plan.currency?.symbol} -// {plan.price} -// -// /mo -//
-//
-// Max Users: {plan.maxUser} | Storage: {plan.maxStorage} MB -//
-//
- -//
-//
    -// {plan.features?.modules && -// Object.values(plan.features.modules).map((mod) => ( -//
  • -// -// {mod.name}{" "} -// {mod.enabled ? ( -// Enabled -// ) : ( -// Disabled -// )} -//
  • -// ))} -//
  • -// -// Support:{" "} -// {plan.features?.supports?.prioritySupport -// ? "Priority" -// : plan.features?.supports?.phoneSupport -// ? "Phone & Email" -// : "Email Only"} -//
  • -//
-//
- -//
-// -//
-//
-//
-// )) -// )} -//
-//
-// ); -// }; - -// export default SubscriptionPlans; - import React, { useState, useEffect } from "react"; import axios from "axios"; @@ -120,11 +10,10 @@ const SubscriptionPlans = () => { const fetchPlans = async () => { try { setLoading(true); - const res = await axios.get(`http://localhost:5032/api/market/list/subscription-plan?frequency=${frequency}`, { - headers: { - "Content-Type": "application/json" - } - }); + const res = await axios.get( + `http://localhost:5032/api/market/list/subscription-plan?frequency=${frequency}`, + { headers: { "Content-Type": "application/json" } } + ); setPlans(res.data?.data || []); } catch (err) { console.error("Error fetching plans:", err); @@ -155,7 +44,7 @@ const SubscriptionPlans = () => { key={idx} type="button" className={`btn btn-${frequency === idx ? "primary" : "outline-secondary"}`} - onClick={() => setFrequency(idx)} // use idx directly (0,1,2,3) + onClick={() => setFrequency(idx)} > {label} @@ -163,7 +52,6 @@ const SubscriptionPlans = () => { - {/* Cards */}
{loading ? ( @@ -173,54 +61,65 @@ const SubscriptionPlans = () => { ) : ( plans.map((plan) => (
-
-
-

{plan.planName}

-

{plan.description}

-
- - {plan.currency?.symbol}{plan.price} - - /{frequencyLabel(frequency)} -
-
- Max Users: {plan.maxUser} | Storage: {plan.maxStorage} MB +
+ {/* Header */} +
+ +
+

+ {plan.planName} +

+

{plan.description}

-
-
    - {plan.features?.modules && - Object.values(plan.features.modules).map((modGroup) => - Object.values(modGroup).map((mod) => - mod && mod.name ? ( -
  • - - {mod.name}{" "} - {mod.enabled ? ( - Enabled - ) : ( - Disabled - )} -
  • - ) : null - ) - )} - -
  • - - Support:{" "} - {plan.features?.supports?.prioritySupport - ? "Priority" - : plan.features?.supports?.phoneSupport - ? "Phone & Email" - : "Email Only"} -
  • -
+ {/* Price */} +
+

+ {plan.currency?.symbol} {plan.price} +

-
- + {/* Storage & Trial */} +
+
+ + Storage {plan.maxStorage} MB +
+
+ + Trial Days {plan.trialDays} +
+
+ + {/* Features */} +
+ Features +
+
    + {plan.features?.modules && + Object.values(plan.features.modules).map((mod) => + mod && mod.name ? ( +
  • + {mod.enabled ? ( + + ) : ( + + )} + {mod.name} +
  • + ) : null + )} +
+ + {/* Button */} +
+
@@ -232,4 +131,3 @@ const SubscriptionPlans = () => { }; export default SubscriptionPlans; - From df9107f0d830a51dcdb5f4fc5a32904b368ab905 Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Wed, 17 Sep 2025 16:49:52 +0530 Subject: [PATCH 2/7] Changes in UI of Subscription-plan. --- src/pages/Home/SubscriptionPlans.jsx | 45 +++++++++++++++------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/src/pages/Home/SubscriptionPlans.jsx b/src/pages/Home/SubscriptionPlans.jsx index 7c06a751..6799efb6 100644 --- a/src/pages/Home/SubscriptionPlans.jsx +++ b/src/pages/Home/SubscriptionPlans.jsx @@ -1,5 +1,6 @@ import React, { useState, useEffect } from "react"; import axios from "axios"; +import { Link } from "react-router-dom"; const SubscriptionPlans = () => { const [plans, setPlans] = useState([]); @@ -26,10 +27,10 @@ const SubscriptionPlans = () => { const frequencyLabel = (freq) => { switch (freq) { - case 0: return "mo"; + case 0: return "1mo"; case 1: return "3mo"; case 2: return "6mo"; - case 3: return "yr"; + case 3: return "1yr"; default: return "mo"; } }; @@ -61,28 +62,25 @@ const SubscriptionPlans = () => { ) : ( plans.map((plan) => (
-
+
{/* Header */} -
- -
-

- {plan.planName} -

-

{plan.description}

-
+
+ +

{plan.planName}

+

{plan.description}

{/* Price */} -
-

+
+

{plan.currency?.symbol} {plan.price} + / {frequencyLabel(frequency)}

{/* Storage & Trial */} -
-
+
+
Storage {plan.maxStorage} MB
@@ -92,17 +90,18 @@ const SubscriptionPlans = () => {
+ {/* Features */} -
+
Features
-
    +
      {plan.features?.modules && Object.values(plan.features.modules).map((mod) => mod && mod.name ? (
    • {mod.enabled ? ( @@ -117,15 +116,19 @@ const SubscriptionPlans = () => { {/* Button */}
      - + + Enquiry +

)) )}
+
); }; From 1c0e8655c4ba177083f515ab0fef0f905bf55e05 Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Wed, 17 Sep 2025 17:09:56 +0530 Subject: [PATCH 3/7] Changes in Login-form hide/unhide button add secondary. --- src/pages/authentication/LoginPage.jsx | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/pages/authentication/LoginPage.jsx b/src/pages/authentication/LoginPage.jsx index db99e6a1..3e331376 100644 --- a/src/pages/authentication/LoginPage.jsx +++ b/src/pages/authentication/LoginPage.jsx @@ -136,7 +136,7 @@ const LoginPage = () => { )}
*/} -
+
@@ -146,7 +146,8 @@ const LoginPage = () => { type={hidepass ? "password" : "text"} autoComplete="new-password" id="password" - className="form-control form-control-xl shadow-none" + className={`form-control form-control-xl shadow-none ${errors.password ? "is-invalid" : "" + }`} name="password" {...register("password")} placeholder="••••••••••••" @@ -155,7 +156,7 @@ const LoginPage = () => {
+ + {/* ✅ Error message */} + {errors.password && ( +
+ {errors.password.message} +
+ )}
+ {/* Remember Me + Forgot Password */}
From fd36298543cc3fbc04ea5698b7b21a5403958068 Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Thu, 18 Sep 2025 12:07:46 +0530 Subject: [PATCH 4/7] Changes in UI of Landing Page subscription and add skeleton --- src/pages/Home/PlanCardSkeleton.jsx | 44 ++++++++++++++++++++++++++++ src/pages/Home/SubscriptionPlans.jsx | 23 +++++++++------ 2 files changed, 58 insertions(+), 9 deletions(-) create mode 100644 src/pages/Home/PlanCardSkeleton.jsx diff --git a/src/pages/Home/PlanCardSkeleton.jsx b/src/pages/Home/PlanCardSkeleton.jsx new file mode 100644 index 00000000..837ea686 --- /dev/null +++ b/src/pages/Home/PlanCardSkeleton.jsx @@ -0,0 +1,44 @@ +import React from "react"; + +const SubscriptionPlanSkeleton = () => { + return ( +
+
+ {/* Header */} +
+
+
+
+
+ + {/* Price */} +
+
+
+ + {/* Storage & Trial */} +
+
+
+
+ + {/* Features */} +
+ Features +
+
    + {[1, 2, 3].map((i) => ( +
  • +
    +
  • + ))} +
+ + {/* Button */} +
+
+
+ ); +}; + +export default SubscriptionPlanSkeleton; diff --git a/src/pages/Home/SubscriptionPlans.jsx b/src/pages/Home/SubscriptionPlans.jsx index 6799efb6..24be62f9 100644 --- a/src/pages/Home/SubscriptionPlans.jsx +++ b/src/pages/Home/SubscriptionPlans.jsx @@ -1,6 +1,7 @@ import React, { useState, useEffect } from "react"; import axios from "axios"; import { Link } from "react-router-dom"; +import PlanCardSkeleton from "./PlanCardSkeleton"; const SubscriptionPlans = () => { const [plans, setPlans] = useState([]); @@ -27,10 +28,10 @@ const SubscriptionPlans = () => { const frequencyLabel = (freq) => { switch (freq) { - case 0: return "1mo"; - case 1: return "3mo"; - case 2: return "6mo"; - case 3: return "1yr"; + case 0: return "1 mo"; + case 1: return "3 mo"; + case 2: return "6 mo"; + case 3: return "1 yr"; default: return "mo"; } }; @@ -54,15 +55,20 @@ const SubscriptionPlans = () => {
{/* Cards */} -
+
{loading ? ( -
Loading...
+ // Show 3 skeletons + <> + + + + ) : plans.length === 0 ? (
No plans found
) : ( plans.map((plan) => (
-
+
{/* Header */}
@@ -90,7 +96,6 @@ const SubscriptionPlans = () => {
- {/* Features */}
Features @@ -120,7 +125,7 @@ const SubscriptionPlans = () => { to="/auth/reqest/demo" className="btn btn-outline-primary w-100 fw-bold" > - Enquiry + Request a Demo
From a27b8571b555fe82497fe283127f1fb82ed7192e Mon Sep 17 00:00:00 2001 From: Vikas Nale Date: Thu, 18 Sep 2025 12:35:04 +0530 Subject: [PATCH 5/7] cosmatic changes --- src/pages/Home/LandingPage.css | 3 +- src/pages/Home/LandingPage.jsx | 95 ++++++++++++++++++++-------------- 2 files changed, 59 insertions(+), 39 deletions(-) diff --git a/src/pages/Home/LandingPage.css b/src/pages/Home/LandingPage.css index 318eadd5..35b05e9e 100644 --- a/src/pages/Home/LandingPage.css +++ b/src/pages/Home/LandingPage.css @@ -299,7 +299,7 @@ nav.layout-navbar.navbar-active::after { color: #d3d4dc; } .landing-footer .footer-bottom { - background-color: #282c3e; + background-color: #f44336; } .landing-footer .footer-link { transition: all 0.2s ease-in-out; @@ -312,6 +312,7 @@ nav.layout-navbar.navbar-active::after { padding-bottom: 1.3rem; border-top-left-radius: 1.75rem; border-top-right-radius: 1.75rem; + background-color: #f44336; } @media (max-width: 767.98px) { .landing-footer .footer-top { diff --git a/src/pages/Home/LandingPage.jsx b/src/pages/Home/LandingPage.jsx index 6d5a44ca..35b01202 100644 --- a/src/pages/Home/LandingPage.jsx +++ b/src/pages/Home/LandingPage.jsx @@ -591,14 +591,14 @@ const LandingPage = () => { FAQ

- Frequently asked - - questions - + Questions + {/* laptop charging + /> */}

@@ -816,19 +816,26 @@ const LandingPage = () => {

+
+ hero elements +
{" "}

- Let's work - laptop charging + /> */} - together + Together

Any question or remark? just write us a message @@ -873,15 +880,15 @@ const LandingPage = () => {

-

+

Ready to Get Started? -
-
- Start your project with a 14-day free trial
- +
+ Start your project with a free trial +
+ {/*
Get Started - {" "} + {" "} */} {
-
- hero elements -
@@ -1056,7 +1056,10 @@ const LandingPage = () => { {/* Footer: Start */} From 9311f41f5601c751e3edfde7d260a6634915a68d Mon Sep 17 00:00:00 2001 From: pramod mahajan Date: Thu, 18 Sep 2025 12:38:39 +0530 Subject: [PATCH 6/7] fixed high level changes --- src/components/Activities/InfraPlanning.jsx | 76 ++++++------ src/hooks/useHasUserPermission.js | 18 ++- src/hooks/useProjectAccess.js | 26 ++++ src/hooks/useProjects.js | 3 +- src/pages/Directory/DirectoryPage.jsx | 1 + src/pages/project/ProjectDetails.jsx | 125 ++++++-------------- 6 files changed, 123 insertions(+), 126 deletions(-) create mode 100644 src/hooks/useProjectAccess.js diff --git a/src/components/Activities/InfraPlanning.jsx b/src/components/Activities/InfraPlanning.jsx index 664c0613..dc237c63 100644 --- a/src/components/Activities/InfraPlanning.jsx +++ b/src/components/Activities/InfraPlanning.jsx @@ -19,54 +19,60 @@ import { useSelectedProject } from "../../slices/apiDataManager"; import Loader from "../common/Loader"; -const InfraPlanning = () => -{ - const {profile: LoggedUser, refetch : fetchData} = useProfile() - const dispatch = useDispatch() - // const selectedProject = useSelector((store)=>store.localVariables.projectId) + + +const InfraPlanning = () => { + const { profile: LoggedUser, refetch: fetchData } = useProfile(); + const dispatch = useDispatch(); const selectedProject = useSelectedProject(); - const {projectInfra, isLoading, error} = useProjectInfra( selectedProject ) + const { projectInfra, isLoading, isError, error, isFetched } = useProjectInfra(selectedProject); - - const ManageInfra = useHasUserPermission( MANAGE_PROJECT_INFRA ) - const ApprovedTaskRights = useHasUserPermission(APPROVE_TASK) - const ReportTaskRights = useHasUserPermission(ASSIGN_REPORT_TASK) - const reloadedData = useSelector( ( store ) => store.localVariables.reload ) + const canManageInfra = useHasUserPermission(MANAGE_PROJECT_INFRA); + const canApproveTask = useHasUserPermission(APPROVE_TASK); + const canReportTask = useHasUserPermission(ASSIGN_REPORT_TASK); - - // useEffect( () => - // { - // if (reloadedData) - // { - // refetch() - // dispatch( refreshData( false ) ) - // } + const reloadedData = useSelector((store) => store.localVariables.reload); - // },[reloadedData]) + const hasAccess = canManageInfra || canApproveTask || canReportTask; + + if (isError) { + return
{error?.response?.data?.message || error?.message}
; + } + + if (!hasAccess && !isLoading) { + return ( +
+ +

Access Denied: You don't have permission to perform this action.

+
+ ); + } + + if (isLoading) { + return ; + } + + if (isFetched && (!projectInfra || projectInfra.length === 0)) { + return ( +
+

No Result Found

+
+ ); + } return (
-
-
- {(ApprovedTaskRights || ReportTaskRights) ? ( -
-
- {isLoading && ( )} - {( !isLoading && projectInfra?.length === 0 ) && (

No Result Found

)} - {(!isLoading && projectInfra?.length > 0) && ()} +
+
+
+
- ) : ( -
- -

Access Denied: You don't have permission to perform this action. !

-
- )}
-
); }; export default InfraPlanning; + diff --git a/src/hooks/useHasUserPermission.js b/src/hooks/useHasUserPermission.js index cefeea6c..b4ec3e52 100644 --- a/src/hooks/useHasUserPermission.js +++ b/src/hooks/useHasUserPermission.js @@ -1,16 +1,26 @@ - import { useSelectedProject } from "../slices/apiDataManager"; import { useAllProjectLevelPermissions, useProfile } from "./useProfile"; export const useHasUserPermission = (permission) => { const selectedProject = useSelectedProject(); const { profile } = useProfile(); - const { data: projectPermissions = [], isLoading, isError } = useAllProjectLevelPermissions(selectedProject); + const { + data: projectPermissions = [], + isLoading, + isError, + } = useAllProjectLevelPermissions(selectedProject); if (isLoading || !permission) return false; const globalPerms = profile?.featurePermissions ?? []; const projectPerms = projectPermissions ?? []; - - return globalPerms.includes(permission) || projectPerms.includes(permission); + if (selectedProject) { + if (projectPerms.length === 0) { + return projectPerms.includes(permission); + } else { + return projectPerms.includes(permission); + } + } else { + return globalPerms.includes(permission); + } }; diff --git a/src/hooks/useProjectAccess.js b/src/hooks/useProjectAccess.js new file mode 100644 index 00000000..a3ff27ac --- /dev/null +++ b/src/hooks/useProjectAccess.js @@ -0,0 +1,26 @@ +import { useNavigate } from "react-router-dom"; +import { useEffect } from "react"; +import { useHasUserPermission } from "./useHasUserPermission"; +import { useAllProjectLevelPermissions } from "./useProfile"; +import { VIEW_PROJECTS } from "../utils/constants"; +import showToast from "../services/toastService"; + +export const useProjectAccess = (projectId) => { + const { data: projectPermissions, isLoading, isFetched } = + useAllProjectLevelPermissions(projectId); + + const canView = useHasUserPermission(VIEW_PROJECTS); + const navigate = useNavigate(); + + useEffect(() => { + if (projectId && isFetched && !isLoading && !canView) { + showToast("You don't have permission to view project details", "warning"); + navigate("/projects"); + } + }, [projectId, isFetched, isLoading, canView, navigate]); + + return { + canView, + loading: isLoading || !isFetched, + }; +}; diff --git a/src/hooks/useProjects.js b/src/hooks/useProjects.js index a9815fc2..ee399b19 100644 --- a/src/hooks/useProjects.js +++ b/src/hooks/useProjects.js @@ -177,6 +177,7 @@ export const useProjectInfra = (projectId) => { data: projectInfra, isLoading, error, + isFetched } = useQuery({ queryKey: ["ProjectInfra", projectId], queryFn: async () => { @@ -190,7 +191,7 @@ export const useProjectInfra = (projectId) => { }, }); - return { projectInfra, isLoading, error }; + return { projectInfra, isLoading, error, isFetched }; }; export const useProjectTasks = (workAreaId, IsExpandedArea = false) => { diff --git a/src/pages/Directory/DirectoryPage.jsx b/src/pages/Directory/DirectoryPage.jsx index 40dc51e3..8e17b802 100644 --- a/src/pages/Directory/DirectoryPage.jsx +++ b/src/pages/Directory/DirectoryPage.jsx @@ -21,6 +21,7 @@ import ContactProfile from "../../components/Directory/ContactProfile"; import GlobalModel from "../../components/common/GlobalModel"; import { exportToCSV } from "../../utils/exportUtils"; import ConfirmModal from "../../components/common/ConfirmModal"; +import { useSelectedProject } from "../../slices/apiDataManager"; const NotesPage = lazy(() => import("./NotesPage")); const ContactsPage = lazy(() => import("./ContactsPage")); diff --git a/src/pages/project/ProjectDetails.jsx b/src/pages/project/ProjectDetails.jsx index f7ccabbe..b57f9362 100644 --- a/src/pages/project/ProjectDetails.jsx +++ b/src/pages/project/ProjectDetails.jsx @@ -1,5 +1,6 @@ -import { useSelector, useDispatch } from "react-redux"; // Import useSelector import React, { useState, useEffect, useCallback } from "react"; +import { useDispatch } from "react-redux"; +import { useNavigate } from "react-router-dom"; import ProjectOverview from "../../components/Project/ProjectOverview"; import AboutProject from "../../components/Project/AboutProject"; @@ -9,63 +10,43 @@ import ProjectInfra from "../../components/Project/ProjectInfra"; import Loader from "../../components/common/Loader"; import WorkPlan from "../../components/Project/WorkPlan"; import Breadcrumb from "../../components/common/Breadcrumb"; -import { - cacheData, - clearCacheKey, - getCachedData, - useSelectedProject, -} from "../../slices/apiDataManager"; -import "./ProjectDetails.css"; -import { useProjectDetails } from "../../hooks/useProjects"; +import { useSelectedProject } from "../../slices/apiDataManager"; +import { useProjectDetails, useProjectName } from "../../hooks/useProjects"; import { ComingSoonPage } from "../Misc/ComingSoonPage"; import eventBus from "../../services/eventBus"; import ProjectProgressChart from "../../components/Dashboard/ProjectProgressChart"; -import { useProjectName } from "../../hooks/useProjects"; import AttendanceOverview from "../../components/Dashboard/AttendanceChart"; import { setProjectId } from "../../slices/localVariablesSlice"; -import ProjectDocument from "../../components/Project/ProjectDocuments"; import ProjectDocuments from "../../components/Project/ProjectDocuments"; import ProjectSetting from "../../components/Project/ProjectSetting"; import DirectoryPage from "../Directory/DirectoryPage"; -import { useHasAnyPermission } from "../../hooks/useExpense"; -import { VIEW_PROJECTS } from "../../utils/constants"; -import { useNavigate, useRoutes } from "react-router-dom"; -import { useHasUserPermission } from "../../hooks/useHasUserPermission"; +import { useProjectAccess } from "../../hooks/useProjectAccess"; // ✅ new + +import "./ProjectDetails.css"; const ProjectDetails = () => { const projectId = useSelectedProject(); - const CanViewProject = useHasUserPermission(VIEW_PROJECTS); - const navigate = useNavigate(); - - const { projectNames, fetchData } = useProjectName(); const dispatch = useDispatch(); + const { projectNames } = useProjectName(); + const { projects_Details, loading: projectLoading, refetch } = + useProjectDetails(projectId); + + const { canView, loading: permsLoading } = useProjectAccess(projectId); + useEffect(() => { - if (!CanViewProject) { - navigate("/dashboard"); + if (!projectId && projectNames.length > 0) { + dispatch(setProjectId(projectNames[0].id)); } - if (projectId == null) { - dispatch(setProjectId(projectNames[0]?.id)); - } - }, [projectNames]); + }, [projectId, projectNames, dispatch]); - const { - projects_Details, - loading: projectLoading, - error: projectError, - refetch, - } = useProjectDetails(projectId); - - const [activePill, setActivePill] = useState(() => { - return localStorage.getItem("lastActiveProjectTab") || "profile"; - }); + const [activePill, setActivePill] = useState( + localStorage.getItem("lastActiveProjectTab") || "profile" + ); const handler = useCallback( (msg) => { - if ( - msg.keyword === "Update_Project" && - projects_Details?.id === msg.response.id - ) { + if (msg.keyword === "Update_Project" && projects_Details?.id === msg.response.id) { refetch(); } }, @@ -79,69 +60,42 @@ const ProjectDetails = () => { const handlePillClick = (pillKey) => { setActivePill(pillKey); - localStorage.setItem("lastActiveProjectTab", pillKey); + localStorage.setItem("lastActiveProjectTab", pillKey); }; - const renderContent = () => { - if (projectLoading || !projects_Details) return ; + if (projectLoading || permsLoading || !projects_Details) { + return ; + } + const renderContent = () => { switch (activePill) { case "profile": - return ( - <> -
-
- - -
-
- -
- {" "} - -
-
-
- - ); - - case "teams": return (
-
- +
+ + +
+
+ +
+ +
); - + case "teams": + return ; case "infra": return ; - case "workplan": return ; - case "directory": - return ( -
- -
- ); + return ; case "documents": - return ( -
- -
- ); + return ; case "setting": - return ( -
- -
- ); - + return ; default: return ; } @@ -156,7 +110,6 @@ const ProjectDetails = () => { { label: projects_Details?.name || "Project", link: null }, ]} /> -
From b2c68824dd6627fc699fd2c98337677223711397 Mon Sep 17 00:00:00 2001 From: pramod mahajan Date: Thu, 18 Sep 2025 12:57:37 +0530 Subject: [PATCH 7/7] fixed refresh existen permission --- src/components/Project/ProjectPermission.jsx | 31 +++++++++++++------- src/hooks/useProjects.js | 2 +- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/components/Project/ProjectPermission.jsx b/src/components/Project/ProjectPermission.jsx index 471e283d..fa6bf1d2 100644 --- a/src/components/Project/ProjectPermission.jsx +++ b/src/components/Project/ProjectPermission.jsx @@ -28,6 +28,7 @@ const ProjectPermission = () => { handleSubmit, reset, control, + setValue, formState: { errors, isDirty }, } = useForm({ resolver: zodResolver(ProjectPermissionSchema), @@ -45,18 +46,26 @@ const ProjectPermission = () => { ); useEffect(() => { - if (!selectedEmployee) return; + if (!selectedEmployee) return; - const enabledPerms = - selectedEmpPermissions?.permissions - ?.filter((perm) => perm.isEnabled) - ?.map((perm) => perm.id) || []; + const enabledPerms = + selectedEmpPermissions?.permissions + ?.filter((perm) => perm.isEnabled) + ?.map((perm) => perm.id) || []; - reset((prev) => ({ - ...prev, - selectedPermissions: enabledPerms, - })); - }, [selectedEmpPermissions, reset, selectedEmployee]); + setValue("selectedPermissions", enabledPerms, { shouldValidate: true }); +}, [selectedEmpPermissions, setValue, selectedEmployee]); + +const selectedPermissions = watch("selectedPermissions") || []; + +const existingEnabledIds = + selectedEmpPermissions?.permissions + ?.filter((p) => p.isEnabled) + ?.map((p) => p.id) || []; + +const hasChanges = + selectedPermissions.length !== existingEnabledIds.length || + selectedPermissions.some((id) => !existingEnabledIds.includes(id)); const { mutate: updatePermission, isPending } = useUpdateProjectLevelEmployeePermission(); @@ -145,7 +154,7 @@ const ProjectPermission = () => {
- {isDirty && ( + {hasChanges && (