feat: project user preference for pages (#1673)
* feat: project user preference for pages * feat: page block description improvement * fix: create block input box
This commit is contained in:
parent
89e7975821
commit
6769d1139e
5 changed files with 144 additions and 13 deletions
|
|
@ -28,7 +28,7 @@ import { CreateLabelModal } from "components/labels";
|
|||
import { CreateBlock } from "components/pages/create-block";
|
||||
// ui
|
||||
import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
|
||||
import { CustomSearchSelect, Loader, PrimaryButton, TextArea, Tooltip } from "components/ui";
|
||||
import { CustomSearchSelect, Loader, TextArea, ToggleSwitch, Tooltip } from "components/ui";
|
||||
// icons
|
||||
import {
|
||||
ArrowLeftIcon,
|
||||
|
|
@ -38,6 +38,7 @@ import {
|
|||
StarIcon,
|
||||
LinkIcon,
|
||||
XMarkIcon,
|
||||
ChevronDownIcon,
|
||||
} from "@heroicons/react/24/outline";
|
||||
import { ColorPalletteIcon, ClipboardIcon } from "components/icons";
|
||||
// helpers
|
||||
|
|
@ -46,18 +47,20 @@ import { copyTextToClipboard } from "helpers/string.helper";
|
|||
import { orderArrayBy } from "helpers/array.helper";
|
||||
// types
|
||||
import type { NextPage } from "next";
|
||||
import { IIssueLabels, IPage, IPageBlock } from "types";
|
||||
import { IIssueLabels, IPage, IPageBlock, IProjectMember } from "types";
|
||||
// fetch-keys
|
||||
import {
|
||||
PAGE_BLOCKS_LIST,
|
||||
PAGE_DETAILS,
|
||||
PROJECT_DETAILS,
|
||||
PROJECT_ISSUE_LABELS,
|
||||
USER_PROJECT_VIEW,
|
||||
} from "constants/fetch-keys";
|
||||
|
||||
const SinglePage: NextPage = () => {
|
||||
const [createBlockForm, setCreateBlockForm] = useState(false);
|
||||
const [labelModal, setLabelModal] = useState(false);
|
||||
const [showBlock, setShowBlock] = useState(false);
|
||||
|
||||
const scrollToRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
|
|
@ -110,6 +113,13 @@ const SinglePage: NextPage = () => {
|
|||
: null
|
||||
);
|
||||
|
||||
const { data: memberDetails } = useSWR(
|
||||
workspaceSlug && projectId ? USER_PROJECT_VIEW(projectId.toString()) : null,
|
||||
workspaceSlug && projectId
|
||||
? () => projectService.projectMemberMe(workspaceSlug.toString(), projectId.toString())
|
||||
: null
|
||||
);
|
||||
|
||||
const updatePage = async (formData: IPage) => {
|
||||
if (!workspaceSlug || !projectId || !pageId) return;
|
||||
|
||||
|
|
@ -264,6 +274,43 @@ const SinglePage: NextPage = () => {
|
|||
});
|
||||
}, [setCreateBlockForm, scrollToRef]);
|
||||
|
||||
const handleShowBlockToggle = async () => {
|
||||
if (!workspaceSlug || !projectId) return;
|
||||
|
||||
const payload: Partial<IProjectMember> = {
|
||||
preferences: {
|
||||
pages: {
|
||||
block_display: !showBlock,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
mutate<IProjectMember>(
|
||||
(workspaceSlug as string) && (projectId as string)
|
||||
? USER_PROJECT_VIEW(projectId as string)
|
||||
: null,
|
||||
(prevData) => {
|
||||
if (!prevData) return prevData;
|
||||
|
||||
return {
|
||||
...prevData,
|
||||
...payload,
|
||||
};
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
await projectService
|
||||
.setProjectView(workspaceSlug as string, projectId as string, payload)
|
||||
.catch(() => {
|
||||
setToastAlert({
|
||||
type: "error",
|
||||
title: "Error!",
|
||||
message: "Something went wrong. Please try again.",
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const options =
|
||||
labels?.map((label) => ({
|
||||
value: label.id,
|
||||
|
|
@ -289,6 +336,11 @@ const SinglePage: NextPage = () => {
|
|||
});
|
||||
}, [reset, pageDetails]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!memberDetails) return;
|
||||
setShowBlock(memberDetails.preferences.pages.block_display);
|
||||
}, [memberDetails]);
|
||||
|
||||
return (
|
||||
<ProjectAuthorizationWrapper
|
||||
breadcrumbs={
|
||||
|
|
@ -403,6 +455,49 @@ const SinglePage: NextPage = () => {
|
|||
>
|
||||
<p className="text-sm">{render24HourFormatTime(pageDetails.updated_at)}</p>
|
||||
</Tooltip>
|
||||
<Popover className="relative">
|
||||
{({ open }) => (
|
||||
<>
|
||||
<Popover.Button
|
||||
className={`group flex items-center gap-2 rounded-md border border-custom-sidebar-border-200 bg-transparent px-2 py-1 text-xs hover:bg-custom-sidebar-background-90 hover:text-custom-sidebar-text-100 focus:outline-none duration-300 ${
|
||||
open
|
||||
? "bg-custom-sidebar-background-90 text-custom-sidebar-text-100"
|
||||
: "text-custom-sidebar-text-200"
|
||||
}`}
|
||||
>
|
||||
View
|
||||
<ChevronDownIcon className="h-3 w-3" aria-hidden="true" />
|
||||
</Popover.Button>
|
||||
|
||||
<Transition
|
||||
as={React.Fragment}
|
||||
enter="transition ease-out duration-200"
|
||||
enterFrom="opacity-0 translate-y-1"
|
||||
enterTo="opacity-100 translate-y-0"
|
||||
leave="transition ease-in duration-150"
|
||||
leaveFrom="opacity-100 translate-y-0"
|
||||
leaveTo="opacity-0 translate-y-1"
|
||||
>
|
||||
<Popover.Panel className="absolute right-0 z-30 mt-1 w-screen max-w-xs transform rounded-lg border border-custom-border-200 bg-custom-background-90 p-3 shadow-lg">
|
||||
<div className="relative divide-y-2 divide-custom-border-200">
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm text-custom-text-200">
|
||||
Show full block content
|
||||
</span>
|
||||
<ToggleSwitch
|
||||
value={showBlock}
|
||||
onChange={(value) => {
|
||||
setShowBlock(value);
|
||||
handleShowBlockToggle();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Popover.Panel>
|
||||
</Transition>
|
||||
</>
|
||||
)}
|
||||
</Popover>
|
||||
<button className="flex items-center gap-2" onClick={handleCopyText}>
|
||||
<LinkIcon className="h-4 w-4" />
|
||||
</button>
|
||||
|
|
@ -528,6 +623,7 @@ const SinglePage: NextPage = () => {
|
|||
key={block.id}
|
||||
block={block}
|
||||
projectDetails={projectDetails}
|
||||
showBlockDetails={showBlock}
|
||||
index={index}
|
||||
user={user}
|
||||
/>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue