chore: user cannot update their own role (#1041)

This commit is contained in:
Aaryan Khandelwal 2023-05-15 11:35:19 +05:30 committed by GitHub
parent 290318603d
commit 9fdc56db0f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 55 additions and 39 deletions

View File

@ -5,6 +5,7 @@ import Image from "next/image";
import useSWR, { mutate } from "swr";
// react-hook-form
import { Controller, useForm } from "react-hook-form";
// layouts
import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
@ -12,6 +13,8 @@ import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
import projectService from "services/project.service";
// hooks
import useToast from "hooks/use-toast";
// components
import { SettingsHeader } from "components/project";
// ui
import { CustomSelect, Loader, SecondaryButton } from "components/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
@ -20,7 +23,6 @@ import { IProject, IWorkspace } from "types";
import type { NextPage } from "next";
// fetch-keys
import { PROJECTS_LIST, PROJECT_DETAILS, PROJECT_MEMBERS } from "constants/fetch-keys";
import { SettingsHeader } from "components/project";
const defaultValues: Partial<IProject> = {
project_lead: null,
@ -104,7 +106,7 @@ const ControlSettings: NextPage = () => {
</Breadcrumbs>
}
>
<form onSubmit={handleSubmit(onSubmit)} className="px-24 py-8">
<form onSubmit={handleSubmit(onSubmit)} className="p-8 lg:px-24">
<SettingsHeader />
<div className="space-y-8 sm:space-y-12">
<div className="grid grid-cols-12 items-start gap-4 sm:gap-16">

View File

@ -13,6 +13,7 @@ import useProjectDetails from "hooks/use-project-details";
import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
// components
import { CreateUpdateEstimateModal, SingleEstimate } from "components/estimates";
import { SettingsHeader } from "components/project";
//hooks
import useToast from "hooks/use-toast";
// ui
@ -27,7 +28,6 @@ import { IEstimate, IProject } from "types";
import type { NextPage } from "next";
// fetch-keys
import { ESTIMATES_LIST, PROJECT_DETAILS } from "constants/fetch-keys";
import { SettingsHeader } from "components/project";
const EstimatesSettings: NextPage = () => {
const [estimateFormOpen, setEstimateFormOpen] = useState(false);
@ -118,7 +118,7 @@ const EstimatesSettings: NextPage = () => {
</Breadcrumbs>
}
>
<div className="px-24 py-8">
<div className="p-8 lg:px-24">
<SettingsHeader />
<section className="flex items-center justify-between">
<h3 className="text-2xl font-semibold">Estimates</h3>

View File

@ -11,6 +11,8 @@ import trackEventServices, { MiscellaneousEventType } from "services/track-event
import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
// hooks
import useToast from "hooks/use-toast";
// components
import { SettingsHeader } from "components/project";
// ui
import { SecondaryButton, ToggleSwitch } from "components/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
@ -22,7 +24,6 @@ import { IFavoriteProject, IProject } from "types";
import type { NextPage } from "next";
// fetch-keys
import { FAVORITE_PROJECTS_LIST, PROJECTS_LIST, PROJECT_DETAILS } from "constants/fetch-keys";
import { SettingsHeader } from "components/project";
const featuresList = [
{
@ -163,7 +164,7 @@ const FeaturesSettings: NextPage = () => {
</Breadcrumbs>
}
>
<div className="px-24 py-8">
<div className="p-8 lg:px-24">
<SettingsHeader />
<section className="space-y-8">
<h3 className="text-2xl font-semibold">Features</h3>

View File

@ -151,7 +151,7 @@ const GeneralSettings: NextPage = () => {
router.push(`/${workspaceSlug}/projects`);
}}
/>
<form onSubmit={handleSubmit(onSubmit)} className="py-8 px-24">
<form onSubmit={handleSubmit(onSubmit)} className="p-8 lg:px-24">
<SettingsHeader />
<div className="space-y-8 sm:space-y-12">
<div className="grid grid-cols-12 items-start gap-4 sm:gap-16">

View File

@ -54,7 +54,7 @@ const ProjectIntegrations: NextPage = () => {
</Breadcrumbs>
}
>
<div className="px-24 py-8">
<div className="p-8 lg:px-24">
<SettingsHeader />
{workspaceIntegrations ? (
workspaceIntegrations.length > 0 ? (

View File

@ -16,6 +16,7 @@ import {
SingleLabel,
SingleLabelGroup,
} from "components/labels";
import { SettingsHeader } from "components/project";
// ui
import { Loader, PrimaryButton } from "components/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
@ -26,7 +27,6 @@ import { IIssueLabels } from "types";
import type { NextPage } from "next";
// fetch-keys
import { PROJECT_DETAILS, PROJECT_ISSUE_LABELS } from "constants/fetch-keys";
import { SettingsHeader } from "components/project";
const LabelsSettings: NextPage = () => {
// create/edit label form
@ -102,7 +102,7 @@ const LabelsSettings: NextPage = () => {
</Breadcrumbs>
}
>
<div className="px-24 py-8">
<div className="p-8 lg:px-24">
<SettingsHeader />
<section className="grid grid-cols-12 gap-10">
<div className="col-span-12 sm:col-span-5">

View File

@ -11,11 +11,13 @@ import workspaceService from "services/workspace.service";
// hooks
import useToast from "hooks/use-toast";
import useProjectDetails from "hooks/use-project-details";
import useUser from "hooks/use-user";
// layouts
import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
// components
import ConfirmProjectMemberRemove from "components/project/confirm-project-member-remove";
import SendProjectInvitationModal from "components/project/send-project-invitation-modal";
import { SettingsHeader } from "components/project";
// ui
import { CustomMenu, CustomSelect, Loader } from "components/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
@ -27,7 +29,6 @@ import type { NextPage } from "next";
import { PROJECT_INVITATIONS, PROJECT_MEMBERS, WORKSPACE_DETAILS } from "constants/fetch-keys";
// constants
import { ROLE } from "constants/workspace";
import { SettingsHeader } from "components/project";
const MembersSettings: NextPage = () => {
const [inviteModal, setInviteModal] = useState(false);
@ -36,17 +37,17 @@ const MembersSettings: NextPage = () => {
const { setToastAlert } = useToast();
const {
query: { workspaceSlug, projectId },
} = useRouter();
const router = useRouter();
const { workspaceSlug, projectId } = router.query;
const { user } = useUser();
const { projectDetails } = useProjectDetails();
const { data: activeWorkspace } = useSWR(
workspaceSlug ? WORKSPACE_DETAILS(workspaceSlug as string) : null,
() => (workspaceSlug ? workspaceService.getWorkspace(workspaceSlug as string) : null)
);
const { projectDetails } = useProjectDetails();
const { data: projectMembers, mutate: mutateMembers } = useSWR(
workspaceSlug && projectId ? PROJECT_MEMBERS(projectId as string) : null,
workspaceSlug && projectId
@ -62,8 +63,9 @@ const MembersSettings: NextPage = () => {
);
const members = [
...(projectMembers?.map((item: any) => ({
...(projectMembers?.map((item) => ({
id: item.id,
memberId: item.member?.id,
avatar: item.member?.avatar,
first_name: item.member?.first_name,
last_name: item.member?.last_name,
@ -74,6 +76,7 @@ const MembersSettings: NextPage = () => {
})) || []),
...(projectInvitations?.map((item: any) => ({
id: item.id,
memberId: item.id,
avatar: item.avatar ?? "",
first_name: item.first_name ?? item.email,
last_name: item.last_name ?? "",
@ -142,7 +145,7 @@ const MembersSettings: NextPage = () => {
</Breadcrumbs>
}
>
<div className="px-24 py-8">
<div className="p-8 lg:px-24">
<SettingsHeader />
<section className="space-y-8">
<div className="flex items-end justify-between gap-4">
@ -231,6 +234,7 @@ const MembersSettings: NextPage = () => {
});
}}
position="right"
disabled={member.memberId === user?.id}
>
{Object.keys(ROLE).map((key) => (
<CustomSelect.Option key={key} value={key}>

View File

@ -17,6 +17,7 @@ import {
SingleState,
StateGroup,
} from "components/states";
import { SettingsHeader } from "components/project";
// ui
import { Loader } from "components/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
@ -28,7 +29,6 @@ import { getStatesList, orderStateGroups } from "helpers/state.helper";
import type { NextPage } from "next";
// fetch-keys
import { STATES_LIST } from "constants/fetch-keys";
import { SettingsHeader } from "components/project";
const StatesSettings: NextPage = () => {
const [activeGroup, setActiveGroup] = useState<StateGroup>(null);
@ -67,7 +67,7 @@ const StatesSettings: NextPage = () => {
</Breadcrumbs>
}
>
<div className="px-24 py-8">
<div className="p-8 lg:px-24">
<SettingsHeader />
<div className="grid grid-cols-12 gap-10">
<div className="col-span-12 sm:col-span-5">

View File

@ -39,7 +39,7 @@ const BillingSettings: NextPage = () => {
</Breadcrumbs>
}
>
<div className="px-24 py-8">
<div className="p-8 lg:px-24">
<SettingsHeader />
<section className="space-y-8">
<div>

View File

@ -23,7 +23,7 @@ const ImportExport: NextPage = () => {
</Breadcrumbs>
}
>
<div className="px-24 py-8">
<div className="p-8 lg:px-24">
<SettingsHeader />
<IntegrationGuide />
</div>

View File

@ -173,7 +173,7 @@ const WorkspaceSettings: NextPage = () => {
}}
data={activeWorkspace ?? null}
/>
<div className="px-24 py-8">
<div className="p-8 lg:px-24">
<SettingsHeader />
{activeWorkspace ? (
<div className="space-y-8 sm:space-y-12">

View File

@ -47,7 +47,7 @@ const WorkspaceIntegrations: NextPage = () => {
</Breadcrumbs>
}
>
<div className="px-24 py-8">
<div className="p-8 lg:px-24">
<SettingsHeader />
<section className="space-y-8">
<div className="flex flex-col items-start gap-3">

View File

@ -5,10 +5,11 @@ import { useRouter } from "next/router";
import useSWR from "swr";
// hooks
import useToast from "hooks/use-toast";
// services
import workspaceService from "services/workspace.service";
// hooks
import useToast from "hooks/use-toast";
import useUser from "hooks/use-user";
// layouts
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout";
import { SettingsHeader } from "components/workspace";
@ -37,24 +38,27 @@ const MembersSettings: NextPage = () => {
const { setToastAlert } = useToast();
const { user } = useUser();
const { data: activeWorkspace } = useSWR(
workspaceSlug ? WORKSPACE_DETAILS(workspaceSlug as string) : null,
() => (workspaceSlug ? workspaceService.getWorkspace(workspaceSlug as string) : null)
workspaceSlug ? WORKSPACE_DETAILS(workspaceSlug.toString()) : null,
() => (workspaceSlug ? workspaceService.getWorkspace(workspaceSlug.toString()) : null)
);
const { data: workspaceMembers, mutate: mutateMembers } = useSWR<any[]>(
workspaceSlug ? WORKSPACE_MEMBERS(workspaceSlug as string) : null,
workspaceSlug ? () => workspaceService.workspaceMembers(workspaceSlug as string) : null
const { data: workspaceMembers, mutate: mutateMembers } = useSWR(
workspaceSlug ? WORKSPACE_MEMBERS(workspaceSlug.toString()) : null,
workspaceSlug ? () => workspaceService.workspaceMembers(workspaceSlug.toString()) : null
);
const { data: workspaceInvitations, mutate: mutateInvitations } = useSWR<any[]>(
const { data: workspaceInvitations, mutate: mutateInvitations } = useSWR(
workspaceSlug ? WORKSPACE_INVITATIONS : null,
workspaceSlug ? () => workspaceService.workspaceInvitations(workspaceSlug as string) : null
workspaceSlug ? () => workspaceService.workspaceInvitations(workspaceSlug.toString()) : null
);
const members = [
...(workspaceMembers?.map((item) => ({
id: item.id,
memberId: item.member?.id,
avatar: item.member?.avatar,
first_name: item.member?.first_name,
last_name: item.member?.last_name,
@ -65,9 +69,10 @@ const MembersSettings: NextPage = () => {
})) || []),
...(workspaceInvitations?.map((item) => ({
id: item.id,
avatar: item.avatar ?? "",
first_name: item.first_name ?? item.email,
last_name: item.last_name ?? "",
memberId: item.id,
avatar: "",
first_name: item.email,
last_name: "",
email: item.email,
role: item.role,
status: item.accepted,
@ -138,7 +143,7 @@ const MembersSettings: NextPage = () => {
</Breadcrumbs>
}
>
<div className="px-24 py-8">
<div className="p-8 lg:px-24">
<SettingsHeader />
<section className="space-y-8">
<div className="flex items-end justify-between gap-4">
@ -197,8 +202,10 @@ const MembersSettings: NextPage = () => {
label={ROLE[member.role as keyof typeof ROLE]}
value={member.role}
onChange={(value: any) => {
if (!workspaceSlug) return;
workspaceService
.updateWorkspaceMember(activeWorkspace?.slug as string, member.id, {
.updateWorkspaceMember(workspaceSlug?.toString(), member.id, {
role: value,
})
.then(() => {
@ -224,6 +231,7 @@ const MembersSettings: NextPage = () => {
});
}}
position="right"
disabled={member.memberId === user?.id}
>
{Object.keys(ROLE).map((key) => (
<CustomSelect.Option key={key} value={key}>

View File

@ -60,6 +60,7 @@ type ProjectViewTheme = {
};
export interface IProjectMember {
id: string;
member: IUserLite;
project: IProject;
workspace: IWorkspace;

View File

@ -23,9 +23,9 @@ export interface IWorkspaceLite {
}
export interface IWorkspaceMemberInvitation {
accepted: boolean;
readonly id: string;
email: string;
accepted: boolean;
token: string;
message: string;
responded_at: Date;