Merge pull request 'Handled Global and Project level permissions' (#403) from hotchanges_projectPermission into Refactor_Directory
Reviewed-on: #403 Merged
This commit is contained in:
commit
7ef10e3e5b
@ -7,6 +7,10 @@ import {
|
|||||||
DIRECTORY_USER,
|
DIRECTORY_USER,
|
||||||
MANAGE_PROJECT_INFRA,
|
MANAGE_PROJECT_INFRA,
|
||||||
MANAGE_TASK,
|
MANAGE_TASK,
|
||||||
|
MANAGE_TEAM,
|
||||||
|
MODIFY_DOCUMENT,
|
||||||
|
UPLOAD_DOCUMENT,
|
||||||
|
VIEW_DOCUMENT,
|
||||||
VIEW_PROJECT_INFRA,
|
VIEW_PROJECT_INFRA,
|
||||||
} from "../../utils/constants";
|
} from "../../utils/constants";
|
||||||
|
|
||||||
@ -17,6 +21,10 @@ const ProjectNav = ({ onPillClick, activePill }) => {
|
|||||||
const DirAdmin = useHasUserPermission(DIRECTORY_ADMIN);
|
const DirAdmin = useHasUserPermission(DIRECTORY_ADMIN);
|
||||||
const DireManager = useHasUserPermission(DIRECTORY_MANAGER);
|
const DireManager = useHasUserPermission(DIRECTORY_MANAGER);
|
||||||
const DirUser = useHasUserPermission(DIRECTORY_USER);
|
const DirUser = useHasUserPermission(DIRECTORY_USER);
|
||||||
|
const isManageTeam = useHasUserPermission(MANAGE_TEAM)
|
||||||
|
const isViewDocuments = hasUserPermission(VIEW_DOCUMENT);
|
||||||
|
const isUploadDocument = useHasUserPermission(UPLOAD_DOCUMENT)
|
||||||
|
const isModifyDocument = useHasUserPermission(MODIFY_DOCUMENT)
|
||||||
|
|
||||||
const ProjectTab = [
|
const ProjectTab = [
|
||||||
{ key: "profile", icon: "bx bx-user", label: "Profile" },
|
{ key: "profile", icon: "bx bx-user", label: "Profile" },
|
||||||
@ -33,8 +41,8 @@ const ProjectNav = ({ onPillClick, activePill }) => {
|
|||||||
label: "Directory",
|
label: "Directory",
|
||||||
hidden: !(DirAdmin || DireManager || DirUser),
|
hidden: !(DirAdmin || DireManager || DirUser),
|
||||||
},
|
},
|
||||||
{ key: "documents", icon: "bx bx-folder-open", label: "Documents" },
|
{ key: "documents", icon: "bx bx-folder-open", label: "Documents",hidden:!(isViewDocuments || isModifyDocument || isUploadDocument) },
|
||||||
{ key: "setting", icon: "bx bxs-cog", label: "Setting" },
|
{ key: "setting", icon: "bx bxs-cog", label: "Setting",hidden:!isManageTeam },
|
||||||
];
|
];
|
||||||
return (
|
return (
|
||||||
<div className="nav-align-top">
|
<div className="nav-align-top">
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect } from "react";
|
import React, { useCallback, useEffect } from "react";
|
||||||
import {
|
import {
|
||||||
useProjectLevelEmployeePermission,
|
useProjectLevelEmployeePermission,
|
||||||
useProjectLevelModules,
|
useProjectLevelModules,
|
||||||
@ -27,7 +27,7 @@ const ProjectPermission = () => {
|
|||||||
watch,
|
watch,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
reset,
|
reset,
|
||||||
formState: { errors },
|
formState: { errors, isDirty },
|
||||||
} = useForm({
|
} = useForm({
|
||||||
resolver: zodResolver(ProjectPermissionSchema),
|
resolver: zodResolver(ProjectPermissionSchema),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
@ -43,82 +43,82 @@ const ProjectPermission = () => {
|
|||||||
selectedProject
|
selectedProject
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!selectedEmployee) return;
|
if (!selectedEmployee) return;
|
||||||
|
|
||||||
const enabledPerms =
|
const enabledPerms =
|
||||||
selectedEmpPermissions?.permissions
|
selectedEmpPermissions?.permissions
|
||||||
?.filter((perm) => perm.isEnabled)
|
?.filter((perm) => perm.isEnabled)
|
||||||
?.map((perm) => perm.id) || [];
|
?.map((perm) => perm.id) || [];
|
||||||
|
|
||||||
reset((prev) => ({
|
|
||||||
...prev,
|
|
||||||
selectedPermissions: enabledPerms,
|
|
||||||
}));
|
|
||||||
}, [selectedEmpPermissions, reset, selectedEmployee]);
|
|
||||||
|
|
||||||
|
reset((prev) => ({
|
||||||
|
...prev,
|
||||||
|
selectedPermissions: enabledPerms,
|
||||||
|
}));
|
||||||
|
}, [selectedEmpPermissions, reset, selectedEmployee]);
|
||||||
|
|
||||||
const { mutate: updatePermission, isPending } =
|
const { mutate: updatePermission, isPending } =
|
||||||
useUpdateProjectLevelEmployeePermission();
|
useUpdateProjectLevelEmployeePermission();
|
||||||
|
|
||||||
const onSubmit = (formData) => {
|
const onSubmit = (formData) => {
|
||||||
if (!formData.employeeId) {
|
if (!formData.employeeId) {
|
||||||
showToast("Please select an employee", "warn");
|
showToast("Please select an employee", "warn");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const existingPermissions = selectedEmpPermissions?.permissions || [];
|
const existingPermissions = selectedEmpPermissions?.permissions || [];
|
||||||
const existingEnabledIds = existingPermissions
|
const existingEnabledIds = existingPermissions
|
||||||
.filter((p) => p.isEnabled)
|
.filter((p) => p.isEnabled)
|
||||||
.map((p) => p.id);
|
.map((p) => p.id);
|
||||||
|
|
||||||
const newSelectedIds = formData.selectedPermissions || [];
|
const newSelectedIds = formData.selectedPermissions || [];
|
||||||
|
|
||||||
const removed = existingEnabledIds
|
const removed = existingEnabledIds
|
||||||
.filter((id) => !newSelectedIds.includes(id))
|
.filter((id) => !newSelectedIds.includes(id))
|
||||||
.map((id) => ({ id, isEnabled: false }));
|
.map((id) => ({ id, isEnabled: false }));
|
||||||
|
|
||||||
const added = newSelectedIds
|
const added = newSelectedIds
|
||||||
.filter((id) => !existingEnabledIds.includes(id))
|
.filter((id) => !existingEnabledIds.includes(id))
|
||||||
.map((id) => ({ id, isEnabled: true }));
|
.map((id) => ({ id, isEnabled: true }));
|
||||||
|
|
||||||
const payloadPermissions = [...removed, ...added];
|
const payloadPermissions = [...removed, ...added];
|
||||||
|
|
||||||
if (payloadPermissions.length === 0) {
|
if (payloadPermissions.length === 0) {
|
||||||
showToast("No changes detected", "info");
|
showToast("No changes detected", "info");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
employeeId: formData.employeeId,
|
employeeId: formData.employeeId,
|
||||||
projectId: selectedProject,
|
projectId: selectedProject,
|
||||||
permission: payloadPermissions,
|
permission: payloadPermissions,
|
||||||
|
};
|
||||||
|
|
||||||
|
updatePermission(payload);
|
||||||
};
|
};
|
||||||
|
|
||||||
updatePermission(payload);
|
const useOnClick = useCallback((event) => {}, []);
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="row px-2 py-1">
|
<div className="w-100 p py-1 ">
|
||||||
<form className="row" onSubmit={handleSubmit(onSubmit)}>
|
<form className="row" onSubmit={handleSubmit(onSubmit)}>
|
||||||
{/* Employee Dropdown */}
|
<div className="d-flex justify-content-between align-items-end gap-2 mb-3">
|
||||||
<div className="d-flex align-items-end gap-2">
|
<div className="text-start d-flex align-items-center gap-2">
|
||||||
<div className="text-start">
|
<div className="d-block"><label className="form-label">Select Employee</label></div>
|
||||||
<label className="form-label">Select Employee</label>
|
<div className="d-block"> <select
|
||||||
<select
|
|
||||||
className="form-select form-select-sm"
|
className="form-select form-select-sm"
|
||||||
{...register("employeeId")}
|
{...register("employeeId")}
|
||||||
disabled={isPending}
|
disabled={isPending}
|
||||||
|
dd
|
||||||
>
|
>
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<option value="">Loading...</option>
|
<option value="">Loading...</option>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<option value="">-- Select Employee --</option>
|
<option value="">-- Select Employee --</option>
|
||||||
{[...employees]?.sort((a, b) =>
|
{[...employees]
|
||||||
`${a.firstName} ${a.firstName}`?.localeCompare(
|
?.sort((a, b) =>
|
||||||
`${b.firstName} ${b.lastName}`
|
`${a?.firstName} ${a?.firstName}`?.localeCompare(
|
||||||
|
`${b?.firstName} ${b?.lastName}`
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
?.map((emp) => (
|
?.map((emp) => (
|
||||||
@ -128,7 +128,7 @@ useEffect(() => {
|
|||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</select>
|
</select></div>
|
||||||
|
|
||||||
{errors.employeeId && (
|
{errors.employeeId && (
|
||||||
<div className="text-danger small">
|
<div className="text-danger small">
|
||||||
@ -136,42 +136,48 @@ useEffect(() => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<button
|
{isDirty && (
|
||||||
className="btn btn-sm btn-primary"
|
<div className="mt-3 text-end">
|
||||||
disabled={isPending || loading}
|
<button
|
||||||
>
|
type="submit"
|
||||||
{isPending ? "Please Wait..." : "Update Permission"}
|
className="btn btn-sm btn-primary"
|
||||||
</button>
|
disabled={isPending || loading}
|
||||||
|
>
|
||||||
|
{isPending ? "Please Wait..." : "Save Permission"}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Permissions */}
|
|
||||||
{ProjectModules.map((feature) => (
|
{ProjectModules.map((feature) => (
|
||||||
<div key={feature.id} className="row my-2 px-3 ">
|
<div
|
||||||
<div className="col-12 text-start fw-semibold mb-2">
|
key={feature.id}
|
||||||
{feature.name}
|
className="col-12 col-sm-6 col-md-4 col-lg-4 mb-4"
|
||||||
</div>
|
>
|
||||||
<div className="col-12">
|
<div className="card text-start border-1 p-1">
|
||||||
<div className="row">
|
<p className="card-title fs-6 fw-semibold">{feature.name}</p>
|
||||||
{feature.featurePermissions?.map((perm) => (
|
<div className="px-2">
|
||||||
<div className="col-12 col-sm-6 col-md-4 mb-2" key={perm.id}>
|
<ul class="list-unstyled">
|
||||||
<label
|
{feature.featurePermissions?.map((perm) => (
|
||||||
className="form-check-label d-flex align-items-center"
|
<div className="d-flex my-2" key={perm.id}>
|
||||||
htmlFor={perm.id}
|
<label
|
||||||
>
|
className="form-check-label d-flex align-items-center"
|
||||||
<input
|
htmlFor={perm.id}
|
||||||
type="checkbox"
|
>
|
||||||
className="form-check-input me-2"
|
<input
|
||||||
id={perm.id}
|
type="checkbox"
|
||||||
value={perm.id}
|
className="form-check-input me-2"
|
||||||
{...register("selectedPermissions")}
|
id={perm.id}
|
||||||
/>
|
value={perm.id}
|
||||||
{perm.name}
|
{...register("selectedPermissions")}
|
||||||
</label>
|
/>
|
||||||
</div>
|
{perm.name}
|
||||||
))}
|
</label>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<hr className="my-2" />
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</form>
|
</form>
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
|
|
||||||
import { useProfile } from "./useProfile"
|
import { useSelectedProject } from "../slices/apiDataManager";
|
||||||
|
import { useAllProjectLevelPermissions, useProfile } from "./useProfile";
|
||||||
|
|
||||||
export const useHasUserPermission = (permission) => {
|
export const useHasUserPermission = (permission) => {
|
||||||
|
const selectedProject = useSelectedProject();
|
||||||
const { profile } = useProfile();
|
const { profile } = useProfile();
|
||||||
|
const { data: projectPermissions = [], isLoading, isError } = useAllProjectLevelPermissions(selectedProject);
|
||||||
|
|
||||||
if (profile && permission && typeof permission === "string") {
|
if (isLoading || !permission) return false;
|
||||||
return profile?.featurePermissions.includes(permission);
|
|
||||||
}
|
const globalPerms = profile?.featurePermissions ?? [];
|
||||||
|
const projectPerms = projectPermissions ?? [];
|
||||||
return false;
|
|
||||||
|
return globalPerms.includes(permission) || projectPerms.includes(permission);
|
||||||
};
|
};
|
||||||
|
@ -1,67 +1,20 @@
|
|||||||
import {useState,useEffect, useCallback} from "react";
|
import { useState, useEffect, useCallback } from "react";
|
||||||
import AuthRepository from "../repositories/AuthRepository";
|
import AuthRepository from "../repositories/AuthRepository";
|
||||||
import {cacheData, cacheProfileData, getCachedData, getCachedProfileData} from "../slices/apiDataManager";
|
import {
|
||||||
import {useSelector} from "react-redux";
|
cacheData,
|
||||||
|
cacheProfileData,
|
||||||
|
getCachedData,
|
||||||
|
getCachedProfileData,
|
||||||
|
useSelectedProject,
|
||||||
|
} from "../slices/apiDataManager";
|
||||||
|
import { useSelector } from "react-redux";
|
||||||
import eventBus from "../services/eventBus";
|
import eventBus from "../services/eventBus";
|
||||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||||
|
import ProjectRepository from "../repositories/ProjectRepository";
|
||||||
|
|
||||||
let hasFetched = false;
|
let hasFetched = false;
|
||||||
let hasReceived = false;
|
let hasReceived = false;
|
||||||
|
|
||||||
// export const useProfile = () => {
|
|
||||||
// const loggedUser = useSelector( ( store ) => store.globalVariables.loginUser );
|
|
||||||
// const [profile, setProfile] = useState(null);
|
|
||||||
// const [loading, setLoading] = useState(false);
|
|
||||||
// const [error, setError] = useState("");
|
|
||||||
|
|
||||||
// const fetchData = async () => {
|
|
||||||
// try {
|
|
||||||
// setLoading(true);
|
|
||||||
// let response = await AuthRepository.profile();
|
|
||||||
// setProfile(response.data);
|
|
||||||
// cacheProfileData(response.data);
|
|
||||||
// } catch (error) {
|
|
||||||
// setError("Failed to fetch data.");
|
|
||||||
// } finally {
|
|
||||||
// setLoading(false);
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const validation = () => {
|
|
||||||
// if (!hasFetched) {
|
|
||||||
// hasFetched = true;
|
|
||||||
// if (!loggedUser) {
|
|
||||||
// fetchData();
|
|
||||||
// } else {
|
|
||||||
// setProfile(loggedUser);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// setProfile(loggedUser);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// validation();
|
|
||||||
// }, [loggedUser]);
|
|
||||||
|
|
||||||
// const handler = useCallback(
|
|
||||||
// (data) => {
|
|
||||||
// if(!getCachedData("hasReceived")){
|
|
||||||
// cacheData("hasReceived", true);
|
|
||||||
// hasFetched = false;
|
|
||||||
// validation();
|
|
||||||
// }
|
|
||||||
// },[]
|
|
||||||
// );
|
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// eventBus.on("assign_project_one", handler);
|
|
||||||
// return () => eventBus.off("assign_project_one", handler);
|
|
||||||
// }, [handler]);
|
|
||||||
|
|
||||||
// return { profile, loading, error };
|
|
||||||
// };
|
|
||||||
|
|
||||||
export const useProfile = () => {
|
export const useProfile = () => {
|
||||||
const loggedUser = useSelector((store) => store.globalVariables.loginUser);
|
const loggedUser = useSelector((store) => store.globalVariables.loginUser);
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
@ -100,12 +53,26 @@ export const useProfile = () => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useSidBarMenu = () => {
|
||||||
export const useSidBarMenu = ()=>{
|
const userLogged = useSelector((store) => store.globalVariables.loginUser);
|
||||||
const userLogged = useSelector((store)=>store.globalVariables.loginUser);
|
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey:["AppMenu"],
|
queryKey: ["AppMenu"],
|
||||||
queryFn:async()=> await AuthRepository.appmenu(),
|
queryFn: async () => await AuthRepository.appmenu(),
|
||||||
enabled: !!userLogged
|
enabled: !!userLogged,
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
|
export const useAllProjectLevelPermissions = (projectId) => {
|
||||||
|
|
||||||
|
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ["AllProjectLevelPermission", projectId],
|
||||||
|
queryFn: async () => {
|
||||||
|
const resp = await ProjectRepository.getAllProjectLevelPermission(
|
||||||
|
projectId
|
||||||
|
);
|
||||||
|
return resp.data;
|
||||||
|
},
|
||||||
|
enabled: !!projectId,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
@ -44,7 +44,8 @@ const ProjectRepository = {
|
|||||||
getProjectLevelEmployeeList:(projectId)=>api.get(`/api/Project/get/proejct-level/employees/${projectId}`),
|
getProjectLevelEmployeeList:(projectId)=>api.get(`/api/Project/get/proejct-level/employees/${projectId}`),
|
||||||
getProjectLevelModules:()=>api.get(`/api/Project/get/proejct-level/modules`),
|
getProjectLevelModules:()=>api.get(`/api/Project/get/proejct-level/modules`),
|
||||||
getProjectLevelEmployeePermissions:(employeeId,projectId)=>api.get(`/api/Project/get/project-level-permission/employee/${employeeId}/project/${projectId}`),
|
getProjectLevelEmployeePermissions:(employeeId,projectId)=>api.get(`/api/Project/get/project-level-permission/employee/${employeeId}/project/${projectId}`),
|
||||||
updateProjectLevelEmployeePermission:(data)=>api.post(`/api/Project/assign/project-level-permission`,data)
|
updateProjectLevelEmployeePermission:(data)=>api.post(`/api/Project/assign/project-level-permission`,data),
|
||||||
|
getAllProjectLevelPermission:(projectId)=>api.get(`/api/Project/get/all/project-level-permission/${projectId}`)
|
||||||
};
|
};
|
||||||
|
|
||||||
export const TasksRepository = {
|
export const TasksRepository = {
|
||||||
|
@ -17,6 +17,7 @@ export const VIEW_ALL_EMPLOYEES = "60611762-7f8a-4fb5-b53f-b1139918796b"
|
|||||||
|
|
||||||
export const VIEW_TEAM_MEMBERS = "b82d2b7e-0d52-45f3-997b-c008ea460e7f"
|
export const VIEW_TEAM_MEMBERS = "b82d2b7e-0d52-45f3-997b-c008ea460e7f"
|
||||||
|
|
||||||
|
export const MANAGE_TEAM = "b94802ce-0689-4643-9e1d-11c86950c35b"
|
||||||
|
|
||||||
export const MANAGE_PROJECT_INFRA = "cf2825ad-453b-46aa-91d9-27c124d63373"
|
export const MANAGE_PROJECT_INFRA = "cf2825ad-453b-46aa-91d9-27c124d63373"
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user