From 6b8585febde42b22c79c5392e456b7988e98515a Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal Date: Wed, 4 Sep 2024 14:30:42 +0530 Subject: [PATCH] chore: add favorites option inside a page --- .../pages/editor/header/extra-options.tsx | 68 +++++++++---------- .../pages/list/block-item-action.tsx | 30 ++++---- web/core/store/pages/page.ts | 10 +++ 3 files changed, 57 insertions(+), 51 deletions(-) diff --git a/web/core/components/pages/editor/header/extra-options.tsx b/web/core/components/pages/editor/header/extra-options.tsx index b0493fc3041..5654a431e62 100644 --- a/web/core/components/pages/editor/header/extra-options.tsx +++ b/web/core/components/pages/editor/header/extra-options.tsx @@ -1,20 +1,17 @@ "use client"; -import { useState } from "react"; import { observer } from "mobx-react"; -import { CircleAlert, Sparkle } from "lucide-react"; +import { CircleAlert } from "lucide-react"; // editor import { EditorReadOnlyRefApi, EditorRefApi } from "@plane/editor"; // ui -import { ArchiveIcon, Tooltip } from "@plane/ui"; +import { ArchiveIcon, FavoriteStar, setToast, TOAST_TYPE, Tooltip } from "@plane/ui"; // components -import { GptAssistantPopover } from "@/components/core"; import { LockedComponent } from "@/components/icons/locked-component"; import { PageInfoPopover, PageOptionsDropdown } from "@/components/pages"; // helpers import { renderFormattedDate } from "@/helpers/date-time.helper"; // hooks -import { useInstance } from "@/hooks/store"; import useOnlineStatus from "@/hooks/use-online-status"; // store import { IPage } from "@/store/pages/page"; @@ -29,18 +26,37 @@ type Props = { export const PageExtraOptions: React.FC = observer((props) => { const { editorRef, handleDuplicatePage, hasConnectionFailed, page, readOnlyEditorRef } = props; - // states - const [gptModalOpen, setGptModal] = useState(false); - // store hooks - const { config } = useInstance(); // derived values - const { archived_at, isContentEditable, is_locked } = page; + const { + archived_at, + isContentEditable, + is_favorite, + is_locked, + canCurrentUserFavoritePage, + addToFavorites, + removePageFromFavorites, + } = page; // use online status const { isOnline } = useOnlineStatus(); - - const handleAiAssistance = async (response: string) => { - if (!editorRef) return; - editorRef.current?.setEditorValueAtCursorPosition(response); + // favorite handler + const handleFavorite = () => { + if (is_favorite) { + removePageFromFavorites().then(() => + setToast({ + type: TOAST_TYPE.SUCCESS, + title: "Success!", + message: "Page removed from favorites.", + }) + ); + } else { + addToFavorites().then(() => + setToast({ + type: TOAST_TYPE.SUCCESS, + title: "Success!", + message: "Page added to favorites.", + }) + ); + } }; return ( @@ -74,28 +90,8 @@ export const PageExtraOptions: React.FC = observer((props) => { )} - {isContentEditable && config?.has_openai_configured && ( - { - setGptModal((prevData) => !prevData); - // this is done so that the title do not reset after gpt popover closed - // reset(getValues()); - }} - onResponse={handleAiAssistance} - placement="top-end" - button={ - - } - className="!min-w-[38rem]" - /> + {canCurrentUserFavoritePage && ( + )} = observer((props) => { const { workspaceSlug, projectId, pageId, parentRef } = props; - // store hooks const page = usePage(pageId); const { getUserDetails } = useMember(); - const { getProjectById } = useProject(); - // derived values - const { access, created_at, is_favorite, owned_by, addToFavorites, removePageFromFavorites } = page; - - // derived values - const project = getProjectById(projectId); - const isViewerOrGuest = - project?.member_role && [EUserProjectRoles.VIEWER, EUserProjectRoles.GUEST].includes(project.member_role); + const { + access, + created_at, + is_favorite, + owned_by, + canCurrentUserFavoritePage, + addToFavorites, + removePageFromFavorites, + } = page; const ownerDetails = owned_by ? getUserDetails(owned_by) : undefined; // handlers const handleFavorites = () => { - if (is_favorite) + if (is_favorite) { removePageFromFavorites().then(() => setToast({ type: TOAST_TYPE.SUCCESS, @@ -48,7 +46,7 @@ export const BlockItemAction: FC = observer((props) => { message: "Page removed from favorites.", }) ); - else + } else { addToFavorites().then(() => setToast({ type: TOAST_TYPE.SUCCESS, @@ -56,7 +54,9 @@ export const BlockItemAction: FC = observer((props) => { message: "Page added to favorites.", }) ); + } }; + return ( <> {/* page details */} @@ -81,7 +81,7 @@ export const BlockItemAction: FC = observer((props) => { {/* favorite/unfavorite */} - {!isViewerOrGuest && ( + {canCurrentUserFavoritePage && ( { e.preventDefault(); diff --git a/web/core/store/pages/page.ts b/web/core/store/pages/page.ts index 47096912656..d7f28c0f884 100644 --- a/web/core/store/pages/page.ts +++ b/web/core/store/pages/page.ts @@ -24,6 +24,7 @@ export interface IPage extends TPage { canCurrentUserChangeAccess: boolean; canCurrentUserArchivePage: boolean; canCurrentUserDeletePage: boolean; + canCurrentUserFavoritePage: boolean; isContentEditable: boolean; // helpers oldName: string; @@ -133,6 +134,7 @@ export class Page implements IPage { canCurrentUserChangeAccess: computed, canCurrentUserArchivePage: computed, canCurrentUserDeletePage: computed, + canCurrentUserFavoritePage: computed, isContentEditable: computed, // actions update: action, @@ -255,6 +257,14 @@ export class Page implements IPage { return this.isCurrentUserOwner || currentUserProjectRole === EUserProjectRoles.ADMIN; } + /** + * @description returns true if the current logged in user can favorite the page + */ + get canCurrentUserFavoritePage() { + const currentUserProjectRole = this.store.user.membership.currentProjectRole; + return !!currentUserProjectRole && currentUserProjectRole >= EUserProjectRoles.MEMBER; + } + /** * @description returns true if the page can be edited */