refactor: pages folder structure (#544)

* refactor: pages folder structure, mutation issues

* fix: block edit and push

* fix: block title placeholder
This commit is contained in:
Aaryan Khandelwal 2023-03-27 23:19:05 +05:30 committed by GitHub
parent e13b679c28
commit 3503b22dd9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 378 additions and 192 deletions

View File

@ -15,7 +15,12 @@ import { PageForm } from "./page-form";
// types // types
import { IPage } from "types"; import { IPage } from "types";
// fetch-keys // fetch-keys
import { RECENT_PAGES_LIST } from "constants/fetch-keys"; import {
ALL_PAGES_LIST,
FAVORITE_PAGES_LIST,
MY_PAGES_LIST,
RECENT_PAGES_LIST,
} from "constants/fetch-keys";
type Props = { type Props = {
isOpen: boolean; isOpen: boolean;
@ -36,8 +41,18 @@ export const CreateUpdatePageModal: React.FC<Props> = ({ isOpen, handleClose, da
const createPage = async (payload: IPage) => { const createPage = async (payload: IPage) => {
await pagesService await pagesService
.createPage(workspaceSlug as string, projectId as string, payload) .createPage(workspaceSlug as string, projectId as string, payload)
.then(() => { .then((res) => {
mutate(RECENT_PAGES_LIST(projectId as string)); mutate(RECENT_PAGES_LIST(projectId as string));
mutate<IPage[]>(
MY_PAGES_LIST(projectId as string),
(prevData) => [res, ...(prevData as IPage[])],
false
);
mutate<IPage[]>(
ALL_PAGES_LIST(projectId as string),
(prevData) => [res, ...(prevData as IPage[])],
false
);
onClose(); onClose();
setToastAlert({ setToastAlert({
@ -58,8 +73,38 @@ export const CreateUpdatePageModal: React.FC<Props> = ({ isOpen, handleClose, da
const updatePage = async (payload: IPage) => { const updatePage = async (payload: IPage) => {
await pagesService await pagesService
.patchPage(workspaceSlug as string, projectId as string, data?.id ?? "", payload) .patchPage(workspaceSlug as string, projectId as string, data?.id ?? "", payload)
.then(() => { .then((res) => {
mutate(RECENT_PAGES_LIST(projectId as string)); mutate(RECENT_PAGES_LIST(projectId as string));
mutate<IPage[]>(
FAVORITE_PAGES_LIST(projectId as string),
(prevData) =>
(prevData ?? []).map((p) => {
if (p.id === res.id) return { ...p, ...res };
return p;
}),
false
);
mutate<IPage[]>(
MY_PAGES_LIST(projectId as string),
(prevData) =>
(prevData ?? []).map((p) => {
if (p.id === res.id) return { ...p, ...res };
return p;
}),
false
);
mutate<IPage[]>(
ALL_PAGES_LIST(projectId as string),
(prevData) =>
(prevData ?? []).map((p) => {
if (p.id === res.id) return { ...p, ...res };
return p;
}),
false
);
onClose(); onClose();
setToastAlert({ setToastAlert({

View File

@ -1,12 +1,8 @@
export * from "./all-pages-list"; export * from "./pages-list";
export * from "./create-update-page-modal"; export * from "./create-update-page-modal";
export * from "./delete-page-modal"; export * from "./delete-page-modal";
export * from "./favorite-pages-list";
export * from "./my-pages-list";
export * from "./other-pages-list";
export * from "./page-form"; export * from "./page-form";
export * from "./pages-view"; export * from "./pages-view";
export * from "./recent-pages-list";
export * from "./single-page-block"; export * from "./single-page-block";
export * from "./single-page-detailed-item"; export * from "./single-page-detailed-item";
export * from "./single-page-list-item"; export * from "./single-page-list-item";

View File

@ -1,7 +1,11 @@
import { useEffect } from "react"; import { useEffect } from "react";
import { useForm } from "react-hook-form";
import dynamic from "next/dynamic";
// react-hook-form
import { Controller, useForm } from "react-hook-form";
// ui // ui
import { Input, PrimaryButton, SecondaryButton, TextArea } from "components/ui"; import { Input, Loader, PrimaryButton, SecondaryButton } from "components/ui";
// types // types
import { IPage } from "types"; import { IPage } from "types";
@ -12,6 +16,16 @@ type Props = {
data?: IPage | null; data?: IPage | null;
}; };
// rich-text-editor
const RemirrorRichTextEditor = dynamic(() => import("components/rich-text-editor"), {
ssr: false,
loading: () => (
<Loader>
<Loader.Item height="12rem" width="100%" />
</Loader>
),
});
const defaultValues = { const defaultValues = {
name: "", name: "",
description: "", description: "",
@ -23,6 +37,8 @@ export const PageForm: React.FC<Props> = ({ handleFormSubmit, handleClose, statu
formState: { errors, isSubmitting }, formState: { errors, isSubmitting },
handleSubmit, handleSubmit,
reset, reset,
control,
setValue,
} = useForm<IPage>({ } = useForm<IPage>({
defaultValues, defaultValues,
}); });
@ -68,16 +84,20 @@ export const PageForm: React.FC<Props> = ({ handleFormSubmit, handleClose, statu
}} }}
/> />
</div> </div>
<div> {/* <div>
<TextArea <Controller
id="description"
name="description" name="description"
label="Description" control={control}
placeholder="Enter description" render={({ field: { value } }) => (
error={errors.description} <RemirrorRichTextEditor
register={register} value={value}
onJSONChange={(jsonValue) => setValue("description", jsonValue)}
onHTMLChange={(htmlValue) => setValue("description_html", htmlValue)}
placeholder="Description"
/>
)}
/> />
</div> </div> */}
</div> </div>
</div> </div>
<div className="mt-5 flex justify-end gap-2"> <div className="mt-5 flex justify-end gap-2">

View File

@ -7,15 +7,11 @@ import pagesService from "services/pages.service";
// components // components
import { PagesView } from "components/pages"; import { PagesView } from "components/pages";
// types // types
import { TPageViewProps } from "types"; import { TPagesListProps } from "./types";
// fetch-keys // fetch-keys
import { ALL_PAGES_LIST } from "constants/fetch-keys"; import { ALL_PAGES_LIST } from "constants/fetch-keys";
type Props = { export const AllPagesList: React.FC<TPagesListProps> = ({ viewType }) => {
viewType: TPageViewProps;
};
export const AllPagesList: React.FC<Props> = ({ viewType }) => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;

View File

@ -7,15 +7,11 @@ import pagesService from "services/pages.service";
// components // components
import { PagesView } from "components/pages"; import { PagesView } from "components/pages";
// types // types
import { TPageViewProps } from "types"; import { TPagesListProps } from "./types";
// fetch-keys // fetch-keys
import { FAVORITE_PAGES_LIST } from "constants/fetch-keys"; import { FAVORITE_PAGES_LIST } from "constants/fetch-keys";
type Props = { export const FavoritePagesList: React.FC<TPagesListProps> = ({ viewType }) => {
viewType: TPageViewProps;
};
export const FavoritePagesList: React.FC<Props> = ({ viewType }) => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;

View File

@ -0,0 +1,6 @@
export * from "./all-pages-list";
export * from "./favorite-pages-list";
export * from "./my-pages-list";
export * from "./other-pages-list";
export * from "./recent-pages-list";
export * from "./types";

View File

@ -7,15 +7,11 @@ import pagesService from "services/pages.service";
// components // components
import { PagesView } from "components/pages"; import { PagesView } from "components/pages";
// types // types
import { TPageViewProps } from "types"; import { TPagesListProps } from "./types";
// fetch-keys // fetch-keys
import { MY_PAGES_LIST } from "constants/fetch-keys"; import { MY_PAGES_LIST } from "constants/fetch-keys";
type Props = { export const MyPagesList: React.FC<TPagesListProps> = ({ viewType }) => {
viewType: TPageViewProps;
};
export const MyPagesList: React.FC<Props> = ({ viewType }) => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;

View File

@ -7,15 +7,11 @@ import pagesService from "services/pages.service";
// components // components
import { PagesView } from "components/pages"; import { PagesView } from "components/pages";
// types // types
import { TPageViewProps } from "types"; import { TPagesListProps } from "./types";
// fetch-keys // fetch-keys
import { OTHER_PAGES_LIST } from "constants/fetch-keys"; import { OTHER_PAGES_LIST } from "constants/fetch-keys";
type Props = { export const OtherPagesList: React.FC<TPagesListProps> = ({ viewType }) => {
viewType: TPageViewProps;
};
export const OtherPagesList: React.FC<Props> = ({ viewType }) => {
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId } = router.query; const { workspaceSlug, projectId } = router.query;

View File

@ -0,0 +1,62 @@
import React from "react";
import { useRouter } from "next/router";
import useSWR from "swr";
// services
import pagesService from "services/pages.service";
// components
import { PagesView } from "components/pages";
// ui
import { Loader } from "components/ui";
// helpers
import { replaceUnderscoreIfSnakeCase } from "helpers/string.helper";
// types
import { TPagesListProps } from "./types";
import { RecentPagesResponse } from "types";
// fetch-keys
import { RECENT_PAGES_LIST } from "constants/fetch-keys";
export const RecentPagesList: React.FC<TPagesListProps> = ({ viewType }) => {
const router = useRouter();
const { workspaceSlug, projectId } = router.query;
const { data: pages } = useSWR(
workspaceSlug && projectId ? RECENT_PAGES_LIST(projectId as string) : null,
workspaceSlug && projectId
? () => pagesService.getRecentPages(workspaceSlug as string, projectId as string)
: null
);
return (
<>
{pages ? (
Object.keys(pages).length > 0 ? (
<div className="mt-4 space-y-4">
{Object.keys(pages).map((key) => {
if (pages[key].length === 0) return null;
return (
<React.Fragment key={key}>
<h2 className="text-xl font-medium capitalize">
{replaceUnderscoreIfSnakeCase(key)}
</h2>
<PagesView pages={pages[key as keyof RecentPagesResponse]} viewType={viewType} />
</React.Fragment>
);
})}
</div>
) : (
<p className="mt-4 text-center">No issues found</p>
)
) : (
<Loader className="mt-8 space-y-4">
<Loader.Item height="40px" />
<Loader.Item height="40px" />
<Loader.Item height="40px" />
</Loader>
)}
</>
);
};

View File

@ -0,0 +1,5 @@
import { TPageViewProps } from "types";
export type TPagesListProps = {
viewType: TPageViewProps;
};

View File

@ -19,6 +19,13 @@ import { EmptyState, Loader } from "components/ui";
import emptyPage from "public/empty-state/empty-page.svg"; import emptyPage from "public/empty-state/empty-page.svg";
// types // types
import { IPage, TPageViewProps } from "types"; import { IPage, TPageViewProps } from "types";
import {
ALL_PAGES_LIST,
FAVORITE_PAGES_LIST,
MY_PAGES_LIST,
RECENT_PAGES_LIST,
} from "constants/fetch-keys";
import { mutate } from "swr";
type Props = { type Props = {
pages: IPage[] | undefined; pages: IPage[] | undefined;
@ -50,6 +57,33 @@ export const PagesView: React.FC<Props> = ({ pages, viewType }) => {
const handleAddToFavorites = (page: IPage) => { const handleAddToFavorites = (page: IPage) => {
if (!workspaceSlug || !projectId) return; if (!workspaceSlug || !projectId) return;
mutate(RECENT_PAGES_LIST(projectId as string));
mutate<IPage[]>(
ALL_PAGES_LIST(projectId as string),
(prevData) =>
(prevData ?? []).map((p) => {
if (p.id === page.id) p.is_favorite = true;
return p;
}),
false
);
mutate<IPage[]>(
MY_PAGES_LIST(projectId as string),
(prevData) =>
(prevData ?? []).map((p) => {
if (p.id === page.id) p.is_favorite = true;
return p;
}),
false
);
mutate<IPage[]>(
FAVORITE_PAGES_LIST(projectId as string),
(prevData) => [page, ...(prevData as IPage[])],
false
);
pagesService pagesService
.addPageToFavorites(workspaceSlug as string, projectId as string, { .addPageToFavorites(workspaceSlug as string, projectId as string, {
page: page.id, page: page.id,
@ -73,6 +107,33 @@ export const PagesView: React.FC<Props> = ({ pages, viewType }) => {
const handleRemoveFromFavorites = (page: IPage) => { const handleRemoveFromFavorites = (page: IPage) => {
if (!workspaceSlug || !projectId) return; if (!workspaceSlug || !projectId) return;
mutate(RECENT_PAGES_LIST(projectId as string));
mutate<IPage[]>(
ALL_PAGES_LIST(projectId as string),
(prevData) =>
(prevData ?? []).map((p) => {
if (p.id === page.id) p.is_favorite = false;
return p;
}),
false
);
mutate<IPage[]>(
MY_PAGES_LIST(projectId as string),
(prevData) =>
(prevData ?? []).map((p) => {
if (p.id === page.id) p.is_favorite = false;
return p;
}),
false
);
mutate<IPage[]>(
FAVORITE_PAGES_LIST(projectId as string),
(prevData) => (prevData ?? []).filter((p) => p.id !== page.id),
false
);
pagesService pagesService
.removePageFromFavorites(workspaceSlug as string, projectId as string, page.id) .removePageFromFavorites(workspaceSlug as string, projectId as string, page.id)
.then(() => { .then(() => {

View File

@ -1,46 +0,0 @@
import React from "react";
// components
import { PagesView } from "components/pages";
// ui
import { Loader } from "components/ui";
// helpers
import { replaceUnderscoreIfSnakeCase } from "helpers/string.helper";
// types
import { RecentPagesResponse, TPageViewProps } from "types";
type Props = {
pages: RecentPagesResponse | undefined;
viewType: TPageViewProps;
};
export const RecentPagesList: React.FC<Props> = ({ pages, viewType }) => (
<>
{pages ? (
Object.keys(pages).length > 0 ? (
<div className="mt-4 space-y-4">
{Object.keys(pages).map((key) => {
if (pages[key].length === 0) return null;
return (
<React.Fragment key={key}>
<h2 className="text-xl font-medium capitalize">
{replaceUnderscoreIfSnakeCase(key)}
</h2>
<PagesView pages={pages[key as keyof RecentPagesResponse]} viewType={viewType} />
</React.Fragment>
);
})}
</div>
) : (
<p className="mt-4 text-center">No issues found</p>
)
) : (
<Loader className="mt-8 space-y-4">
<Loader.Item height="40px" />
<Loader.Item height="40px" />
<Loader.Item height="40px" />
</Loader>
)}
</>
);

View File

@ -34,7 +34,7 @@ type Props = {
const RemirrorRichTextEditor = dynamic(() => import("components/rich-text-editor"), { const RemirrorRichTextEditor = dynamic(() => import("components/rich-text-editor"), {
ssr: false, ssr: false,
loading: () => ( loading: () => (
<Loader> <Loader className="mx-4 mt-6">
<Loader.Item height="100px" width="100%" /> <Loader.Item height="100px" width="100%" />
</Loader> </Loader>
), ),
@ -149,7 +149,20 @@ export const SinglePageBlock: React.FC<Props> = ({ block, projectDetails }) => {
const handleAiAssistance = async (response: string) => { const handleAiAssistance = async (response: string) => {
if (!workspaceSlug || !projectId) return; if (!workspaceSlug || !projectId) return;
setValue("description", {}); setValue("description", {
type: "doc",
content: [
{
type: "paragraph",
content: [
{
text: response,
type: "text",
},
],
},
],
});
setValue("description_html", `<p>${response}</p>`); setValue("description_html", `<p>${response}</p>`);
handleSubmit(updatePageBlock)() handleSubmit(updatePageBlock)()
.then(() => { .then(() => {
@ -204,7 +217,7 @@ export const SinglePageBlock: React.FC<Props> = ({ block, projectDetails }) => {
<TextArea <TextArea
id="name" id="name"
name="name" name="name"
placeholder="Enter issue name" placeholder="Enter block title"
value={watch("name")} value={watch("name")}
onBlur={handleSubmit(updatePageBlock)} onBlur={handleSubmit(updatePageBlock)}
onChange={(e) => setValue("name", e.target.value)} onChange={(e) => setValue("name", e.target.value)}

View File

@ -34,72 +34,99 @@ export const SinglePageListItem: React.FC<TSingleStatProps> = ({
return ( return (
<li> <li>
<div className="relative rounded p-4 hover:bg-gray-100"> <Link href={`/${workspaceSlug}/projects/${projectId}/pages/${page.id}`}>
<div className="flex items-center justify-between"> <a>
<div className="flex items-center gap-2"> <div className="relative rounded p-4 hover:bg-gray-100">
<PencilScribbleIcon /> <div className="flex items-center justify-between">
<Link href={`/${workspaceSlug}/projects/${projectId}/pages/${page.id}`}> <div className="flex items-center gap-2">
<a> <PencilScribbleIcon />
<p className="mr-2 truncate text-sm font-medium">{truncateText(page.name, 75)}</p> <p className="mr-2 truncate text-sm font-medium">{truncateText(page.name, 75)}</p>
</a> {page.label_details.length > 0 &&
</Link> page.label_details.map((label) => (
{page.label_details.length > 0 && <div
page.label_details.map((label) => ( key={label.id}
<div className="group flex items-center gap-1 rounded-2xl border px-2 py-0.5 text-xs"
key={label.id} style={{
className="group flex items-center gap-1 rounded-2xl border px-2 py-0.5 text-xs" backgroundColor: `${
style={{ label?.color && label.color !== "" ? label.color : "#000000"
backgroundColor: `${ }20`,
label?.color && label.color !== "" ? label.color : "#000000" }}
}20`, >
}} <span
> className="h-1.5 w-1.5 flex-shrink-0 rounded-full"
<span style={{
className="h-1.5 w-1.5 flex-shrink-0 rounded-full" backgroundColor:
style={{ label?.color && label.color !== "" ? label.color : "#000000",
backgroundColor: label?.color && label.color !== "" ? label.color : "#000000", }}
}} />
/> {label.name}
{label.name} </div>
))}
</div>
<div className="ml-2 flex flex-shrink-0">
<div className="flex items-center gap-2">
<Tooltip
tooltipContent={`Last updated at ${renderShortTime(
page.updated_at
)} ${renderShortDate(page.updated_at)}`}
>
<p className="text-sm text-gray-400">{renderShortTime(page.updated_at)}</p>
</Tooltip>
{page.is_favorite ? (
<button
type="button"
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
handleRemoveFromFavorites();
}}
>
<StarIcon className="h-4 w-4 text-orange-400" fill="#f6ad55" />
</button>
) : (
<button
type="button"
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
handleAddToFavorites();
}}
>
<StarIcon className="h-4 w-4 " color="#858e96" />
</button>
)}
<CustomMenu width="auto" verticalEllipsis>
<CustomMenu.MenuItem
onClick={(e: any) => {
e.preventDefault();
e.stopPropagation();
handleEditPage();
}}
>
<span className="flex items-center justify-start gap-2 text-gray-800">
<PencilIcon className="h-3.5 w-3.5" />
<span>Edit Page</span>
</span>
</CustomMenu.MenuItem>
<CustomMenu.MenuItem
onClick={(e: any) => {
e.preventDefault();
e.stopPropagation();
handleDeletePage();
}}
>
<span className="flex items-center justify-start gap-2 text-gray-800">
<TrashIcon className="h-3.5 w-3.5" />
<span>Delete Page</span>
</span>
</CustomMenu.MenuItem>
</CustomMenu>
</div> </div>
))} </div>
</div>
<div className="ml-2 flex flex-shrink-0">
<div className="flex items-center gap-2">
<Tooltip
tooltipContent={`Last updated at ${renderShortTime(
page.updated_at
)} ${renderShortDate(page.updated_at)}`}
>
<p className="text-sm text-gray-400">{renderShortTime(page.updated_at)}</p>
</Tooltip>
{page.is_favorite ? (
<button onClick={handleRemoveFromFavorites}>
<StarIcon className="h-4 w-4 text-orange-400" fill="#f6ad55" />
</button>
) : (
<button onClick={handleAddToFavorites} type="button">
<StarIcon className="h-4 w-4 " color="#858e96" />
</button>
)}
<CustomMenu width="auto" verticalEllipsis>
<CustomMenu.MenuItem onClick={handleEditPage}>
<span className="flex items-center justify-start gap-2 text-gray-800">
<PencilIcon className="h-3.5 w-3.5" />
<span>Edit Page</span>
</span>
</CustomMenu.MenuItem>
<CustomMenu.MenuItem onClick={handleDeletePage}>
<span className="flex items-center justify-start gap-2 text-gray-800">
<TrashIcon className="h-3.5 w-3.5" />
<span>Delete Page</span>
</span>
</CustomMenu.MenuItem>
</CustomMenu>
</div> </div>
</div> </div>
</div> </a>
</div> </Link>
</li> </li>
); );
}; };

View File

@ -25,7 +25,7 @@ type MenuItemProps = {
children: JSX.Element | string; children: JSX.Element | string;
renderAs?: "button" | "a"; renderAs?: "button" | "a";
href?: string; href?: string;
onClick?: () => void; onClick?: (args?: any) => void;
className?: string; className?: string;
}; };

View File

@ -1,4 +1,4 @@
import React, { useEffect } from "react"; import React, { useEffect, useState } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
@ -43,6 +43,8 @@ import {
} from "constants/fetch-keys"; } from "constants/fetch-keys";
const SinglePage: NextPage<UserAuth> = (props) => { const SinglePage: NextPage<UserAuth> = (props) => {
const [isAddingBlock, setIsAddingBlock] = useState(false);
const router = useRouter(); const router = useRouter();
const { workspaceSlug, projectId, pageId } = router.query; const { workspaceSlug, projectId, pageId } = router.query;
@ -132,6 +134,8 @@ const SinglePage: NextPage<UserAuth> = (props) => {
const createPageBlock = async () => { const createPageBlock = async () => {
if (!workspaceSlug || !projectId || !pageId) return; if (!workspaceSlug || !projectId || !pageId) return;
setIsAddingBlock(true);
await pagesService await pagesService
.createPageBlock(workspaceSlug as string, projectId as string, pageId as string, { .createPageBlock(workspaceSlug as string, projectId as string, pageId as string, {
name: "New block", name: "New block",
@ -149,6 +153,9 @@ const SinglePage: NextPage<UserAuth> = (props) => {
title: "Error!", title: "Error!",
message: "Page could not be created. Please try again.", message: "Page could not be created. Please try again.",
}); });
})
.finally(() => {
setIsAddingBlock(false);
}); });
}; };
@ -392,17 +399,8 @@ const SinglePage: NextPage<UserAuth> = (props) => {
</div> </div>
<div className="px-3"> <div className="px-3">
{pageBlocks ? ( {pageBlocks ? (
pageBlocks.length === 0 ? ( <>
<button {pageBlocks.length !== 0 && (
type="button"
className="flex items-center gap-1 rounded px-2.5 py-1 text-xs hover:bg-gray-100"
onClick={createPageBlock}
>
<PlusIcon className="h-3 w-3" />
Add new block
</button>
) : (
<>
<div className="space-y-4"> <div className="space-y-4">
{pageBlocks.map((block) => ( {pageBlocks.map((block) => (
<SinglePageBlock <SinglePageBlock
@ -412,18 +410,23 @@ const SinglePage: NextPage<UserAuth> = (props) => {
/> />
))} ))}
</div> </div>
<div className=""> )}
<button <button
type="button" type="button"
className="flex items-center gap-1 rounded px-2.5 py-1 text-xs hover:bg-gray-100" className="flex items-center gap-1 rounded px-2.5 py-1 text-xs hover:bg-gray-100"
onClick={createPageBlock} onClick={createPageBlock}
> disabled={isAddingBlock}
>
{isAddingBlock ? (
"Adding block..."
) : (
<>
<PlusIcon className="h-3 w-3" /> <PlusIcon className="h-3 w-3" />
Add new block Add new block
</button> </>
</div> )}
</> </button>
) </>
) : ( ) : (
<Loader> <Loader>
<Loader.Item height="150px" /> <Loader.Item height="150px" />

View File

@ -4,7 +4,7 @@ import { useRouter } from "next/router";
import type { GetServerSidePropsContext, NextPage } from "next"; import type { GetServerSidePropsContext, NextPage } from "next";
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
import useSWR from "swr"; import useSWR, { mutate } from "swr";
// react-hook-form // react-hook-form
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
@ -22,7 +22,7 @@ import { PlusIcon } from "components/icons";
// layouts // layouts
import AppLayout from "layouts/app-layout"; import AppLayout from "layouts/app-layout";
// components // components
import { RecentPagesList, CreateUpdatePageModal } from "components/pages"; import { RecentPagesList, CreateUpdatePageModal, TPagesListProps } from "components/pages";
// ui // ui
import { HeaderButton, Input, PrimaryButton } from "components/ui"; import { HeaderButton, Input, PrimaryButton } from "components/ui";
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
@ -31,30 +31,35 @@ import { ListBulletIcon, RectangleGroupIcon } from "@heroicons/react/20/solid";
// types // types
import { IPage, TPageViewProps, UserAuth } from "types"; import { IPage, TPageViewProps, UserAuth } from "types";
// fetch-keys // fetch-keys
import { PROJECT_DETAILS, RECENT_PAGES_LIST } from "constants/fetch-keys"; import {
ALL_PAGES_LIST,
MY_PAGES_LIST,
PROJECT_DETAILS,
RECENT_PAGES_LIST,
} from "constants/fetch-keys";
const AllPagesList = dynamic<{ viewType: TPageViewProps }>( const AllPagesList = dynamic<TPagesListProps>(
() => import("components/pages").then((a) => a.AllPagesList), () => import("components/pages").then((a) => a.AllPagesList),
{ {
ssr: false, ssr: false,
} }
); );
const FavoritePagesList = dynamic<{ viewType: TPageViewProps }>( const FavoritePagesList = dynamic<TPagesListProps>(
() => import("components/pages").then((a) => a.FavoritePagesList), () => import("components/pages").then((a) => a.FavoritePagesList),
{ {
ssr: false, ssr: false,
} }
); );
const MyPagesList = dynamic<{ viewType: TPageViewProps }>( const MyPagesList = dynamic<TPagesListProps>(
() => import("components/pages").then((a) => a.MyPagesList), () => import("components/pages").then((a) => a.MyPagesList),
{ {
ssr: false, ssr: false,
} }
); );
const OtherPagesList = dynamic<{ viewType: TPageViewProps }>( const OtherPagesList = dynamic<TPagesListProps>(
() => import("components/pages").then((a) => a.OtherPagesList), () => import("components/pages").then((a) => a.OtherPagesList),
{ {
ssr: false, ssr: false,
@ -90,13 +95,6 @@ const ProjectPages: NextPage<UserAuth> = (props) => {
: null : null
); );
const { data: recentPages } = useSWR(
workspaceSlug && projectId ? RECENT_PAGES_LIST(projectId as string) : null,
workspaceSlug && projectId
? () => pagesService.getRecentPages(workspaceSlug as string, projectId as string)
: null
);
const createPage = async (formData: Partial<IPage>) => { const createPage = async (formData: Partial<IPage>) => {
if (!workspaceSlug || !projectId) return; if (!workspaceSlug || !projectId) return;
@ -111,13 +109,25 @@ const ProjectPages: NextPage<UserAuth> = (props) => {
await pagesService await pagesService
.createPage(workspaceSlug as string, projectId as string, formData) .createPage(workspaceSlug as string, projectId as string, formData)
.then(() => { .then((res) => {
setToastAlert({ setToastAlert({
type: "success", type: "success",
title: "Success!", title: "Success!",
message: "Page created successfully.", message: "Page created successfully.",
}); });
reset(); reset();
mutate(RECENT_PAGES_LIST(projectId as string));
mutate<IPage[]>(
MY_PAGES_LIST(projectId as string),
(prevData) => [res, ...(prevData as IPage[])],
false
);
mutate<IPage[]>(
ALL_PAGES_LIST(projectId as string),
(prevData) => [res, ...(prevData as IPage[])],
false
);
}) })
.catch(() => { .catch(() => {
setToastAlert({ setToastAlert({
@ -224,7 +234,7 @@ const ProjectPages: NextPage<UserAuth> = (props) => {
</Tab.List> </Tab.List>
<Tab.Panels> <Tab.Panels>
<Tab.Panel> <Tab.Panel>
<RecentPagesList pages={recentPages} viewType={viewType} /> <RecentPagesList viewType={viewType} />
</Tab.Panel> </Tab.Panel>
<Tab.Panel> <Tab.Panel>
<AllPagesList viewType={viewType} /> <AllPagesList viewType={viewType} />