fix: join project screen flicker (#541)

This commit is contained in:
Aaryan Khandelwal 2023-03-27 16:53:31 +05:30 committed by GitHub
parent 21dd2e703b
commit e13b679c28
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 98 additions and 36 deletions

View File

@ -121,17 +121,17 @@ export const CreateProjectModal: React.FC<Props> = (props) => {
false false
); );
setToastAlert({ setToastAlert({
title: "Success",
type: "success", type: "success",
message: "Project created successfully", title: "Success!",
message: "Project created successfully.",
}); });
handleClose(); handleClose();
}) })
.catch((err) => { .catch((err) => {
if (err.status === 403) { if (err.status === 403) {
setToastAlert({ setToastAlert({
title: "Error",
type: "error", type: "error",
title: "Error!",
message: "You don't have permission to create project.", message: "You don't have permission to create project.",
}); });
handleClose(); handleClose();

View File

@ -7,8 +7,6 @@ import useSWR from "swr";
// services // services
import projectService from "services/project.service"; import projectService from "services/project.service";
// hooks
import useUser from "hooks/use-user";
// ui // ui
import { PrimaryButton, Spinner } from "components/ui"; import { PrimaryButton, Spinner } from "components/ui";
// icon // icon
@ -66,8 +64,6 @@ const AppLayout: FC<AppLayoutProps> = ({
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;
const { user } = useUser();
const { data: projectMembers, mutate: projectMembersMutate } = useSWR( const { data: projectMembers, mutate: projectMembersMutate } = useSWR(
workspaceSlug && projectId ? PROJECT_MEMBERS(projectId as string) : null, workspaceSlug && projectId ? PROJECT_MEMBERS(projectId as string) : null,
workspaceSlug && projectId workspaceSlug && projectId
@ -78,7 +74,12 @@ const AppLayout: FC<AppLayoutProps> = ({
} }
); );
// flags // flags
const isMember = projectMembers?.find((member) => member.member.id === user?.id) || !projectId; const isMember =
!projectId ||
memberType?.isOwner ||
memberType?.isMember ||
memberType?.isViewer ||
memberType?.isGuest;
const handleJoin = () => { const handleJoin = () => {
setIsJoiningProject(true); setIsJoiningProject(true);

View File

@ -111,6 +111,7 @@ const SingleCycle: React.FC<UserAuth> = (props) => {
handleOnSubmit={handleAddIssuesToCycle} handleOnSubmit={handleAddIssuesToCycle}
/> />
<AppLayout <AppLayout
memberType={props}
breadcrumbs={ breadcrumbs={
<Breadcrumbs> <Breadcrumbs>
<BreadcrumbItem <BreadcrumbItem
@ -159,9 +160,19 @@ const SingleCycle: React.FC<UserAuth> = (props) => {
} }
> >
<div className={`h-full ${cycleSidebar ? "mr-[24rem]" : ""} duration-300`}> <div className={`h-full ${cycleSidebar ? "mr-[24rem]" : ""} duration-300`}>
<IssuesView type="cycle" userAuth={props} openIssuesListModal={openIssuesListModal} isCompleted={cycleStatus === "completed" ?? false} /> <IssuesView
type="cycle"
userAuth={props}
openIssuesListModal={openIssuesListModal}
isCompleted={cycleStatus === "completed" ?? false}
/>
</div> </div>
<CycleDetailsSidebar cycleStatus={cycleStatus} cycle={cycleDetails} isOpen={cycleSidebar} isCompleted={cycleStatus === "completed" ?? false} /> <CycleDetailsSidebar
cycleStatus={cycleStatus}
cycle={cycleDetails}
isOpen={cycleSidebar}
isCompleted={cycleStatus === "completed" ?? false}
/>
</AppLayout> </AppLayout>
</IssueViewContextProvider> </IssueViewContextProvider>
); );

View File

@ -8,7 +8,7 @@ import useSWR from "swr";
import { PlusIcon } from "@heroicons/react/24/outline"; import { PlusIcon } from "@heroicons/react/24/outline";
import { Tab } from "@headlessui/react"; import { Tab } from "@headlessui/react";
// lib // lib
import { requiredAuth } from "lib/auth"; import { requiredAdmin, requiredAuth } from "lib/auth";
// services // services
import cycleService from "services/cycles.service"; import cycleService from "services/cycles.service";
@ -23,7 +23,7 @@ import { HeaderButton, Loader } from "components/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
// icons // icons
// types // types
import { SelectCycleType } from "types"; import { SelectCycleType, UserAuth } from "types";
import type { NextPage, GetServerSidePropsContext } from "next"; import type { NextPage, GetServerSidePropsContext } from "next";
// fetching keys // fetching keys
import { import {
@ -44,7 +44,7 @@ const CompletedCyclesList = dynamic<CompletedCyclesListProps>(
} }
); );
const ProjectCycles: NextPage = () => { const ProjectCycles: NextPage<UserAuth> = (props) => {
const [selectedCycle, setSelectedCycle] = useState<SelectCycleType>(); const [selectedCycle, setSelectedCycle] = useState<SelectCycleType>();
const [createUpdateCycleModal, setCreateUpdateCycleModal] = useState(false); const [createUpdateCycleModal, setCreateUpdateCycleModal] = useState(false);
@ -86,6 +86,7 @@ const ProjectCycles: NextPage = () => {
meta={{ meta={{
title: "Plane - Cycles", title: "Plane - Cycles",
}} }}
memberType={props}
breadcrumbs={ breadcrumbs={
<Breadcrumbs> <Breadcrumbs>
<BreadcrumbItem title="Projects" link={`/${workspaceSlug}/projects`} /> <BreadcrumbItem title="Projects" link={`/${workspaceSlug}/projects`} />
@ -210,9 +211,17 @@ export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
}; };
} }
const projectId = ctx.query.projectId as string;
const workspaceSlug = ctx.query.workspaceSlug as string;
const memberDetail = await requiredAdmin(workspaceSlug, projectId, ctx.req?.headers.cookie);
return { return {
props: { props: {
user, isOwner: memberDetail?.role === 20,
isMember: memberDetail?.role === 15,
isViewer: memberDetail?.role === 10,
isGuest: memberDetail?.role === 5,
}, },
}; };
}; };

View File

@ -121,6 +121,7 @@ const IssueDetailsPage: NextPage<UserAuth> = (props) => {
return ( return (
<AppLayout <AppLayout
memberType={props}
noPadding={true} noPadding={true}
bg="secondary" bg="secondary"
breadcrumbs={ breadcrumbs={

View File

@ -37,6 +37,7 @@ const ProjectIssues: NextPage<UserAuth> = (props) => {
return ( return (
<IssueViewContextProvider> <IssueViewContextProvider>
<AppLayout <AppLayout
memberType={props}
breadcrumbs={ breadcrumbs={
<Breadcrumbs> <Breadcrumbs>
<BreadcrumbItem title="Projects" link={`/${workspaceSlug}/projects`} /> <BreadcrumbItem title="Projects" link={`/${workspaceSlug}/projects`} />

View File

@ -112,6 +112,7 @@ const SingleModule: React.FC<UserAuth> = (props) => {
handleOnSubmit={handleAddIssuesToModule} handleOnSubmit={handleAddIssuesToModule}
/> />
<AppLayout <AppLayout
memberType={props}
breadcrumbs={ breadcrumbs={
<Breadcrumbs> <Breadcrumbs>
<BreadcrumbItem <BreadcrumbItem

View File

@ -9,7 +9,7 @@ import emptyModule from "public/empty-state/empty-module.svg";
// layouts // layouts
import AppLayout from "layouts/app-layout"; import AppLayout from "layouts/app-layout";
// lib // lib
import { requiredAuth } from "lib/auth"; import { requiredAdmin, requiredAuth } from "lib/auth";
// services // services
import projectService from "services/project.service"; import projectService from "services/project.service";
import modulesService from "services/modules.service"; import modulesService from "services/modules.service";
@ -21,11 +21,12 @@ import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
// icons // icons
// types // types
import { IModule, SelectModuleType } from "types/modules"; import { IModule, SelectModuleType } from "types/modules";
// fetch-keys import { UserAuth } from "types";
import type { NextPage, GetServerSidePropsContext } from "next"; import type { NextPage, GetServerSidePropsContext } from "next";
// fetch-keys
import { MODULE_LIST, PROJECT_DETAILS } from "constants/fetch-keys"; import { MODULE_LIST, PROJECT_DETAILS } from "constants/fetch-keys";
const ProjectModules: NextPage = () => { const ProjectModules: NextPage<UserAuth> = (props) => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;
const [selectedModule, setSelectedModule] = useState<SelectModuleType>(); const [selectedModule, setSelectedModule] = useState<SelectModuleType>();
@ -63,6 +64,7 @@ const ProjectModules: NextPage = () => {
meta={{ meta={{
title: "Plane - Modules", title: "Plane - Modules",
}} }}
memberType={props}
breadcrumbs={ breadcrumbs={
<Breadcrumbs> <Breadcrumbs>
<BreadcrumbItem title="Projects" link={`/${workspaceSlug}/projects`} /> <BreadcrumbItem title="Projects" link={`/${workspaceSlug}/projects`} />
@ -140,9 +142,17 @@ export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
}; };
} }
const projectId = ctx.query.projectId as string;
const workspaceSlug = ctx.query.workspaceSlug as string;
const memberDetail = await requiredAdmin(workspaceSlug, projectId, ctx.req?.headers.cookie);
return { return {
props: { props: {
user, isOwner: memberDetail?.role === 20,
isMember: memberDetail?.role === 15,
isViewer: memberDetail?.role === 10,
isGuest: memberDetail?.role === 5,
}, },
}; };
}; };

View File

@ -11,7 +11,7 @@ import { Popover, Transition } from "@headlessui/react";
// react-color // react-color
import { TwitterPicker } from "react-color"; import { TwitterPicker } from "react-color";
// lib // lib
import { requiredAuth } from "lib/auth"; import { requiredAdmin, requiredAuth } from "lib/auth";
// services // services
import projectService from "services/project.service"; import projectService from "services/project.service";
import pagesService from "services/pages.service"; import pagesService from "services/pages.service";
@ -33,7 +33,7 @@ import { renderShortTime } from "helpers/date-time.helper";
import { copyTextToClipboard } from "helpers/string.helper"; import { copyTextToClipboard } from "helpers/string.helper";
// types // types
import type { NextPage, GetServerSidePropsContext } from "next"; import type { NextPage, GetServerSidePropsContext } from "next";
import { IIssueLabels, IPage, IPageBlock } from "types"; import { IIssueLabels, IPage, IPageBlock, UserAuth } from "types";
// fetch-keys // fetch-keys
import { import {
PAGE_BLOCKS_LIST, PAGE_BLOCKS_LIST,
@ -42,7 +42,7 @@ import {
PROJECT_ISSUE_LABELS, PROJECT_ISSUE_LABELS,
} from "constants/fetch-keys"; } from "constants/fetch-keys";
const SinglePage: NextPage = () => { const SinglePage: NextPage<UserAuth> = (props) => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId, pageId } = router.query; const { workspaceSlug, projectId, pageId } = router.query;
@ -233,6 +233,7 @@ const SinglePage: NextPage = () => {
meta={{ meta={{
title: "Plane - Pages", title: "Plane - Pages",
}} }}
memberType={props}
breadcrumbs={ breadcrumbs={
<Breadcrumbs> <Breadcrumbs>
<BreadcrumbItem title="Projects" link={`/${workspaceSlug}/projects`} /> <BreadcrumbItem title="Projects" link={`/${workspaceSlug}/projects`} />
@ -454,9 +455,17 @@ export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
}; };
} }
const projectId = ctx.query.projectId as string;
const workspaceSlug = ctx.query.workspaceSlug as string;
const memberDetail = await requiredAdmin(workspaceSlug, projectId, ctx.req?.headers.cookie);
return { return {
props: { props: {
user, isOwner: memberDetail?.role === 20,
isMember: memberDetail?.role === 15,
isViewer: memberDetail?.role === 10,
isGuest: memberDetail?.role === 5,
}, },
}; };
}; };

View File

@ -9,7 +9,7 @@ import useSWR from "swr";
// react-hook-form // react-hook-form
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
// lib // lib
import { requiredAuth } from "lib/auth"; import { requiredAdmin, requiredAuth } from "lib/auth";
// headless ui // headless ui
import { Tab } from "@headlessui/react"; import { Tab } from "@headlessui/react";
// services // services
@ -29,7 +29,7 @@ import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
// icons // icons
import { ListBulletIcon, RectangleGroupIcon } from "@heroicons/react/20/solid"; import { ListBulletIcon, RectangleGroupIcon } from "@heroicons/react/20/solid";
// types // types
import { IPage, TPageViewProps } from "types"; import { IPage, TPageViewProps, UserAuth } from "types";
// fetch-keys // fetch-keys
import { PROJECT_DETAILS, RECENT_PAGES_LIST } from "constants/fetch-keys"; import { PROJECT_DETAILS, RECENT_PAGES_LIST } from "constants/fetch-keys";
@ -61,7 +61,7 @@ const OtherPagesList = dynamic<{ viewType: TPageViewProps }>(
} }
); );
const ProjectPages: NextPage = () => { const ProjectPages: NextPage<UserAuth> = (props) => {
const [createUpdatePageModal, setCreateUpdatePageModal] = useState(false); const [createUpdatePageModal, setCreateUpdatePageModal] = useState(false);
const [viewType, setViewType] = useState<TPageViewProps>("list"); const [viewType, setViewType] = useState<TPageViewProps>("list");
@ -138,6 +138,7 @@ const ProjectPages: NextPage = () => {
meta={{ meta={{
title: "Plane - Pages", title: "Plane - Pages",
}} }}
memberType={props}
breadcrumbs={ breadcrumbs={
<Breadcrumbs> <Breadcrumbs>
<BreadcrumbItem title="Projects" link={`/${workspaceSlug}/projects`} /> <BreadcrumbItem title="Projects" link={`/${workspaceSlug}/projects`} />
@ -260,9 +261,17 @@ export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
}; };
} }
const projectId = ctx.query.projectId as string;
const workspaceSlug = ctx.query.workspaceSlug as string;
const memberDetail = await requiredAdmin(workspaceSlug, projectId, ctx.req?.headers.cookie);
return { return {
props: { props: {
user, isOwner: memberDetail?.role === 20,
isMember: memberDetail?.role === 15,
isViewer: memberDetail?.role === 10,
isGuest: memberDetail?.role === 5,
}, },
}; };
}; };

View File

@ -57,6 +57,7 @@ const SingleView: React.FC<UserAuth> = (props) => {
return ( return (
<IssueViewContextProvider> <IssueViewContextProvider>
<AppLayout <AppLayout
memberType={props}
breadcrumbs={ breadcrumbs={
<Breadcrumbs> <Breadcrumbs>
<BreadcrumbItem <BreadcrumbItem

View File

@ -6,7 +6,7 @@ import { useRouter } from "next/router";
import useSWR from "swr"; import useSWR from "swr";
// lib // lib
import { requiredAuth } from "lib/auth"; import { requiredAdmin, requiredAuth } from "lib/auth";
// services // services
import viewsService from "services/views.service"; import viewsService from "services/views.service";
@ -26,11 +26,11 @@ import { PROJECT_DETAILS, VIEWS_LIST } from "constants/fetch-keys";
import { CustomMenu, PrimaryButton, Loader, EmptyState } from "components/ui"; import { CustomMenu, PrimaryButton, Loader, EmptyState } from "components/ui";
import { DeleteViewModal, CreateUpdateViewModal } from "components/views"; import { DeleteViewModal, CreateUpdateViewModal } from "components/views";
// types // types
import { IView } from "types"; import { IView, UserAuth } from "types";
import type { NextPage, GetServerSidePropsContext } from "next"; import type { NextPage, GetServerSidePropsContext } from "next";
import { StackedLayersIcon } from "components/icons"; import { StackedLayersIcon } from "components/icons";
const ProjectViews: NextPage = () => { const ProjectViews: NextPage<UserAuth> = (props) => {
const [isCreateViewModalOpen, setIsCreateViewModalOpen] = useState(false); const [isCreateViewModalOpen, setIsCreateViewModalOpen] = useState(false);
const [selectedView, setSelectedView] = useState<IView | null>(null); const [selectedView, setSelectedView] = useState<IView | null>(null);
@ -57,6 +57,7 @@ const ProjectViews: NextPage = () => {
meta={{ meta={{
title: "Plane - Views", title: "Plane - Views",
}} }}
memberType={props}
breadcrumbs={ breadcrumbs={
<Breadcrumbs> <Breadcrumbs>
<BreadcrumbItem title="Projects" link={`/${workspaceSlug}/projects`} /> <BreadcrumbItem title="Projects" link={`/${workspaceSlug}/projects`} />
@ -147,9 +148,17 @@ export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
}; };
} }
const projectId = ctx.query.projectId as string;
const workspaceSlug = ctx.query.workspaceSlug as string;
const memberDetail = await requiredAdmin(workspaceSlug, projectId, ctx.req?.headers.cookie);
return { return {
props: { props: {
user, isOwner: memberDetail?.role === 20,
isMember: memberDetail?.role === 15,
isViewer: memberDetail?.role === 10,
isGuest: memberDetail?.role === 5,
}, },
}; };
}; };

View File

@ -14,7 +14,7 @@ import AppLayout from "layouts/app-layout";
import { JoinProjectModal } from "components/project/join-project-modal"; import { JoinProjectModal } from "components/project/join-project-modal";
import { DeleteProjectModal, SingleProjectCard } from "components/project"; import { DeleteProjectModal, SingleProjectCard } from "components/project";
// ui // ui
import { HeaderButton, Loader, EmptyState } from "components/ui"; import { HeaderButton, Loader, EmptyState } from "components/ui";
import { Breadcrumbs, BreadcrumbItem } from "components/breadcrumbs"; import { Breadcrumbs, BreadcrumbItem } from "components/breadcrumbs";
// icons // icons
import { PlusIcon } from "@heroicons/react/24/outline"; import { PlusIcon } from "@heroicons/react/24/outline";
@ -83,11 +83,11 @@ const ProjectsPage: NextPage = () => {
<> <>
{projects.length === 0 ? ( {projects.length === 0 ? (
<EmptyState <EmptyState
type="project" type="project"
title="Create New Project" title="Create New Project"
description="Projects are a collection of issues. They can be used to represent the development work for a product, project, or service." description="Projects are a collection of issues. They can be used to represent the development work for a product, project, or service."
imgURL={emptyProject} imgURL={emptyProject}
/> />
) : ( ) : (
<div className="grid grid-cols-1 gap-9 md:grid-cols-2 lg:grid-cols-3"> <div className="grid grid-cols-1 gap-9 md:grid-cols-2 lg:grid-cols-3">
{projects.map((project) => ( {projects.map((project) => (