fix: pages layout and alignment issues (#1152)

This commit is contained in:
Aaryan Khandelwal 2023-05-29 15:16:49 +05:30 committed by GitHub
parent dce3c3f008
commit 022960d7e3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 161 additions and 286 deletions

View File

@ -25,9 +25,5 @@ export const AllPagesList: React.FC<TPagesListProps> = ({ viewType }) => {
: null : null
); );
return ( return <PagesView pages={pages} viewType={viewType} />;
<div className="mt-4 space-y-4">
<PagesView pages={pages} viewType={viewType} />
</div>
);
}; };

View File

@ -25,9 +25,5 @@ export const FavoritePagesList: React.FC<TPagesListProps> = ({ viewType }) => {
: null : null
); );
return ( return <PagesView pages={pages} viewType={viewType} />;
<div className="mt-4 space-y-4">
<PagesView pages={pages} viewType={viewType} />
</div>
);
}; };

View File

@ -25,9 +25,5 @@ export const MyPagesList: React.FC<TPagesListProps> = ({ viewType }) => {
: null : null
); );
return ( return <PagesView pages={pages} viewType={viewType} />;
<div className="mt-4 space-y-4">
<PagesView pages={pages} viewType={viewType} />
</div>
);
}; };

View File

@ -25,9 +25,5 @@ export const OtherPagesList: React.FC<TPagesListProps> = ({ viewType }) => {
: null : null
); );
return ( return <PagesView pages={pages} viewType={viewType} />;
<div className="mt-4 space-y-4">
<PagesView pages={pages} viewType={viewType} />
</div>
);
}; };

View File

