[WEB-1135] chore: store page full width information in local storage (#4327)

* chore: store page full width information in local storage

* chore: update page types
This commit is contained in:
Aaryan Khandelwal 2024-05-01 18:10:39 +05:30 committed by GitHub
parent 73fd6e641c
commit eb0877a3c8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 32 additions and 74 deletions

View File

@ -16,14 +16,9 @@ export type TPage = {
project: string | undefined; project: string | undefined;
updated_at: Date | undefined; updated_at: Date | undefined;
updated_by: string | undefined; updated_by: string | undefined;
view_props: TPageViewProps | undefined;
workspace: string | undefined; workspace: string | undefined;
}; };
export type TPageViewProps = {
full_width?: boolean;
};
// page filters // page filters
export type TPageNavigationTabs = "public" | "private" | "archived"; export type TPageNavigationTabs = "public" | "private" | "archived";

View File

@ -18,6 +18,7 @@ import { PageContentBrowser, PageEditorTitle } from "@/components/pages";
import { cn } from "@/helpers/common.helper"; import { cn } from "@/helpers/common.helper";
// hooks // hooks
import { useMember, useMention, useUser, useWorkspace } from "@/hooks/store"; import { useMember, useMention, useUser, useWorkspace } from "@/hooks/store";
import { usePageFilters } from "@/hooks/use-page-filters";
import useReloadConfirmations from "@/hooks/use-reload-confirmation"; import useReloadConfirmations from "@/hooks/use-reload-confirmation";
// services // services
import { FileService } from "@/services/file.service"; import { FileService } from "@/services/file.service";
@ -68,7 +69,6 @@ export const PageEditorBody: React.FC<Props> = observer((props) => {
const workspaceId = workspaceSlug ? getWorkspaceBySlug(workspaceSlug.toString())?.id ?? "" : ""; const workspaceId = workspaceSlug ? getWorkspaceBySlug(workspaceSlug.toString())?.id ?? "" : "";
const pageTitle = pageStore?.name ?? ""; const pageTitle = pageStore?.name ?? "";
const pageDescription = pageStore?.description_html ?? "<p></p>"; const pageDescription = pageStore?.description_html ?? "<p></p>";
const isFullWidth = !!pageStore?.view_props?.full_width;
const { description_html, isContentEditable, updateTitle, isSubmitting, setIsSubmitting } = pageStore; const { description_html, isContentEditable, updateTitle, isSubmitting, setIsSubmitting } = pageStore;
const projectMemberIds = projectId ? getProjectMemberIds(projectId.toString()) : []; const projectMemberIds = projectId ? getProjectMemberIds(projectId.toString()) : [];
const projectMemberDetails = projectMemberIds?.map((id) => getUserDetails(id) as IUserLite); const projectMemberDetails = projectMemberIds?.map((id) => getUserDetails(id) as IUserLite);
@ -79,6 +79,8 @@ export const PageEditorBody: React.FC<Props> = observer((props) => {
members: projectMemberDetails, members: projectMemberDetails,
user: currentUser ?? undefined, user: currentUser ?? undefined,
}); });
// page filters
const { isFullWidth } = usePageFilters();
const { setShowAlert } = useReloadConfirmations(isSubmitting === "submitting"); const { setShowAlert } = useReloadConfirmations(isSubmitting === "submitting");

View File

@ -2,6 +2,8 @@ import { observer } from "mobx-react";
import { EditorReadOnlyRefApi, EditorRefApi, IMarking } from "@plane/document-editor"; import { EditorReadOnlyRefApi, EditorRefApi, IMarking } from "@plane/document-editor";
// components // components
import { PageExtraOptions, PageSummaryPopover, PageToolbar } from "@/components/pages"; import { PageExtraOptions, PageSummaryPopover, PageToolbar } from "@/components/pages";
// hooks
import { usePageFilters } from "@/hooks/use-page-filters";
// store // store
import { IPageStore } from "@/store/pages/page.store"; import { IPageStore } from "@/store/pages/page.store";
@ -34,8 +36,9 @@ export const PageEditorMobileHeaderRoot: React.FC<Props> = observer((props) => {
setSidePeekVisible, setSidePeekVisible,
} = props; } = props;
// derived values // derived values
const { isContentEditable, view_props } = pageStore; const { isContentEditable } = pageStore;
const isFullWidth = !!view_props?.full_width; // page filters
const { isFullWidth } = usePageFilters();
if (!editorRef.current && !readOnlyEditorRef.current) return null; if (!editorRef.current && !readOnlyEditorRef.current) return null;

