plane/apps/app/pages/projects/index.tsx

138 lines
4.7 KiB
TypeScript
Raw Normal View History

import React, { useState } from "react";
2022-11-19 14:21:26 +00:00
// next
import type { NextPage } from "next";
// hooks
import useUser from "lib/hooks/useUser";
// hoc
import withAuth from "lib/hoc/withAuthWrapper";
2022-11-19 14:21:26 +00:00
// layouts
import AppLayout from "layouts/app-layout";
2022-11-19 14:21:26 +00:00
// components
import ProjectMemberInvitations from "components/project/memberInvitations";
import ConfirmProjectDeletion from "components/project/confirm-project-deletion";
2022-11-19 14:21:26 +00:00
// ui
import {
Button,
Spinner,
HeaderButton,
Breadcrumbs,
BreadcrumbItem,
EmptySpace,
EmptySpaceItem,
} from "ui";
2022-11-19 14:21:26 +00:00
// services
import projectService from "lib/services/project.service";
// icons
2022-11-19 14:21:26 +00:00
import { ClipboardDocumentListIcon, PlusIcon } from "@heroicons/react/24/outline";
const Projects: NextPage = () => {
const [deleteProject, setDeleteProject] = useState<string | null>(null);
2022-11-19 14:21:26 +00:00
const [invitationsRespond, setInvitationsRespond] = useState<string[]>([]);
const { projects, activeWorkspace, mutateProjects } = useUser();
const handleInvitation = (project_invitation: any, action: "accepted" | "withdraw") => {
if (action === "accepted") {
setInvitationsRespond((prevData) => {
return [...prevData, project_invitation.id];
});
} else if (action === "withdraw") {
setInvitationsRespond((prevData) => {
return prevData.filter((item: string) => item !== project_invitation.id);
});
}
};
const submitInvitations = () => {
projectService
.joinProject((activeWorkspace as any)?.slug, { project_ids: invitationsRespond })
.then(async (res: any) => {
console.log(res);
setInvitationsRespond([]);
await mutateProjects();
})
.catch((err: any) => {
console.log(err);
});
};
return (
<AppLayout>
2022-11-19 14:21:26 +00:00
<ConfirmProjectDeletion
isOpen={!!deleteProject}
onClose={() => setDeleteProject(null)}
data={projects?.find((item) => item.id === deleteProject) ?? null}
2022-11-19 14:21:26 +00:00
/>
{projects ? (
<>
{projects.length === 0 ? (
<div className="h-full w-full grid place-items-center px-4 sm:px-0">
<EmptySpace
title="You don't have any project yet."
description="Projects are a collection of issues. They can be used to represent the development work for a product, project, or service."
Icon={ClipboardDocumentListIcon}
>
<EmptySpaceItem
title="Create a new project"
description={
<span>
Use{" "}
<pre className="inline bg-gray-100 px-2 py-1 rounded">Ctrl/Command + P</pre>{" "}
shortcut to create a new project
</span>
}
Icon={PlusIcon}
action={() => {
const e = new KeyboardEvent("keydown", { key: "p", ctrlKey: true });
document.dispatchEvent(e);
}}
/>
</EmptySpace>
</div>
) : (
<div className="h-full w-full space-y-5">
<Breadcrumbs>
<BreadcrumbItem title={`${activeWorkspace?.name ?? "Workspace"} Projects`} />
</Breadcrumbs>
<div className="flex items-center justify-between cursor-pointer w-full">
<h2 className="text-2xl font-medium">Projects</h2>
<HeaderButton
Icon={PlusIcon}
label="Add Project"
onClick={() => {
const e = new KeyboardEvent("keydown", { key: "p", ctrlKey: true });
document.dispatchEvent(e);
}}
/>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{projects.map((item) => (
<ProjectMemberInvitations
key={item.id}
project={item}
slug={(activeWorkspace as any).slug}
invitationsRespond={invitationsRespond}
handleInvitation={handleInvitation}
setDeleteProject={setDeleteProject}
/>
))}
</div>
{invitationsRespond.length > 0 && (
<div className="flex justify-between mt-4">
<Button onClick={submitInvitations}>Submit</Button>
2022-11-19 14:21:26 +00:00
</div>
)}
</div>
)}
2022-11-19 14:21:26 +00:00
</>
) : (
<div className="w-full h-full flex justify-center items-center">
<Spinner />
</div>
)}
</AppLayout>
2022-11-19 14:21:26 +00:00
);
};
export default withAuth(Projects);