@ -37,37 +37,28 @@ export const RecentPagesList: React.FC<TPagesListProps> = ({ viewType }) => {
<> <>
{pages ? ( {pages ? (
Object.keys(pages).length > 0 && !isEmpty ? ( Object.keys(pages).length > 0 && !isEmpty ? (
<div className="mt-4 space-y-4 flex flex-col gap-5"> Object.keys(pages).map((key) => {
{Object.keys(pages).map((key) => { if (pages[key].length === 0) return null;
if (pages[key].length === 0) return null;
return ( return (
<React.Fragment key={key}> <div key={key}>
<div> <h2 className="text-xl font-semibold capitalize mb-2">
<h2 className="text-xl font-semibold capitalize mb-4"> {replaceUnderscoreIfSnakeCase(key)}
{replaceUnderscoreIfSnakeCase(key)} </h2>
</h2> <PagesView pages={pages[key as keyof RecentPagesResponse]} viewType={viewType} />
<PagesView </div>
pages={pages[key as keyof RecentPagesResponse]} );
viewType={viewType} })
/>
</div>
</React.Fragment>
);
})}
</div>
) : ( ) : (
<div className="mt-4"> <EmptyState
<EmptyState type="page"
type="page" title="Create New Page"
title="Create New Page" description="Create and document issues effortlessly in one place with Plane Notes, AI-powered for ease."
description="Create and document issues effortlessly in one place with Plane Notes, AI-powered for ease." imgURL={emptyPage}
imgURL={emptyPage} />
/>
</div>
) )
) : ( ) : (
<Loader className="mt-8 space-y-4"> <Loader className="space-y-4">
<Loader.Item height="40px" /> <Loader.Item height="40px" />
<Loader.Item height="40px" /> <Loader.Item height="40px" />
<Loader.Item height="40px" /> <Loader.Item height="40px" />

View File

@ -200,61 +200,63 @@ export const PagesView: React.FC<Props> = ({ pages, viewType }) => {
data={selectedPageToDelete} data={selectedPageToDelete}
/> />
{pages ? ( {pages ? (
pages.length > 0 ? ( <div className="space-y-4 h-full overflow-y-auto">
viewType === "list" ? ( {pages.length > 0 ? (
<ul role="list" className="divide-y divide-brand-base"> viewType === "list" ? (
{pages.map((page) => ( <ul role="list" className="divide-y divide-brand-base">
<SinglePageListItem {pages.map((page) => (
key={page.id} <SinglePageListItem
page={page} key={page.id}
people={people} page={page}
handleEditPage={() => handleEditPage(page)} people={people}
handleDeletePage={() => handleDeletePage(page)} handleEditPage={() => handleEditPage(page)}
handleAddToFavorites={() => handleAddToFavorites(page)} handleDeletePage={() => handleDeletePage(page)}
handleRemoveFromFavorites={() => handleRemoveFromFavorites(page)} handleAddToFavorites={() => handleAddToFavorites(page)}
partialUpdatePage={partialUpdatePage} handleRemoveFromFavorites={() => handleRemoveFromFavorites(page)}
/> partialUpdatePage={partialUpdatePage}
))} />
</ul> ))}
) : viewType === "detailed" ? ( </ul>
<div className="divide-y divide-brand-base rounded-[10px] border border-brand-base bg-brand-base"> ) : viewType === "detailed" ? (
{pages.map((page) => ( <div className="divide-y divide-brand-base rounded-[10px] border border-brand-base bg-brand-base">
<SinglePageDetailedItem {pages.map((page) => (
key={page.id} <SinglePageDetailedItem
page={page} key={page.id}
people={people} page={page}
handleEditPage={() => handleEditPage(page)} people={people}
handleDeletePage={() => handleDeletePage(page)} handleEditPage={() => handleEditPage(page)}
handleAddToFavorites={() => handleAddToFavorites(page)} handleDeletePage={() => handleDeletePage(page)}
handleRemoveFromFavorites={() => handleRemoveFromFavorites(page)} handleAddToFavorites={() => handleAddToFavorites(page)}
partialUpdatePage={partialUpdatePage} handleRemoveFromFavorites={() => handleRemoveFromFavorites(page)}
/> partialUpdatePage={partialUpdatePage}
))} />
</div> ))}
</div>
) : (
<div className="rounded-[10px] border border-brand-base">
{pages.map((page) => (
<SinglePageDetailedItem
key={page.id}
page={page}
people={people}
handleEditPage={() => handleEditPage(page)}
handleDeletePage={() => handleDeletePage(page)}
handleAddToFavorites={() => handleAddToFavorites(page)}
handleRemoveFromFavorites={() => handleRemoveFromFavorites(page)}
partialUpdatePage={partialUpdatePage}
/>
))}
</div>
)
) : ( ) : (
<div className="rounded-[10px] border border-brand-base"> <EmptyState
{pages.map((page) => ( type="page"
<SinglePageDetailedItem title="Create New Page"
key={page.id} description="Create and document issues effortlessly in one place with Plane Notes, AI-powered for ease."
page={page} imgURL={emptyPage}
people={people} />
handleEditPage={() => handleEditPage(page)} )}
handleDeletePage={() => handleDeletePage(page)} </div>
handleAddToFavorites={() => handleAddToFavorites(page)}
handleRemoveFromFavorites={() => handleRemoveFromFavorites(page)}
partialUpdatePage={partialUpdatePage}
/>
))}
</div>
)
) : (
<EmptyState
type="page"
title="Create New Page"
description="Create and document issues effortlessly in one place with Plane Notes, AI-powered for ease."
imgURL={emptyPage}
/>
)
) : viewType === "list" ? ( ) : viewType === "list" ? (
<Loader className="space-y-4"> <Loader className="space-y-4">
<Loader.Item height="40px" /> <Loader.Item height="40px" />

View File

@ -1,19 +1,15 @@
import { useState } from "react"; import { useState, Fragment } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
import useSWR, { mutate } from "swr"; import useSWR from "swr";
// react-hook-form
import { useForm } from "react-hook-form";
// headless ui // headless ui
import { Tab } from "@headlessui/react"; import { Tab } from "@headlessui/react";
// services // services
import projectService from "services/project.service"; import projectService from "services/project.service";
import pagesService from "services/pages.service";
// hooks // hooks
import useToast from "hooks/use-toast";
import useLocalStorage from "hooks/use-local-storage"; import useLocalStorage from "hooks/use-local-storage";
// icons // icons
import { PlusIcon } from "components/icons"; import { PlusIcon } from "components/icons";
@ -22,20 +18,15 @@ import { ProjectAuthorizationWrapper } from "layouts/auth-layout";
// components // components
import { RecentPagesList, CreateUpdatePageModal, TPagesListProps } from "components/pages"; import { RecentPagesList, CreateUpdatePageModal, TPagesListProps } from "components/pages";
// ui // ui
import { Input, PrimaryButton } from "components/ui"; import { PrimaryButton } from "components/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
// icons // icons
import { ListBulletIcon, Squares2X2Icon } from "@heroicons/react/24/outline"; import { ListBulletIcon, Squares2X2Icon } from "@heroicons/react/24/outline";
// types // types
import { IPage, TPageViewProps } from "types"; import { TPageViewProps } from "types";
import type { NextPage } from "next"; import type { NextPage } from "next";
// fetch-keys // fetch-keys
import { import { PROJECT_DETAILS } from "constants/fetch-keys";
ALL_PAGES_LIST,
MY_PAGES_LIST,
PROJECT_DETAILS,
RECENT_PAGES_LIST,
} from "constants/fetch-keys";
const AllPagesList = dynamic<TPagesListProps>( const AllPagesList = dynamic<TPagesListProps>(
() => import("components/pages").then((a) => a.AllPagesList), () => import("components/pages").then((a) => a.AllPagesList),
@ -65,6 +56,8 @@ const OtherPagesList = dynamic<TPagesListProps>(
} }
); );
const tabsList = ["Recent", "All", "Favorites", "Created by me", "Created by others"];
const ProjectPages: NextPage = () => { const ProjectPages: NextPage = () => {
const [createUpdatePageModal, setCreateUpdatePageModal] = useState(false); const [createUpdatePageModal, setCreateUpdatePageModal] = useState(false);
@ -73,22 +66,8 @@ const ProjectPages: NextPage = () => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;
const { setToastAlert } = useToast();
const { storedValue: pageTab, setValue: setPageTab } = useLocalStorage("pageTab", "Recent"); const { storedValue: pageTab, setValue: setPageTab } = useLocalStorage("pageTab", "Recent");
const {
handleSubmit,
register,
watch,
reset,
formState: { isSubmitting },
} = useForm<Partial<IPage>>({
defaultValues: {
name: "",
},
});
const { data: projectDetails } = useSWR( const { data: projectDetails } = useSWR(
workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null, workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null,
workspaceSlug && projectId workspaceSlug && projectId
@ -96,58 +75,6 @@ const ProjectPages: NextPage = () => {
: null : null
); );
const createPage = async (formData: Partial<IPage>) => {
if (!workspaceSlug || !projectId) return;
if (formData.name === "") {
setToastAlert({
type: "error",
title: "Error!",
message: "Page name is required",
});
return;
}
await pagesService
.createPage(workspaceSlug as string, projectId as string, formData)
.then((res) => {
setToastAlert({
type: "success",
title: "Success!",
message: "Page created successfully.",
});
router.push(`/${workspaceSlug}/projects/${projectId}/pages/${res.id}`);
reset();
mutate(RECENT_PAGES_LIST(projectId as string));
mutate<IPage[]>(
MY_PAGES_LIST(projectId as string),
(prevData) => {
if (!prevData) return undefined;
return [res, ...(prevData as IPage[])];
},
false
);
mutate<IPage[]>(
ALL_PAGES_LIST(projectId as string),
(prevData) => {
if (!prevData) return undefined;
return [res, ...(prevData as IPage[])];
},
false
);
})
.catch(() => {
setToastAlert({
type: "error",
title: "Error!",
message: "Page could not be created. Please try again",
});
});
};
const currentTabValue = (tab: string | null) => { const currentTabValue = (tab: string | null) => {
switch (tab) { switch (tab) {
case "Recent": case "Recent":
@ -195,114 +122,85 @@ const ProjectPages: NextPage = () => {
</PrimaryButton> </PrimaryButton>
} }
> >
<div className="space-y-5 p-8"> <div className="space-y-5 p-8 h-full overflow-hidden flex flex-col">
<h3 className="text-2xl font-semibold text-brand-base">Pages</h3> <h3 className="text-2xl font-semibold text-brand-base">Pages</h3>
{/* <form <Tab.Group
onSubmit={handleSubmit(createPage)} as={Fragment}
className="relative mb-12 flex items-center justify-between gap-2 rounded-[6px] border border-brand-base p-2 shadow" defaultIndex={currentTabValue(pageTab)}
> onChange={(i) => {
<Input switch (i) {
type="text" case 0:
name="name" return setPageTab("Recent");
register={register} case 1:
className="flex break-all border-none text-xl font-medium outline-none focus:ring-0" return setPageTab("All");
placeholder="Title" case 2:
/> return setPageTab("Favorites");
{watch("name") !== "" && ( case 3:
<PrimaryButton type="submit" loading={isSubmitting}> return setPageTab("Created by me");
{isSubmitting ? "Creating..." : "Create"} case 4:
</PrimaryButton> return setPageTab("Created by others");
)}
</form> */}
<div>
<Tab.Group
defaultIndex={currentTabValue(pageTab)}
onChange={(i) => {
switch (i) {
case 0:
return setPageTab("Recent");
case 1:
return setPageTab("All");
case 2:
return setPageTab("Favorites");
case 3:
return setPageTab("Created by me");
case 4:
return setPageTab("Created by others");
default: default:
return setPageTab("Recent"); return setPageTab("Recent");
} }
}} }}
> >
<Tab.List as="div" className="mb-6 flex items-center justify-between"> <Tab.List as="div" className="mb-6 flex items-center justify-between">
<div className="flex gap-4"> <div className="flex gap-4">
{["Recent", "All", "Favorites", "Created by me", "Created by others"].map( {tabsList.map((tab, index) => (
(tab, index) => ( <Tab
<Tab key={`${tab}-${index}`}
key={index} className={({ selected }) =>
className={({ selected }) => `rounded-full border px-5 py-1.5 text-sm outline-none ${
`rounded-full border px-5 py-1.5 text-sm outline-none ${ selected
selected ? "border-brand-accent bg-brand-accent text-white"
? "border-brand-accent bg-brand-accent text-white" : "border-brand-base bg-brand-base hover:bg-brand-surface-1"
: "border-brand-base bg-brand-base hover:bg-brand-surface-1" }`
}` }
}
>
{tab}
</Tab>
)
)}
</div>
<div className="flex gap-x-1">
<button
type="button"
className={`grid h-7 w-7 place-items-center rounded p-1 outline-none duration-300 hover:bg-brand-surface-2 ${
viewType === "list" ? "bg-brand-surface-2" : ""
}`}
onClick={() => setViewType("list")}
> >
<ListBulletIcon className="h-4 w-4" /> {tab}
</button> </Tab>
<button ))}
type="button" </div>
className={`grid h-7 w-7 place-items-center rounded p-1 outline-none duration-300 hover:bg-brand-surface-2 ${ <div className="flex gap-x-1">
viewType === "detailed" ? "bg-brand-surface-2" : "" <button
}`} type="button"
onClick={() => setViewType("detailed")} className={`grid h-7 w-7 place-items-center rounded p-1 outline-none duration-300 hover:bg-brand-surface-2 ${
> viewType === "list" ? "bg-brand-surface-2" : ""
<Squares2X2Icon className="h-4 w-4" /> }`}
</button> onClick={() => setViewType("list")}
{/* <button >
type="button" <ListBulletIcon className="h-4 w-4" />
className={`grid h-7 w-7 place-items-center rounded p-1 outline-none duration-300 hover:bg-brand-surface-2 ${ </button>
viewType === "masonry" ? "bg-brand-surface-2" : "" <button
}`} type="button"
onClick={() => setViewType("masonry")} className={`grid h-7 w-7 place-items-center rounded p-1 outline-none duration-300 hover:bg-brand-surface-2 ${
> viewType === "detailed" ? "bg-brand-surface-2" : ""
<RectangleGroupIcon className="h-4 w-4" /> }`}
</button> */} onClick={() => setViewType("detailed")}
</div> >
</Tab.List> <Squares2X2Icon className="h-4 w-4" />
<Tab.Panels> </button>
<Tab.Panel> </div>
<RecentPagesList viewType={viewType} /> </Tab.List>
</Tab.Panel> <Tab.Panels as={Fragment}>
<Tab.Panel> <Tab.Panel as="div" className="h-full overflow-y-auto space-y-5">
<AllPagesList viewType={viewType} /> <RecentPagesList viewType={viewType} />
</Tab.Panel> </Tab.Panel>
<Tab.Panel> <Tab.Panel as="div" className="h-full overflow-hidden">
<FavoritePagesList viewType={viewType} /> <AllPagesList viewType={viewType} />
</Tab.Panel> </Tab.Panel>
<Tab.Panel> <Tab.Panel as="div" className="h-full overflow-hidden">
<MyPagesList viewType={viewType} /> <FavoritePagesList viewType={viewType} />
</Tab.Panel> </Tab.Panel>
<Tab.Panel> <Tab.Panel as="div" className="h-full overflow-hidden">
<OtherPagesList viewType={viewType} /> <MyPagesList viewType={viewType} />
</Tab.Panel> </Tab.Panel>
</Tab.Panels> <Tab.Panel as="div" className="h-full overflow-hidden">
</Tab.Group> <OtherPagesList viewType={viewType} />
</div> </Tab.Panel>
</Tab.Panels>
</Tab.Group>
</div> </div>
</ProjectAuthorizationWrapper> </ProjectAuthorizationWrapper>
</> </>