View File

@ -4,13 +4,11 @@ import { ArchiveRestoreIcon, Clipboard, Copy, Link, Lock, LockOpen } from "lucid
import { EditorReadOnlyRefApi, EditorRefApi } from "@plane/document-editor"; import { EditorReadOnlyRefApi, EditorRefApi } from "@plane/document-editor";
// ui // ui
import { ArchiveIcon, CustomMenu, TOAST_TYPE, ToggleSwitch, setToast } from "@plane/ui"; import { ArchiveIcon, CustomMenu, TOAST_TYPE, ToggleSwitch, setToast } from "@plane/ui";
// constants
import { EUserProjectRoles } from "@/constants/project";
// helpers // helpers
import { cn } from "@/helpers/common.helper";
import { copyTextToClipboard, copyUrlToClipboard } from "@/helpers/string.helper"; import { copyTextToClipboard, copyUrlToClipboard } from "@/helpers/string.helper";
// hooks // hooks
import { useApplication, useUser } from "@/hooks/store"; import { useApplication } from "@/hooks/store";
import { usePageFilters } from "@/hooks/use-page-filters";
// store // store
import { IPageStore } from "@/store/pages/page.store"; import { IPageStore } from "@/store/pages/page.store";
@ -34,18 +32,13 @@ export const PageOptionsDropdown: React.FC<Props> = observer((props) => {
canCurrentUserDuplicatePage, canCurrentUserDuplicatePage,
canCurrentUserLockPage, canCurrentUserLockPage,
restore, restore,
view_props,
updateViewProps,
} = pageStore; } = pageStore;
// store hooks // store hooks
const { const {
router: { workspaceSlug, projectId }, router: { workspaceSlug, projectId },
} = useApplication(); } = useApplication();
const { // page filters
membership: { currentProjectRole }, const { isFullWidth, handleFullWidth } = usePageFilters();
} = useUser();
// auth
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
const handleArchivePage = async () => const handleArchivePage = async () =>
await archive().catch(() => await archive().catch(() =>
@ -149,22 +142,10 @@ export const PageOptionsDropdown: React.FC<Props> = observer((props) => {
<CustomMenu maxHeight="md" placement="bottom-start" verticalEllipsis closeOnSelect> <CustomMenu maxHeight="md" placement="bottom-start" verticalEllipsis closeOnSelect>
<CustomMenu.MenuItem <CustomMenu.MenuItem
className="hidden md:flex w-full items-center justify-between gap-2" className="hidden md:flex w-full items-center justify-between gap-2"
onClick={() => onClick={() => handleFullWidth(!isFullWidth)}
updateViewProps({
full_width: !view_props?.full_width,
})
}
disabled={!isEditingAllowed}
> >
Full width Full width
<ToggleSwitch <ToggleSwitch value={isFullWidth} onChange={() => {}} />
value={!!view_props?.full_width}
onChange={() => {}}
className={cn({
"opacity-40": !isEditingAllowed,
})}
disabled={!isEditingAllowed}
/>
</CustomMenu.MenuItem> </CustomMenu.MenuItem>
{MENU_ITEMS.map((item) => { {MENU_ITEMS.map((item) => {
if (!item.shouldRender) return null; if (!item.shouldRender) return null;

View File

@ -4,6 +4,8 @@ import { EditorReadOnlyRefApi, EditorRefApi, IMarking } from "@plane/document-ed
import { PageEditorMobileHeaderRoot, PageExtraOptions, PageSummaryPopover, PageToolbar } from "@/components/pages"; import { PageEditorMobileHeaderRoot, PageExtraOptions, PageSummaryPopover, PageToolbar } from "@/components/pages";
// helpers // helpers
import { cn } from "@/helpers/common.helper"; import { cn } from "@/helpers/common.helper";
// hooks
import { usePageFilters } from "@/hooks/use-page-filters";
// store // store
import { IPageStore } from "@/store/pages/page.store"; import { IPageStore } from "@/store/pages/page.store";
@ -36,8 +38,9 @@ export const PageEditorHeaderRoot: React.FC<Props> = observer((props) => {
setSidePeekVisible, setSidePeekVisible,
} = props; } = props;
// derived values // derived values
const { isContentEditable, view_props } = pageStore; const { isContentEditable } = pageStore;
const isFullWidth = !!view_props?.full_width; // page filters
const { isFullWidth } = usePageFilters();
if (!editorRef.current && !readOnlyEditorRef.current) return null; if (!editorRef.current && !readOnlyEditorRef.current) return null;

View File

@ -0,0 +1,12 @@
// hooks
import useLocalStorage from "@/hooks/use-local-storage";
export const usePageFilters = () => {
const { storedValue: isFullWidth, setValue: setFullWidth } = useLocalStorage<boolean>("page_full_width", true);
const handleFullWidth = (value: boolean) => setFullWidth(value);
return {
isFullWidth: !!isFullWidth,
handleFullWidth,
};
};

View File

@ -1,7 +1,7 @@
import set from "lodash/set"; import set from "lodash/set";
import { action, computed, makeObservable, observable, reaction, runInAction } from "mobx"; import { action, computed, makeObservable, observable, reaction, runInAction } from "mobx";
// types // types
import { TPage, TPageViewProps } from "@plane/types"; import { TPage } from "@plane/types";
// constants // constants
import { EPageAccess } from "@/constants/page"; import { EPageAccess } from "@/constants/page";
import { EUserProjectRoles } from "@/constants/project"; import { EUserProjectRoles } from "@/constants/project";
@ -33,7 +33,6 @@ export interface IPageStore extends TPage {
cleanup: () => void; cleanup: () => void;
// actions // actions
update: (pageData: Partial<TPage>) => Promise<TPage | undefined>; update: (pageData: Partial<TPage>) => Promise<TPage | undefined>;
updateViewProps: (viewProps: Partial<TPageViewProps>) => void;
makePublic: () => Promise<void>; makePublic: () => Promise<void>;
makePrivate: () => Promise<void>; makePrivate: () => Promise<void>;
lock: () => Promise<void>; lock: () => Promise<void>;
@ -65,7 +64,6 @@ export class PageStore implements IPageStore {
updated_by: string | undefined; updated_by: string | undefined;
created_at: Date | undefined; created_at: Date | undefined;
updated_at: Date | undefined; updated_at: Date | undefined;
view_props: TPageViewProps | undefined;
// helpers // helpers
oldName: string = ""; oldName: string = "";
// reactions // reactions
@ -93,7 +91,6 @@ export class PageStore implements IPageStore {
this.updated_by = page?.updated_by || undefined; this.updated_by = page?.updated_by || undefined;
this.created_at = page?.created_at || undefined; this.created_at = page?.created_at || undefined;
this.updated_at = page?.updated_at || undefined; this.updated_at = page?.updated_at || undefined;
this.view_props = page?.view_props || undefined;
this.oldName = page?.name || ""; this.oldName = page?.name || "";
makeObservable(this, { makeObservable(this, {
@ -117,7 +114,6 @@ export class PageStore implements IPageStore {
updated_by: observable.ref, updated_by: observable.ref,
created_at: observable.ref, created_at: observable.ref,
updated_at: observable.ref, updated_at: observable.ref,
view_props: observable,
// helpers // helpers
oldName: observable, oldName: observable,
// computed // computed
@ -137,7 +133,6 @@ export class PageStore implements IPageStore {
cleanup: action, cleanup: action,
// actions // actions
update: action, update: action,
updateViewProps: action,
makePublic: action, makePublic: action,
makePrivate: action, makePrivate: action,
lock: action, lock: action,
@ -216,7 +211,6 @@ export class PageStore implements IPageStore {
updated_by: this.updated_by, updated_by: this.updated_by,
created_at: this.created_at, created_at: this.created_at,
updated_at: this.updated_at, updated_at: this.updated_at,
view_props: this.view_props,
}; };
} }
@ -338,38 +332,6 @@ export class PageStore implements IPageStore {
} }
}; };
/**
* @description update the page view props
* @param {Partial<TPageViewProps>} updatedProps
*/
updateViewProps = async (updatedProps: Partial<TPageViewProps>) => {
const { workspaceSlug, projectId } = this.store.app.router;
if (!workspaceSlug || !projectId || !this.id) return undefined;
const currentViewProps = { ...this.view_props };
runInAction(() => {
Object.keys(updatedProps).forEach((key) => {
const currentPageKey = key as keyof TPageViewProps;
if (this.view_props) set(this.view_props, key, updatedProps[currentPageKey]);
});
});
try {
await this.pageService.update(workspaceSlug, projectId, this.id, {
view_props: {
...this.view_props,
...updatedProps,
},
});
} catch (error) {
runInAction(() => {
this.view_props = currentViewProps;
});
throw error;
}
};
/** /**
* @description make the page public * @description make the page public
*/ */