From 5e7f3a3a99255df419b388342c1319594b45d465 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia Date: Wed, 7 Aug 2024 20:24:37 +0530 Subject: [PATCH 1/9] chore: fav item drag and drop improvement --- .../sidebar/favorites/favorite-item.tsx | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/web/core/components/workspace/sidebar/favorites/favorite-item.tsx b/web/core/components/workspace/sidebar/favorites/favorite-item.tsx index 348b5c76e75..7a4bd04b8fa 100644 --- a/web/core/components/workspace/sidebar/favorites/favorite-item.tsx +++ b/web/core/components/workspace/sidebar/favorites/favorite-item.tsx @@ -4,12 +4,20 @@ import React, { useEffect, useRef, useState } from "react"; import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine"; import { draggable, dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter"; import { observer } from "mobx-react"; -import Link from "next/link"; -import { useParams } from "next/navigation"; +import { useParams, useRouter } from "next/navigation"; import { Briefcase, FileText, Layers, MoreHorizontal, Star } from "lucide-react"; // ui import { IFavorite } from "@plane/types"; -import { ContrastIcon, CustomMenu, DiceIcon, DragHandle, FavoriteFolderIcon, LayersIcon, Tooltip } from "@plane/ui"; +import { + ContrastIcon, + ControlLink, + CustomMenu, + DiceIcon, + DragHandle, + FavoriteFolderIcon, + LayersIcon, + Tooltip, +} from "@plane/ui"; // components import { Logo } from "@/components/common"; import { SidebarNavItem } from "@/components/sidebar"; @@ -52,6 +60,7 @@ export const FavoriteItem = observer( const [isMenuActive, setIsMenuActive] = useState(false); // router params + const router = useRouter(); const { workspaceSlug } = useParams(); // derived values @@ -141,14 +150,15 @@ export const FavoriteItem = observer( <> {sidebarCollapsed ? (
- router.push(getLink())} className={cn( "group/project-item cursor-pointer relative group w-full flex items-center justify-center gap-1.5 rounded px-2 py-1 outline-none text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-90 active:bg-custom-sidebar-background-90 truncate p-0 size-8 aspect-square mx-auto" )} > {getIcon()} - +
) : (
- + router.push(getLink())} + href={getLink()} + className="flex items-center gap-1.5 truncate w-full" + >
{getIcon()}
{favorite.entity_data ? favorite.entity_data.name : favorite.name} - +
Date: Thu, 8 Aug 2024 13:26:56 +0530 Subject: [PATCH 2/9] chore: user favorite type updated --- packages/types/src/favorite/favorite.d.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/types/src/favorite/favorite.d.ts b/packages/types/src/favorite/favorite.d.ts index 092a1209599..1da74b3b1a4 100644 --- a/packages/types/src/favorite/favorite.d.ts +++ b/packages/types/src/favorite/favorite.d.ts @@ -15,6 +15,7 @@ export type IFavorite = { name: string; entity_type: string; entity_data: { + id: string; name: string; logo_props?: TLogoProps | undefined; }; From 30fc6cf914c3c1af1ea6fcec48fd8c5b2478bf0c Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia Date: Thu, 8 Aug 2024 13:27:38 +0530 Subject: [PATCH 3/9] chore: user favorites helper function added --- .../favorite-items/common/helper.tsx | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 web/core/components/workspace/sidebar/favorites/favorite-items/common/helper.tsx diff --git a/web/core/components/workspace/sidebar/favorites/favorite-items/common/helper.tsx b/web/core/components/workspace/sidebar/favorites/favorite-items/common/helper.tsx new file mode 100644 index 00000000000..3f7940f90d8 --- /dev/null +++ b/web/core/components/workspace/sidebar/favorites/favorite-items/common/helper.tsx @@ -0,0 +1,51 @@ +"use client"; +// lucide +import { Briefcase, FileText, Layers } from "lucide-react"; +// types +import { IFavorite, TLogoProps } from "@plane/types"; +// ui +import { ContrastIcon, DiceIcon, FavoriteFolderIcon } from "@plane/ui"; +import { Logo } from "@/components/common"; + +const iconClassName = `flex-shrink-0 size-4 stroke-[1.5] m-auto`; + +export const FAVORITE_ITEM: Record = { + page: , + project: , + view: , + module: , + cycle: , + folder: , +}; + +export const getFavoriteItemIcon = (type: string, logo?: TLogoProps | undefined) => ( + <> +
+ {FAVORITE_ITEM[type] || } +
+
+ {logo?.in_use ? ( + + ) : ( + FAVORITE_ITEM[type] || + )} +
+ +); + +export const generateFavoriteItemLink = (workspaceSlug: string, favorite: IFavorite) => { + switch (favorite.entity_type) { + case "project": + return `/${workspaceSlug}/projects/${favorite.project_id}/issues`; + case "cycle": + return `/${workspaceSlug}/projects/${favorite.project_id}/cycles/${favorite.entity_identifier}`; + case "module": + return `/${workspaceSlug}/projects/${favorite.project_id}/modules/${favorite.entity_identifier}`; + case "view": + return `/${workspaceSlug}/projects/${favorite.project_id}/views/${favorite.entity_identifier}`; + case "page": + return `/${workspaceSlug}/projects/${favorite.project_id}/pages/${favorite.entity_identifier}`; + default: + return `/${workspaceSlug}`; + } +}; From f67a2e6f01ee463590d079b85692d6baeb599d65 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia Date: Thu, 8 Aug 2024 13:31:12 +0530 Subject: [PATCH 4/9] dev: favorite item common component added --- .../common/favorite-item-drag-handle.tsx | 42 ++++++++++++++++ .../common/favorite-item-quick-action.tsx | 48 +++++++++++++++++++ .../common/favorite-item-title.tsx | 36 ++++++++++++++ .../common/favorite-item-wrapper.tsx | 38 +++++++++++++++ .../favorite-items/common/helper.tsx | 6 +-- .../favorites/favorite-items/common/index.ts | 6 +++ 6 files changed, 173 insertions(+), 3 deletions(-) create mode 100644 web/core/components/workspace/sidebar/favorites/favorite-items/common/favorite-item-drag-handle.tsx create mode 100644 web/core/components/workspace/sidebar/favorites/favorite-items/common/favorite-item-quick-action.tsx create mode 100644 web/core/components/workspace/sidebar/favorites/favorite-items/common/favorite-item-title.tsx create mode 100644 web/core/components/workspace/sidebar/favorites/favorite-items/common/favorite-item-wrapper.tsx create mode 100644 web/core/components/workspace/sidebar/favorites/favorite-items/common/index.ts diff --git a/web/core/components/workspace/sidebar/favorites/favorite-items/common/favorite-item-drag-handle.tsx b/web/core/components/workspace/sidebar/favorites/favorite-items/common/favorite-item-drag-handle.tsx new file mode 100644 index 00000000000..d8a6568c731 --- /dev/null +++ b/web/core/components/workspace/sidebar/favorites/favorite-items/common/favorite-item-drag-handle.tsx @@ -0,0 +1,42 @@ +"use client"; +import React, { FC } from "react"; +import { observer } from "mobx-react"; +// ui +import { DragHandle, Tooltip } from "@plane/ui"; +// helper +import { cn } from "@/helpers/common.helper"; +// hooks +import { usePlatformOS } from "@/hooks/use-platform-os"; + +type Props = { + sort_order: number | null; + isDragging: boolean; +}; + +export const FavoriteItemDragHandle: FC = observer((props) => { + const { sort_order, isDragging } = props; + // store hooks + const { isMobile } = usePlatformOS(); + + return ( + + + + ); +}); diff --git a/web/core/components/workspace/sidebar/favorites/favorite-items/common/favorite-item-quick-action.tsx b/web/core/components/workspace/sidebar/favorites/favorite-items/common/favorite-item-quick-action.tsx new file mode 100644 index 00000000000..a715ae56510 --- /dev/null +++ b/web/core/components/workspace/sidebar/favorites/favorite-items/common/favorite-item-quick-action.tsx @@ -0,0 +1,48 @@ +"use client"; +import React, { FC } from "react"; +import { MoreHorizontal, Star } from "lucide-react"; +import { IFavorite } from "@plane/types"; +// ui +import { CustomMenu } from "@plane/ui"; +// helpers +import { cn } from "@/helpers/common.helper"; + +type Props = { + ref: React.MutableRefObject; + isMenuActive: boolean; + favorite: IFavorite; + setIsMenuActive: React.Dispatch>; + handleRemoveFromFavorites: (favorite: IFavorite) => void; +}; + +export const FavoriteItemQuickAction: FC = (props) => { + const { ref, isMenuActive, setIsMenuActive, handleRemoveFromFavorites, favorite } = props; + return ( + setIsMenuActive(!isMenuActive)} + > + + + } + className={cn( + "opacity-0 pointer-events-none flex-shrink-0 group-hover/project-item:opacity-100 group-hover/project-item:pointer-events-auto", + { + "opacity-100 pointer-events-auto": isMenuActive, + } + )} + customButtonClassName="grid place-items-center" + placement="bottom-start" + > + handleRemoveFromFavorites(favorite)}> + + + Remove from favorites + + + + ); +}; diff --git a/web/core/components/workspace/sidebar/favorites/favorite-items/common/favorite-item-title.tsx b/web/core/components/workspace/sidebar/favorites/favorite-items/common/favorite-item-title.tsx new file mode 100644 index 00000000000..bc7276e292f --- /dev/null +++ b/web/core/components/workspace/sidebar/favorites/favorite-items/common/favorite-item-title.tsx @@ -0,0 +1,36 @@ +"use client"; +import React, { FC } from "react"; +import Link from "next/link"; +// helpers +import { cn } from "@/helpers/common.helper"; + +type Props = { + href: string; + title: string; + icon: JSX.Element; + isSidebarCollapsed: boolean; +}; + +export const FavoriteItemTitle: FC = (props) => { + const { href, title, icon, isSidebarCollapsed } = props; + return ( + <> + {isSidebarCollapsed ? ( + + {icon} + + ) : ( + +
{icon}
+ {title} + + )} + + ); +}; diff --git a/web/core/components/workspace/sidebar/favorites/favorite-items/common/favorite-item-wrapper.tsx b/web/core/components/workspace/sidebar/favorites/favorite-items/common/favorite-item-wrapper.tsx new file mode 100644 index 00000000000..3f56a4c5586 --- /dev/null +++ b/web/core/components/workspace/sidebar/favorites/favorite-items/common/favorite-item-wrapper.tsx @@ -0,0 +1,38 @@ +"use client"; +import React, { FC } from "react"; +// helpers +import { cn } from "@/helpers/common.helper"; + +type Props = { + children: React.ReactNode; + elementRef: React.RefObject; + isMenuActive?: boolean; + sidebarCollapsed?: boolean; +}; + +export const FavoriteItemWrapper: FC = (props) => { + const { children, elementRef, isMenuActive = false, sidebarCollapsed = false } = props; + return ( + <> + {sidebarCollapsed ? ( + <> +
{children}
+ + ) : ( + <> +
+ {children} +
+ + )} + + ); +}; diff --git a/web/core/components/workspace/sidebar/favorites/favorite-items/common/helper.tsx b/web/core/components/workspace/sidebar/favorites/favorite-items/common/helper.tsx index 3f7940f90d8..cdb2248a3d0 100644 --- a/web/core/components/workspace/sidebar/favorites/favorite-items/common/helper.tsx +++ b/web/core/components/workspace/sidebar/favorites/favorite-items/common/helper.tsx @@ -9,7 +9,7 @@ import { Logo } from "@/components/common"; const iconClassName = `flex-shrink-0 size-4 stroke-[1.5] m-auto`; -export const FAVORITE_ITEM: Record = { +export const FAVORITE_ITEM_ICON: Record = { page: , project: , view: , @@ -21,13 +21,13 @@ export const FAVORITE_ITEM: Record = { export const getFavoriteItemIcon = (type: string, logo?: TLogoProps | undefined) => ( <>
- {FAVORITE_ITEM[type] || } + {FAVORITE_ITEM_ICON[type] || }
{logo?.in_use ? ( ) : ( - FAVORITE_ITEM[type] || + FAVORITE_ITEM_ICON[type] || )}
diff --git a/web/core/components/workspace/sidebar/favorites/favorite-items/common/index.ts b/web/core/components/workspace/sidebar/favorites/favorite-items/common/index.ts new file mode 100644 index 00000000000..7972210d9e3 --- /dev/null +++ b/web/core/components/workspace/sidebar/favorites/favorite-items/common/index.ts @@ -0,0 +1,6 @@ +export * from "./favorite-item-drag-handle"; +export * from "./favorite-item-icon"; +export * from "./favorite-item-quick-action"; +export * from "./favorite-item-wrapper"; +export * from "./favorite-item-title"; +export * from "./helper"; From 9f3e001f6fc42e20706e78b7eb6ee2917ed7bff6 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia Date: Thu, 8 Aug 2024 14:12:48 +0530 Subject: [PATCH 5/9] dev: favorite item component added and code refactor --- .../sidebar/favorites/favorite-item.tsx | 258 +++--------------- .../favorites/favorite-items/common/index.ts | 1 - .../favorite-items/favorite-cycle.tsx | 45 +++ .../favorite-items/favorite-module.tsx | 45 +++ .../favorite-items/favorite-page.tsx | 44 +++ .../favorite-items/favorite-project.tsx | 44 +++ .../favorite-items/favorite-view.tsx | 47 ++++ .../sidebar/favorites/favorite-items/index.ts | 7 + .../sidebar/favorites/favorite-items/root.tsx | 111 ++++++++ .../workspace/sidebar/favorites/index.ts | 5 + .../components/workspace/sidebar/index.ts | 1 + 11 files changed, 382 insertions(+), 226 deletions(-) create mode 100644 web/core/components/workspace/sidebar/favorites/favorite-items/favorite-cycle.tsx create mode 100644 web/core/components/workspace/sidebar/favorites/favorite-items/favorite-module.tsx create mode 100644 web/core/components/workspace/sidebar/favorites/favorite-items/favorite-page.tsx create mode 100644 web/core/components/workspace/sidebar/favorites/favorite-items/favorite-project.tsx create mode 100644 web/core/components/workspace/sidebar/favorites/favorite-items/favorite-view.tsx create mode 100644 web/core/components/workspace/sidebar/favorites/favorite-items/index.ts create mode 100644 web/core/components/workspace/sidebar/favorites/favorite-items/root.tsx create mode 100644 web/core/components/workspace/sidebar/favorites/index.ts diff --git a/web/core/components/workspace/sidebar/favorites/favorite-item.tsx b/web/core/components/workspace/sidebar/favorites/favorite-item.tsx index 7a4bd04b8fa..5cdbd7d85d8 100644 --- a/web/core/components/workspace/sidebar/favorites/favorite-item.tsx +++ b/web/core/components/workspace/sidebar/favorites/favorite-item.tsx @@ -1,234 +1,42 @@ "use client"; - -import React, { useEffect, useRef, useState } from "react"; -import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine"; -import { draggable, dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter"; +import { FC } from "react"; import { observer } from "mobx-react"; -import { useParams, useRouter } from "next/navigation"; -import { Briefcase, FileText, Layers, MoreHorizontal, Star } from "lucide-react"; -// ui import { IFavorite } from "@plane/types"; -import { - ContrastIcon, - ControlLink, - CustomMenu, - DiceIcon, - DragHandle, - FavoriteFolderIcon, - LayersIcon, - Tooltip, -} from "@plane/ui"; // components -import { Logo } from "@/components/common"; -import { SidebarNavItem } from "@/components/sidebar"; - -// helpers -import { cn } from "@/helpers/common.helper"; -// hooks -import { useAppTheme } from "@/hooks/store"; -import useOutsideClickDetector from "@/hooks/use-outside-click-detector"; -import { usePlatformOS } from "@/hooks/use-platform-os"; +import { FavoriteCycle, FavoriteModule, FavoritePage, FavoriteProject, FavoriteView } from "./favorite-items"; -const iconClassName = `flex-shrink-0 size-4 stroke-[1.5] m-auto`; -const ICONS: Record = { - page: , - project: , - view: , - module: , - cycle: , - issue: , - folder: , +type Props = { + favorite: IFavorite; + favoriteMap: Record; + handleRemoveFromFavorites: (favorite: IFavorite) => void; + handleRemoveFromFavoritesFolder: (favoriteId: string) => void; }; -export const FavoriteItem = observer( - ({ - favoriteMap, - favorite, - handleRemoveFromFavorites, - handleRemoveFromFavoritesFolder, - }: { - favorite: IFavorite; - favoriteMap: Record; - handleRemoveFromFavorites: (favorite: IFavorite) => void; - handleRemoveFromFavoritesFolder: (favoriteId: string) => void; - }) => { - // store hooks - const { sidebarCollapsed } = useAppTheme(); - const { isMobile } = usePlatformOS(); - //state - const [isDragging, setIsDragging] = useState(false); - const [isMenuActive, setIsMenuActive] = useState(false); - - // router params - const router = useRouter(); - const { workspaceSlug } = useParams(); - // derived values - - //ref - const elementRef = useRef(null); - const dragHandleRef = useRef(null); - const actionSectionRef = useRef(null); - - const getIcon = () => ( - <> -
- {ICONS[favorite.entity_type] || } -
-
- {favorite.entity_data?.logo_props?.in_use ? ( - - ) : ( - ICONS[favorite.entity_type] || - )} -
- - ); +type EntityType = keyof typeof favoriteComponents; - const getLink = () => { - switch (favorite.entity_type) { - case "project": - return `/${workspaceSlug}/projects/${favorite.project_id}/issues`; - case "cycle": - return `/${workspaceSlug}/projects/${favorite.project_id}/cycles/${favorite.entity_identifier}`; - case "module": - return `/${workspaceSlug}/projects/${favorite.project_id}/modules/${favorite.entity_identifier}`; - case "view": - return `/${workspaceSlug}/projects/${favorite.project_id}/views/${favorite.entity_identifier}`; - case "page": - return `/${workspaceSlug}/projects/${favorite.project_id}/pages/${favorite.entity_identifier}`; - default: - return `/${workspaceSlug}`; - } - }; - - useEffect(() => { - const element = elementRef.current; - - if (!element) return; - - return combine( - draggable({ - element, - // dragHandle: element, - canDrag: () => true, - getInitialData: () => ({ id: favorite.id, type: "CHILD" }), - onDragStart: () => { - setIsDragging(true); - }, - onDrop: () => { - setIsDragging(false); - }, - }), - dropTargetForElements({ - element, - onDragStart: () => { - setIsDragging(true); - }, - onDragEnter: () => { - setIsDragging(true); - }, - onDragLeave: () => { - setIsDragging(false); - }, - onDrop: ({ source }) => { - setIsDragging(false); - const sourceId = source?.data?.id as string | undefined; - if (!sourceId || !favoriteMap[sourceId].parent) return; - handleRemoveFromFavoritesFolder(sourceId); - }, - }) - ); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [elementRef?.current, isDragging]); - useOutsideClickDetector(actionSectionRef, () => setIsMenuActive(false)); +const favoriteComponents = { + page: FavoritePage, + project: FavoriteProject, + view: FavoriteView, + module: FavoriteModule, + cycle: FavoriteCycle, +}; - return ( - <> - {sidebarCollapsed ? ( -
- router.push(getLink())} - className={cn( - "group/project-item cursor-pointer relative group w-full flex items-center justify-center gap-1.5 rounded px-2 py-1 outline-none text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-90 active:bg-custom-sidebar-background-90 truncate p-0 size-8 aspect-square mx-auto" - )} - > - {getIcon()} - -
- ) : ( -
- - - - router.push(getLink())} - href={getLink()} - className="flex items-center gap-1.5 truncate w-full" - > -
{getIcon()}
- - {favorite.entity_data ? favorite.entity_data.name : favorite.name} - -
- setIsMenuActive(!isMenuActive)} - > - - - } - className={cn( - "opacity-0 pointer-events-none flex-shrink-0 group-hover/project-item:opacity-100 group-hover/project-item:pointer-events-auto", - { - "opacity-100 pointer-events-auto": isMenuActive, - } - )} - customButtonClassName="grid place-items-center" - placement="bottom-start" - > - handleRemoveFromFavorites(favorite)}> - - - Remove from favorites - - - -
- )} - - ); - } -); +export const FavoriteItem: FC = observer((props) => { + const { favorite, favoriteMap, handleRemoveFromFavorites, handleRemoveFromFavoritesFolder } = props; + // component based on the entity type + const FavoriteComponent = favoriteComponents[favorite.entity_type as EntityType]; + + return ( + <> + {FavoriteComponent ? ( + + ) : null} + + ); +}); diff --git a/web/core/components/workspace/sidebar/favorites/favorite-items/common/index.ts b/web/core/components/workspace/sidebar/favorites/favorite-items/common/index.ts index 7972210d9e3..5e03ce1c74f 100644 --- a/web/core/components/workspace/sidebar/favorites/favorite-items/common/index.ts +++ b/web/core/components/workspace/sidebar/favorites/favorite-items/common/index.ts @@ -1,5 +1,4 @@ export * from "./favorite-item-drag-handle"; -export * from "./favorite-item-icon"; export * from "./favorite-item-quick-action"; export * from "./favorite-item-wrapper"; export * from "./favorite-item-title"; diff --git a/web/core/components/workspace/sidebar/favorites/favorite-items/favorite-cycle.tsx b/web/core/components/workspace/sidebar/favorites/favorite-items/favorite-cycle.tsx new file mode 100644 index 00000000000..06802b31035 --- /dev/null +++ b/web/core/components/workspace/sidebar/favorites/favorite-items/favorite-cycle.tsx @@ -0,0 +1,45 @@ +"use client"; +import { FC } from "react"; +import { observer } from "mobx-react"; +import { useParams } from "next/navigation"; +import { IFavorite } from "@plane/types"; +// components +import { FavoriteRoot } from "@/components/workspace/sidebar/favorites"; +// hooks +import { useCycle } from "@/hooks/store"; +// helpers +import { generateFavoriteItemLink, getFavoriteItemIcon } from "./common"; + +type Props = { + favorite: IFavorite; + favoriteMap: Record; + handleRemoveFromFavorites: (favorite: IFavorite) => void; + handleRemoveFromFavoritesFolder: (favoriteId: string) => void; +}; + +export const FavoriteCycle: FC = observer((props) => { + const { favorite, favoriteMap, handleRemoveFromFavorites, handleRemoveFromFavoritesFolder } = props; + // router hooks + const { workspaceSlug } = useParams(); + // store hooks + const { getCycleById } = useCycle(); + // derived values + const cycleId = favorite?.entity_data?.id; + const cycleDetail = cycleId ? getCycleById(cycleId) : undefined; + + const itemIcon = getFavoriteItemIcon("cycle"); + const itemTitle = cycleDetail?.name || favorite?.entity_data?.name || favorite?.name; + const itemLink = generateFavoriteItemLink(workspaceSlug.toString(), favorite); + + return ( + + ); +}); diff --git a/web/core/components/workspace/sidebar/favorites/favorite-items/favorite-module.tsx b/web/core/components/workspace/sidebar/favorites/favorite-items/favorite-module.tsx new file mode 100644 index 00000000000..d296dfcde71 --- /dev/null +++ b/web/core/components/workspace/sidebar/favorites/favorite-items/favorite-module.tsx @@ -0,0 +1,45 @@ +"use client"; +import { FC } from "react"; +import { observer } from "mobx-react"; +import { useParams } from "next/navigation"; +import { IFavorite } from "@plane/types"; +// components +import { FavoriteRoot } from "@/components/workspace/sidebar/favorites"; +// hooks +import { useModule } from "@/hooks/store"; +// helpers +import { generateFavoriteItemLink, getFavoriteItemIcon } from "./common"; + +type Props = { + favorite: IFavorite; + favoriteMap: Record; + handleRemoveFromFavorites: (favorite: IFavorite) => void; + handleRemoveFromFavoritesFolder: (favoriteId: string) => void; +}; + +export const FavoriteModule: FC = observer((props) => { + const { favorite, favoriteMap, handleRemoveFromFavorites, handleRemoveFromFavoritesFolder } = props; + // router hooks + const { workspaceSlug } = useParams(); + // store hooks + const { getModuleById } = useModule(); + // derived values + const moduleId = favorite?.entity_data?.id; + const moduleDetail = moduleId ? getModuleById(moduleId) : undefined; + + const itemIcon = getFavoriteItemIcon("module"); + const itemTitle = moduleDetail?.name || favorite?.entity_data.name || favorite?.name; + const itemLink = generateFavoriteItemLink(workspaceSlug.toString(), favorite); + + return ( + + ); +}); diff --git a/web/core/components/workspace/sidebar/favorites/favorite-items/favorite-page.tsx b/web/core/components/workspace/sidebar/favorites/favorite-items/favorite-page.tsx new file mode 100644 index 00000000000..f836a507304 --- /dev/null +++ b/web/core/components/workspace/sidebar/favorites/favorite-items/favorite-page.tsx @@ -0,0 +1,44 @@ +"use client"; +import { FC } from "react"; +import { observer } from "mobx-react"; +import { useParams } from "next/navigation"; +import { IFavorite } from "@plane/types"; +// components +import { FavoriteRoot } from "@/components/workspace/sidebar/favorites"; +// hooks +import { usePage } from "@/hooks/store"; +// helpers +import { generateFavoriteItemLink, getFavoriteItemIcon } from "./common"; + +type Props = { + favorite: IFavorite; + favoriteMap: Record; + handleRemoveFromFavorites: (favorite: IFavorite) => void; + handleRemoveFromFavoritesFolder: (favoriteId: string) => void; +}; + +export const FavoritePage: FC = observer((props) => { + const { favorite, favoriteMap, handleRemoveFromFavorites, handleRemoveFromFavoritesFolder } = props; + // router hooks + const { workspaceSlug } = useParams(); + // store hooks + const { name, logo_props } = usePage(favorite?.entity_data?.id ?? ""); + // derived values + const logoProps = logo_props || favorite?.entity_data?.logo_props; + + const itemIcon = getFavoriteItemIcon("page", logoProps); + const itemTitle = name || favorite?.entity_data?.name || favorite?.name; + const itemLink = generateFavoriteItemLink(workspaceSlug.toString(), favorite); + + return ( + + ); +}); diff --git a/web/core/components/workspace/sidebar/favorites/favorite-items/favorite-project.tsx b/web/core/components/workspace/sidebar/favorites/favorite-items/favorite-project.tsx new file mode 100644 index 00000000000..99fb0cd79f5 --- /dev/null +++ b/web/core/components/workspace/sidebar/favorites/favorite-items/favorite-project.tsx @@ -0,0 +1,44 @@ +"use client"; +import { FC } from "react"; +import { observer } from "mobx-react"; +import { useParams } from "next/navigation"; +import { IFavorite } from "@plane/types"; +// components +import { FavoriteRoot } from "@/components/workspace/sidebar/favorites"; +// hooks +import { useProject } from "@/hooks/store"; +// helpers +import { generateFavoriteItemLink, getFavoriteItemIcon } from "./common"; + +type Props = { + favorite: IFavorite; + favoriteMap: Record; + handleRemoveFromFavorites: (favorite: IFavorite) => void; + handleRemoveFromFavoritesFolder: (favoriteId: string) => void; +}; + +export const FavoriteProject: FC = observer((props) => { + const { favorite, favoriteMap, handleRemoveFromFavorites, handleRemoveFromFavoritesFolder } = props; + // router hooks + const { workspaceSlug } = useParams(); + // store hooks + const { currentProjectDetails } = useProject(); + // derived values + const logoProps = currentProjectDetails?.logo_props || favorite?.entity_data?.logo_props; + + const itemIcon = getFavoriteItemIcon("project", logoProps); + const itemTitle = currentProjectDetails?.name || favorite?.entity_data?.name || favorite?.name; + const itemLink = generateFavoriteItemLink(workspaceSlug.toString(), favorite); + + return ( + + ); +}); diff --git a/web/core/components/workspace/sidebar/favorites/favorite-items/favorite-view.tsx b/web/core/components/workspace/sidebar/favorites/favorite-items/favorite-view.tsx new file mode 100644 index 00000000000..23845118836 --- /dev/null +++ b/web/core/components/workspace/sidebar/favorites/favorite-items/favorite-view.tsx @@ -0,0 +1,47 @@ +"use client"; +import { FC } from "react"; +import { observer } from "mobx-react"; +import { useParams } from "next/navigation"; +import { IFavorite } from "@plane/types"; +// components +import { FavoriteRoot } from "@/components/workspace/sidebar/favorites"; +// hooks +import { useProjectView } from "@/hooks/store"; +// helpers +import { generateFavoriteItemLink, getFavoriteItemIcon } from "./common"; + +type Props = { + favorite: IFavorite; + favoriteMap: Record; + handleRemoveFromFavorites: (favorite: IFavorite) => void; + handleRemoveFromFavoritesFolder: (favoriteId: string) => void; +}; + +export const FavoriteView: FC = observer((props) => { + const { favorite, favoriteMap, handleRemoveFromFavorites, handleRemoveFromFavoritesFolder } = props; + // router hooks + const { workspaceSlug } = useParams(); + // store hooks + const { getViewById } = useProjectView(); + // derived values + const viewId = favorite?.entity_data?.id; + const viewDetails = viewId ? getViewById(viewId) : undefined; + + const logoProps = viewDetails?.logo_props || favorite?.entity_data?.logo_props; + + const itemIcon = getFavoriteItemIcon("view", logoProps); + const itemTitle = viewDetails?.name || favorite?.entity_data?.name || favorite?.name; + const itemLink = generateFavoriteItemLink(workspaceSlug.toString(), favorite); + + return ( + + ); +}); diff --git a/web/core/components/workspace/sidebar/favorites/favorite-items/index.ts b/web/core/components/workspace/sidebar/favorites/favorite-items/index.ts new file mode 100644 index 00000000000..65ce7c6e6a2 --- /dev/null +++ b/web/core/components/workspace/sidebar/favorites/favorite-items/index.ts @@ -0,0 +1,7 @@ +export * from "./common"; +export * from "./favorite-cycle"; +export * from "./favorite-module"; +export * from "./favorite-page"; +export * from "./favorite-project"; +export * from "./favorite-view"; +export * from "./root"; diff --git a/web/core/components/workspace/sidebar/favorites/favorite-items/root.tsx b/web/core/components/workspace/sidebar/favorites/favorite-items/root.tsx new file mode 100644 index 00000000000..f2ffca7179f --- /dev/null +++ b/web/core/components/workspace/sidebar/favorites/favorite-items/root.tsx @@ -0,0 +1,111 @@ +"use client"; + +import React, { FC, useEffect, useRef, useState } from "react"; +import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine"; +import { draggable, dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter"; +import { observer } from "mobx-react"; +// ui +import { IFavorite } from "@plane/types"; +// components +import { + FavoriteItemDragHandle, + FavoriteItemQuickAction, + FavoriteItemWrapper, + FavoriteItemTitle, +} from "@/components/workspace/sidebar/favorites"; +// hooks +import { useAppTheme } from "@/hooks/store"; +import useOutsideClickDetector from "@/hooks/use-outside-click-detector"; + +type Props = { + itemIcon: JSX.Element; + itemTitle: string; + itemLink: string; + favorite: IFavorite; + favoriteMap: Record; + handleRemoveFromFavorites: (favorite: IFavorite) => void; + handleRemoveFromFavoritesFolder: (favoriteId: string) => void; +}; + +export const FavoriteRoot: FC = observer((props) => { + // props + const { + itemIcon, + itemTitle, + itemLink, + favorite, + favoriteMap, + handleRemoveFromFavorites, + handleRemoveFromFavoritesFolder, + } = props; + // store hooks + const { sidebarCollapsed } = useAppTheme(); + + //state + const [isDragging, setIsDragging] = useState(false); + const [isMenuActive, setIsMenuActive] = useState(false); + //ref + const elementRef = useRef(null); + const actionSectionRef = useRef(null); + + // drag and drop + useEffect(() => { + const element = elementRef.current; + + if (!element) return; + + return combine( + draggable({ + element, + dragHandle: elementRef.current, + canDrag: () => true, + getInitialData: () => ({ id: favorite.id, type: "CHILD" }), + onDragStart: () => { + setIsDragging(true); + }, + onDrop: () => { + setIsDragging(false); + }, + }), + dropTargetForElements({ + element, + onDragStart: () => { + setIsDragging(true); + }, + onDragEnter: () => { + setIsDragging(true); + }, + onDragLeave: () => { + setIsDragging(false); + }, + onDrop: ({ source }) => { + setIsDragging(false); + const sourceId = source?.data?.id as string | undefined; + if (!sourceId || !favoriteMap[sourceId].parent) return; + handleRemoveFromFavoritesFolder(sourceId); + }, + }) + ); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [elementRef?.current, isDragging]); + + useOutsideClickDetector(actionSectionRef, () => setIsMenuActive(false)); + + return ( + <> + + {!sidebarCollapsed && } + + {!sidebarCollapsed && ( + + )} + + + ); +}); diff --git a/web/core/components/workspace/sidebar/favorites/index.ts b/web/core/components/workspace/sidebar/favorites/index.ts new file mode 100644 index 00000000000..7998acef824 --- /dev/null +++ b/web/core/components/workspace/sidebar/favorites/index.ts @@ -0,0 +1,5 @@ +export * from "./favorite-folder"; +export * from "./favorite-items"; +export * from "./favorites-menu"; +export * from "./favorites.helpers"; +export * from "./new-fav-folder"; \ No newline at end of file diff --git a/web/core/components/workspace/sidebar/index.ts b/web/core/components/workspace/sidebar/index.ts index f6a930870cd..c1759bf0ff2 100644 --- a/web/core/components/workspace/sidebar/index.ts +++ b/web/core/components/workspace/sidebar/index.ts @@ -1,4 +1,5 @@ export * from "./dropdown"; +export * from "./favorites"; export * from "./help-section"; export * from "./projects-list-item"; export * from "./projects-list"; From de8a2e7d49052bc002a18cf10ee168b8742f4d63 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia Date: Thu, 8 Aug 2024 14:24:37 +0530 Subject: [PATCH 6/9] fix: build error --- packages/types/src/favorite/favorite.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/types/src/favorite/favorite.d.ts b/packages/types/src/favorite/favorite.d.ts index 1da74b3b1a4..c8ec2509de9 100644 --- a/packages/types/src/favorite/favorite.d.ts +++ b/packages/types/src/favorite/favorite.d.ts @@ -15,7 +15,7 @@ export type IFavorite = { name: string; entity_type: string; entity_data: { - id: string; + id?: string; name: string; logo_props?: TLogoProps | undefined; }; From f4ced7cbeeea77d1922663ad36a33e22a8bb3857 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia Date: Thu, 8 Aug 2024 18:08:05 +0530 Subject: [PATCH 7/9] chore: code refactor --- .../common/favorite-item-drag-handle.tsx | 5 ++-- .../common/favorite-item-quick-action.tsx | 8 ++--- .../common/favorite-item-title.tsx | 29 ++++++------------ .../common/favorite-item-wrapper.tsx | 28 ++++++++--------- .../favorite-items/common/helper.tsx | 30 +++++++++---------- .../sidebar/favorites/favorite-items/root.tsx | 4 ++- 6 files changed, 44 insertions(+), 60 deletions(-) diff --git a/web/core/components/workspace/sidebar/favorites/favorite-items/common/favorite-item-drag-handle.tsx b/web/core/components/workspace/sidebar/favorites/favorite-items/common/favorite-item-drag-handle.tsx index d8a6568c731..6c8e8666ea8 100644 --- a/web/core/components/workspace/sidebar/favorites/favorite-items/common/favorite-item-drag-handle.tsx +++ b/web/core/components/workspace/sidebar/favorites/favorite-items/common/favorite-item-drag-handle.tsx @@ -25,8 +25,7 @@ export const FavoriteItemDragHandle: FC = observer((props) => { position="top-right" disabled={isDragging} > - +
); }); diff --git a/web/core/components/workspace/sidebar/favorites/favorite-items/common/favorite-item-quick-action.tsx b/web/core/components/workspace/sidebar/favorites/favorite-items/common/favorite-item-quick-action.tsx index a715ae56510..eadaedb3458 100644 --- a/web/core/components/workspace/sidebar/favorites/favorite-items/common/favorite-item-quick-action.tsx +++ b/web/core/components/workspace/sidebar/favorites/favorite-items/common/favorite-item-quick-action.tsx @@ -11,19 +11,19 @@ type Props = { ref: React.MutableRefObject; isMenuActive: boolean; favorite: IFavorite; - setIsMenuActive: React.Dispatch>; + onChange: (value: boolean) => void; handleRemoveFromFavorites: (favorite: IFavorite) => void; }; export const FavoriteItemQuickAction: FC = (props) => { - const { ref, isMenuActive, setIsMenuActive, handleRemoveFromFavorites, favorite } = props; + const { ref, isMenuActive, onChange, handleRemoveFromFavorites, favorite } = props; return ( setIsMenuActive(!isMenuActive)} + onClick={() => onChange(!isMenuActive)} > @@ -39,7 +39,7 @@ export const FavoriteItemQuickAction: FC = (props) => { > handleRemoveFromFavorites(favorite)}> - + Remove from favorites diff --git a/web/core/components/workspace/sidebar/favorites/favorite-items/common/favorite-item-title.tsx b/web/core/components/workspace/sidebar/favorites/favorite-items/common/favorite-item-title.tsx index bc7276e292f..d8fc0d0b3bf 100644 --- a/web/core/components/workspace/sidebar/favorites/favorite-items/common/favorite-item-title.tsx +++ b/web/core/components/workspace/sidebar/favorites/favorite-items/common/favorite-item-title.tsx @@ -1,8 +1,6 @@ "use client"; import React, { FC } from "react"; import Link from "next/link"; -// helpers -import { cn } from "@/helpers/common.helper"; type Props = { href: string; @@ -13,24 +11,15 @@ type Props = { export const FavoriteItemTitle: FC = (props) => { const { href, title, icon, isSidebarCollapsed } = props; + + const linkClass = "flex items-center gap-1.5 truncate w-full"; + const collapsedClass = + "group/project-item cursor-pointer relative group w-full flex items-center justify-center gap-1.5 rounded px-2 py-1 outline-none text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-90 active:bg-custom-sidebar-background-90 truncate p-0 size-8 aspect-square mx-auto"; + return ( - <> - {isSidebarCollapsed ? ( - - {icon} - - ) : ( - -
{icon}
- {title} - - )} - + + {icon} + {!isSidebarCollapsed && {title}} + ); }; diff --git a/web/core/components/workspace/sidebar/favorites/favorite-items/common/favorite-item-wrapper.tsx b/web/core/components/workspace/sidebar/favorites/favorite-items/common/favorite-item-wrapper.tsx index 3f56a4c5586..f1ffde408ca 100644 --- a/web/core/components/workspace/sidebar/favorites/favorite-items/common/favorite-item-wrapper.tsx +++ b/web/core/components/workspace/sidebar/favorites/favorite-items/common/favorite-item-wrapper.tsx @@ -15,23 +15,19 @@ export const FavoriteItemWrapper: FC = (props) => { return ( <> {sidebarCollapsed ? ( - <> -
{children}
- +
{children}
) : ( - <> -
- {children} -
- +
+ {children} +
)} ); diff --git a/web/core/components/workspace/sidebar/favorites/favorite-items/common/helper.tsx b/web/core/components/workspace/sidebar/favorites/favorite-items/common/helper.tsx index cdb2248a3d0..8f7fb9859e2 100644 --- a/web/core/components/workspace/sidebar/favorites/favorite-items/common/helper.tsx +++ b/web/core/components/workspace/sidebar/favorites/favorite-items/common/helper.tsx @@ -21,31 +21,29 @@ export const FAVORITE_ITEM_ICON: Record = { export const getFavoriteItemIcon = (type: string, logo?: TLogoProps | undefined) => ( <>
- {FAVORITE_ITEM_ICON[type] || } + {FAVORITE_ITEM_ICON[type] || }
{logo?.in_use ? ( ) : ( - FAVORITE_ITEM_ICON[type] || + FAVORITE_ITEM_ICON[type] || )}
); +const entityPaths: Record = { + project: "issues", + cycle: "cycles", + module: "modules", + view: "views", + page: "pages", +}; + export const generateFavoriteItemLink = (workspaceSlug: string, favorite: IFavorite) => { - switch (favorite.entity_type) { - case "project": - return `/${workspaceSlug}/projects/${favorite.project_id}/issues`; - case "cycle": - return `/${workspaceSlug}/projects/${favorite.project_id}/cycles/${favorite.entity_identifier}`; - case "module": - return `/${workspaceSlug}/projects/${favorite.project_id}/modules/${favorite.entity_identifier}`; - case "view": - return `/${workspaceSlug}/projects/${favorite.project_id}/views/${favorite.entity_identifier}`; - case "page": - return `/${workspaceSlug}/projects/${favorite.project_id}/pages/${favorite.entity_identifier}`; - default: - return `/${workspaceSlug}`; - } + const entityPath = entityPaths[favorite.entity_type]; + return entityPath + ? `/${workspaceSlug}/projects/${favorite.project_id}/${entityPath}/${favorite.entity_identifier || ""}` + : `/${workspaceSlug}`; }; diff --git a/web/core/components/workspace/sidebar/favorites/favorite-items/root.tsx b/web/core/components/workspace/sidebar/favorites/favorite-items/root.tsx index f2ffca7179f..5816bafdd62 100644 --- a/web/core/components/workspace/sidebar/favorites/favorite-items/root.tsx +++ b/web/core/components/workspace/sidebar/favorites/favorite-items/root.tsx @@ -48,6 +48,8 @@ export const FavoriteRoot: FC = observer((props) => { const elementRef = useRef(null); const actionSectionRef = useRef(null); + const handleQuickAction = (value: boolean) => setIsMenuActive(value); + // drag and drop useEffect(() => { const element = elementRef.current; @@ -101,7 +103,7 @@ export const FavoriteRoot: FC = observer((props) => { favorite={favorite} ref={actionSectionRef} isMenuActive={isMenuActive} - setIsMenuActive={setIsMenuActive} + onChange={handleQuickAction} handleRemoveFromFavorites={handleRemoveFromFavorites} /> )} From f4895b962e7d3905c155864b00e87461cd4b6a19 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia Date: Thu, 8 Aug 2024 19:17:42 +0530 Subject: [PATCH 8/9] chore: code refactor --- .../sidebar/favorites/favorite-folder.tsx | 5 +- .../sidebar/favorites/favorite-item.tsx | 42 -------------- .../favorite-items/favorite-cycle.tsx | 45 -------------- .../favorite-items/favorite-item-detail.tsx | 34 +++++++++++ .../favorite-items/favorite-module.tsx | 45 -------------- .../favorite-items/favorite-page.tsx | 44 -------------- .../favorite-items/favorite-project.tsx | 44 -------------- .../favorite-items/favorite-view.tsx | 47 --------------- .../sidebar/favorites/favorite-items/index.ts | 6 +- .../sidebar/favorites/favorites-menu.tsx | 5 +- web/core/hooks/use-favorite-item-details.tsx | 58 +++++++++++++++++++ 11 files changed, 99 insertions(+), 276 deletions(-) delete mode 100644 web/core/components/workspace/sidebar/favorites/favorite-item.tsx delete mode 100644 web/core/components/workspace/sidebar/favorites/favorite-items/favorite-cycle.tsx create mode 100644 web/core/components/workspace/sidebar/favorites/favorite-items/favorite-item-detail.tsx delete mode 100644 web/core/components/workspace/sidebar/favorites/favorite-items/favorite-module.tsx delete mode 100644 web/core/components/workspace/sidebar/favorites/favorite-items/favorite-page.tsx delete mode 100644 web/core/components/workspace/sidebar/favorites/favorite-items/favorite-project.tsx delete mode 100644 web/core/components/workspace/sidebar/favorites/favorite-items/favorite-view.tsx create mode 100644 web/core/hooks/use-favorite-item-details.tsx diff --git a/web/core/components/workspace/sidebar/favorites/favorite-folder.tsx b/web/core/components/workspace/sidebar/favorites/favorite-folder.tsx index 046bd4f81fc..766928f95e9 100644 --- a/web/core/components/workspace/sidebar/favorites/favorite-folder.tsx +++ b/web/core/components/workspace/sidebar/favorites/favorite-folder.tsx @@ -20,7 +20,7 @@ import { useFavorite } from "@/hooks/store/use-favorite"; import useOutsideClickDetector from "@/hooks/use-outside-click-detector"; import { usePlatformOS } from "@/hooks/use-platform-os"; // constants -import { FavoriteItem } from "./favorite-item"; +import { FavoriteItemDetail } from "./favorite-items/favorite-item-detail"; import { getDestinationStateSequence } from "./favorites.helpers"; import { NewFavoriteFolder } from "./new-fav-folder"; @@ -314,7 +314,8 @@ export const FavoriteFolder: React.FC = (props) => { })} > {favorite.children.map((child) => ( - ; - handleRemoveFromFavorites: (favorite: IFavorite) => void; - handleRemoveFromFavoritesFolder: (favoriteId: string) => void; -}; - -type EntityType = keyof typeof favoriteComponents; - -const favoriteComponents = { - page: FavoritePage, - project: FavoriteProject, - view: FavoriteView, - module: FavoriteModule, - cycle: FavoriteCycle, -}; - -export const FavoriteItem: FC = observer((props) => { - const { favorite, favoriteMap, handleRemoveFromFavorites, handleRemoveFromFavoritesFolder } = props; - // component based on the entity type - const FavoriteComponent = favoriteComponents[favorite.entity_type as EntityType]; - - return ( - <> - {FavoriteComponent ? ( - - ) : null} - - ); -}); diff --git a/web/core/components/workspace/sidebar/favorites/favorite-items/favorite-cycle.tsx b/web/core/components/workspace/sidebar/favorites/favorite-items/favorite-cycle.tsx deleted file mode 100644 index 06802b31035..00000000000 --- a/web/core/components/workspace/sidebar/favorites/favorite-items/favorite-cycle.tsx +++ /dev/null @@ -1,45 +0,0 @@ -"use client"; -import { FC } from "react"; -import { observer } from "mobx-react"; -import { useParams } from "next/navigation"; -import { IFavorite } from "@plane/types"; -// components -import { FavoriteRoot } from "@/components/workspace/sidebar/favorites"; -// hooks -import { useCycle } from "@/hooks/store"; -// helpers -import { generateFavoriteItemLink, getFavoriteItemIcon } from "./common"; - -type Props = { - favorite: IFavorite; - favoriteMap: Record; - handleRemoveFromFavorites: (favorite: IFavorite) => void; - handleRemoveFromFavoritesFolder: (favoriteId: string) => void; -}; - -export const FavoriteCycle: FC = observer((props) => { - const { favorite, favoriteMap, handleRemoveFromFavorites, handleRemoveFromFavoritesFolder } = props; - // router hooks - const { workspaceSlug } = useParams(); - // store hooks - const { getCycleById } = useCycle(); - // derived values - const cycleId = favorite?.entity_data?.id; - const cycleDetail = cycleId ? getCycleById(cycleId) : undefined; - - const itemIcon = getFavoriteItemIcon("cycle"); - const itemTitle = cycleDetail?.name || favorite?.entity_data?.name || favorite?.name; - const itemLink = generateFavoriteItemLink(workspaceSlug.toString(), favorite); - - return ( - - ); -}); diff --git a/web/core/components/workspace/sidebar/favorites/favorite-items/favorite-item-detail.tsx b/web/core/components/workspace/sidebar/favorites/favorite-items/favorite-item-detail.tsx new file mode 100644 index 00000000000..5ac13267f6e --- /dev/null +++ b/web/core/components/workspace/sidebar/favorites/favorite-items/favorite-item-detail.tsx @@ -0,0 +1,34 @@ +"use client"; +import { FC } from "react"; +import { observer } from "mobx-react"; +import { IFavorite } from "@plane/types"; +// components +import { FavoriteRoot } from "@/components/workspace/sidebar/favorites"; +// hooks +import { useFavoriteItemDetails } from "@/hooks/use-favorite-item-details"; + +type Props = { + workspaceSlug: string; + favorite: IFavorite; + favoriteMap: Record; + handleRemoveFromFavorites: (favorite: IFavorite) => void; + handleRemoveFromFavoritesFolder: (favoriteId: string) => void; +}; + +export const FavoriteItemDetail: FC = observer((props) => { + const { workspaceSlug, favorite, favoriteMap, handleRemoveFromFavorites, handleRemoveFromFavoritesFolder } = props; + // hooks + const { itemLink, itemIcon, itemTitle } = useFavoriteItemDetails(workspaceSlug, favorite); + + return ( + + ); +}); diff --git a/web/core/components/workspace/sidebar/favorites/favorite-items/favorite-module.tsx b/web/core/components/workspace/sidebar/favorites/favorite-items/favorite-module.tsx deleted file mode 100644 index d296dfcde71..00000000000 --- a/web/core/components/workspace/sidebar/favorites/favorite-items/favorite-module.tsx +++ /dev/null @@ -1,45 +0,0 @@ -"use client"; -import { FC } from "react"; -import { observer } from "mobx-react"; -import { useParams } from "next/navigation"; -import { IFavorite } from "@plane/types"; -// components -import { FavoriteRoot } from "@/components/workspace/sidebar/favorites"; -// hooks -import { useModule } from "@/hooks/store"; -// helpers -import { generateFavoriteItemLink, getFavoriteItemIcon } from "./common"; - -type Props = { - favorite: IFavorite; - favoriteMap: Record; - handleRemoveFromFavorites: (favorite: IFavorite) => void; - handleRemoveFromFavoritesFolder: (favoriteId: string) => void; -}; - -export const FavoriteModule: FC = observer((props) => { - const { favorite, favoriteMap, handleRemoveFromFavorites, handleRemoveFromFavoritesFolder } = props; - // router hooks - const { workspaceSlug } = useParams(); - // store hooks - const { getModuleById } = useModule(); - // derived values - const moduleId = favorite?.entity_data?.id; - const moduleDetail = moduleId ? getModuleById(moduleId) : undefined; - - const itemIcon = getFavoriteItemIcon("module"); - const itemTitle = moduleDetail?.name || favorite?.entity_data.name || favorite?.name; - const itemLink = generateFavoriteItemLink(workspaceSlug.toString(), favorite); - - return ( - - ); -}); diff --git a/web/core/components/workspace/sidebar/favorites/favorite-items/favorite-page.tsx b/web/core/components/workspace/sidebar/favorites/favorite-items/favorite-page.tsx deleted file mode 100644 index f836a507304..00000000000 --- a/web/core/components/workspace/sidebar/favorites/favorite-items/favorite-page.tsx +++ /dev/null @@ -1,44 +0,0 @@ -"use client"; -import { FC } from "react"; -import { observer } from "mobx-react"; -import { useParams } from "next/navigation"; -import { IFavorite } from "@plane/types"; -// components -import { FavoriteRoot } from "@/components/workspace/sidebar/favorites"; -// hooks -import { usePage } from "@/hooks/store"; -// helpers -import { generateFavoriteItemLink, getFavoriteItemIcon } from "./common"; - -type Props = { - favorite: IFavorite; - favoriteMap: Record; - handleRemoveFromFavorites: (favorite: IFavorite) => void; - handleRemoveFromFavoritesFolder: (favoriteId: string) => void; -}; - -export const FavoritePage: FC = observer((props) => { - const { favorite, favoriteMap, handleRemoveFromFavorites, handleRemoveFromFavoritesFolder } = props; - // router hooks - const { workspaceSlug } = useParams(); - // store hooks - const { name, logo_props } = usePage(favorite?.entity_data?.id ?? ""); - // derived values - const logoProps = logo_props || favorite?.entity_data?.logo_props; - - const itemIcon = getFavoriteItemIcon("page", logoProps); - const itemTitle = name || favorite?.entity_data?.name || favorite?.name; - const itemLink = generateFavoriteItemLink(workspaceSlug.toString(), favorite); - - return ( - - ); -}); diff --git a/web/core/components/workspace/sidebar/favorites/favorite-items/favorite-project.tsx b/web/core/components/workspace/sidebar/favorites/favorite-items/favorite-project.tsx deleted file mode 100644 index 99fb0cd79f5..00000000000 --- a/web/core/components/workspace/sidebar/favorites/favorite-items/favorite-project.tsx +++ /dev/null @@ -1,44 +0,0 @@ -"use client"; -import { FC } from "react"; -import { observer } from "mobx-react"; -import { useParams } from "next/navigation"; -import { IFavorite } from "@plane/types"; -// components -import { FavoriteRoot } from "@/components/workspace/sidebar/favorites"; -// hooks -import { useProject } from "@/hooks/store"; -// helpers -import { generateFavoriteItemLink, getFavoriteItemIcon } from "./common"; - -type Props = { - favorite: IFavorite; - favoriteMap: Record; - handleRemoveFromFavorites: (favorite: IFavorite) => void; - handleRemoveFromFavoritesFolder: (favoriteId: string) => void; -}; - -export const FavoriteProject: FC = observer((props) => { - const { favorite, favoriteMap, handleRemoveFromFavorites, handleRemoveFromFavoritesFolder } = props; - // router hooks - const { workspaceSlug } = useParams(); - // store hooks - const { currentProjectDetails } = useProject(); - // derived values - const logoProps = currentProjectDetails?.logo_props || favorite?.entity_data?.logo_props; - - const itemIcon = getFavoriteItemIcon("project", logoProps); - const itemTitle = currentProjectDetails?.name || favorite?.entity_data?.name || favorite?.name; - const itemLink = generateFavoriteItemLink(workspaceSlug.toString(), favorite); - - return ( - - ); -}); diff --git a/web/core/components/workspace/sidebar/favorites/favorite-items/favorite-view.tsx b/web/core/components/workspace/sidebar/favorites/favorite-items/favorite-view.tsx deleted file mode 100644 index 23845118836..00000000000 --- a/web/core/components/workspace/sidebar/favorites/favorite-items/favorite-view.tsx +++ /dev/null @@ -1,47 +0,0 @@ -"use client"; -import { FC } from "react"; -import { observer } from "mobx-react"; -import { useParams } from "next/navigation"; -import { IFavorite } from "@plane/types"; -// components -import { FavoriteRoot } from "@/components/workspace/sidebar/favorites"; -// hooks -import { useProjectView } from "@/hooks/store"; -// helpers -import { generateFavoriteItemLink, getFavoriteItemIcon } from "./common"; - -type Props = { - favorite: IFavorite; - favoriteMap: Record; - handleRemoveFromFavorites: (favorite: IFavorite) => void; - handleRemoveFromFavoritesFolder: (favoriteId: string) => void; -}; - -export const FavoriteView: FC = observer((props) => { - const { favorite, favoriteMap, handleRemoveFromFavorites, handleRemoveFromFavoritesFolder } = props; - // router hooks - const { workspaceSlug } = useParams(); - // store hooks - const { getViewById } = useProjectView(); - // derived values - const viewId = favorite?.entity_data?.id; - const viewDetails = viewId ? getViewById(viewId) : undefined; - - const logoProps = viewDetails?.logo_props || favorite?.entity_data?.logo_props; - - const itemIcon = getFavoriteItemIcon("view", logoProps); - const itemTitle = viewDetails?.name || favorite?.entity_data?.name || favorite?.name; - const itemLink = generateFavoriteItemLink(workspaceSlug.toString(), favorite); - - return ( - - ); -}); diff --git a/web/core/components/workspace/sidebar/favorites/favorite-items/index.ts b/web/core/components/workspace/sidebar/favorites/favorite-items/index.ts index 65ce7c6e6a2..71ca71b6acc 100644 --- a/web/core/components/workspace/sidebar/favorites/favorite-items/index.ts +++ b/web/core/components/workspace/sidebar/favorites/favorite-items/index.ts @@ -1,7 +1,3 @@ export * from "./common"; -export * from "./favorite-cycle"; -export * from "./favorite-module"; -export * from "./favorite-page"; -export * from "./favorite-project"; -export * from "./favorite-view"; +export * from "./favorite-item-detail"; export * from "./root"; diff --git a/web/core/components/workspace/sidebar/favorites/favorites-menu.tsx b/web/core/components/workspace/sidebar/favorites/favorites-menu.tsx index d4a18fc402a..42c3545cb15 100644 --- a/web/core/components/workspace/sidebar/favorites/favorites-menu.tsx +++ b/web/core/components/workspace/sidebar/favorites/favorites-menu.tsx @@ -22,7 +22,7 @@ import useLocalStorage from "@/hooks/use-local-storage"; import { usePlatformOS } from "@/hooks/use-platform-os"; // plane web components import { FavoriteFolder } from "./favorite-folder"; -import { FavoriteItem } from "./favorite-item"; +import { FavoriteItemDetail } from "./favorite-items/favorite-item-detail"; import { NewFavoriteFolder } from "./new-fav-folder"; export const SidebarFavoritesMenu = observer(() => { @@ -196,7 +196,8 @@ export const SidebarFavoritesMenu = observer(() => { handleRemoveFromFavoritesFolder={handleRemoveFromFavoritesFolder} /> ) : ( - { + const favoriteItemId = favorite.entity_data.id; + const favoriteItemLogoProps = favorite?.entity_data?.logo_props; + const favoriteItemName = favorite?.entity_data.name || favorite?.name; + const favoriteItemEntityType = favorite?.entity_type; + + // store hooks + const { getViewById } = useProjectView(); + const { currentProjectDetails } = useProject(); + const { getCycleById } = useCycle(); + const { getModuleById } = useModule(); + + // derived values + const pageDetail = usePage(favoriteItemId ?? ""); + const viewDetails = getViewById(favoriteItemId ?? ""); + const cycleDetail = getCycleById(favoriteItemId ?? ""); + const moduleDetail = getModuleById(favoriteItemId ?? ""); + + let itemIcon; + let itemTitle; + const itemLink = generateFavoriteItemLink(workspaceSlug.toString(), favorite); + + switch (favoriteItemEntityType) { + case "project": + itemTitle = currentProjectDetails?.name || favoriteItemName; + itemIcon = getFavoriteItemIcon("project", currentProjectDetails?.logo_props || favoriteItemLogoProps); + break; + case "page": + itemTitle = pageDetail.name || favoriteItemName; + itemIcon = getFavoriteItemIcon("page", pageDetail?.logo_props || favoriteItemLogoProps); + break; + case "view": + itemTitle = viewDetails?.name || favoriteItemName; + itemIcon = getFavoriteItemIcon("view", viewDetails?.logo_props || favoriteItemLogoProps); + break; + case "cycle": + itemTitle = cycleDetail?.name || favoriteItemName; + itemIcon = getFavoriteItemIcon("cycle"); + break; + case "module": + itemTitle = moduleDetail?.name || favoriteItemName; + itemIcon = getFavoriteItemIcon("module"); + break; + default: + itemTitle = favoriteItemName; + itemIcon = getFavoriteItemIcon(favoriteItemEntityType); + break; + } + + return { itemIcon, itemTitle, itemLink }; +}; From 6cb4f2cdbab393eefbf6649a8e6b1c3183103189 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia Date: Thu, 8 Aug 2024 19:52:01 +0530 Subject: [PATCH 9/9] chore: code refactor --- .../sidebar/favorites/favorite-folder.tsx | 6 ++-- .../favorite-items/favorite-item-detail.tsx | 34 ------------------- .../sidebar/favorites/favorite-items/index.ts | 1 - .../sidebar/favorites/favorite-items/root.tsx | 17 +++------- .../sidebar/favorites/favorites-menu.tsx | 4 +-- 5 files changed, 10 insertions(+), 52 deletions(-) delete mode 100644 web/core/components/workspace/sidebar/favorites/favorite-items/favorite-item-detail.tsx diff --git a/web/core/components/workspace/sidebar/favorites/favorite-folder.tsx b/web/core/components/workspace/sidebar/favorites/favorite-folder.tsx index 766928f95e9..63a683c5fc3 100644 --- a/web/core/components/workspace/sidebar/favorites/favorite-folder.tsx +++ b/web/core/components/workspace/sidebar/favorites/favorite-folder.tsx @@ -20,7 +20,7 @@ import { useFavorite } from "@/hooks/store/use-favorite"; import useOutsideClickDetector from "@/hooks/use-outside-click-detector"; import { usePlatformOS } from "@/hooks/use-platform-os"; // constants -import { FavoriteItemDetail } from "./favorite-items/favorite-item-detail"; +import { FavoriteRoot } from "./favorite-items"; import { getDestinationStateSequence } from "./favorites.helpers"; import { NewFavoriteFolder } from "./new-fav-folder"; @@ -314,9 +314,9 @@ export const FavoriteFolder: React.FC = (props) => { })} > {favorite.children.map((child) => ( - ; - handleRemoveFromFavorites: (favorite: IFavorite) => void; - handleRemoveFromFavoritesFolder: (favoriteId: string) => void; -}; - -export const FavoriteItemDetail: FC = observer((props) => { - const { workspaceSlug, favorite, favoriteMap, handleRemoveFromFavorites, handleRemoveFromFavoritesFolder } = props; - // hooks - const { itemLink, itemIcon, itemTitle } = useFavoriteItemDetails(workspaceSlug, favorite); - - return ( - - ); -}); diff --git a/web/core/components/workspace/sidebar/favorites/favorite-items/index.ts b/web/core/components/workspace/sidebar/favorites/favorite-items/index.ts index 71ca71b6acc..1037372f379 100644 --- a/web/core/components/workspace/sidebar/favorites/favorite-items/index.ts +++ b/web/core/components/workspace/sidebar/favorites/favorite-items/index.ts @@ -1,3 +1,2 @@ export * from "./common"; -export * from "./favorite-item-detail"; export * from "./root"; diff --git a/web/core/components/workspace/sidebar/favorites/favorite-items/root.tsx b/web/core/components/workspace/sidebar/favorites/favorite-items/root.tsx index 5816bafdd62..b001b7f69de 100644 --- a/web/core/components/workspace/sidebar/favorites/favorite-items/root.tsx +++ b/web/core/components/workspace/sidebar/favorites/favorite-items/root.tsx @@ -15,12 +15,11 @@ import { } from "@/components/workspace/sidebar/favorites"; // hooks import { useAppTheme } from "@/hooks/store"; +import { useFavoriteItemDetails } from "@/hooks/use-favorite-item-details"; import useOutsideClickDetector from "@/hooks/use-outside-click-detector"; type Props = { - itemIcon: JSX.Element; - itemTitle: string; - itemLink: string; + workspaceSlug: string; favorite: IFavorite; favoriteMap: Record; handleRemoveFromFavorites: (favorite: IFavorite) => void; @@ -29,15 +28,7 @@ type Props = { export const FavoriteRoot: FC = observer((props) => { // props - const { - itemIcon, - itemTitle, - itemLink, - favorite, - favoriteMap, - handleRemoveFromFavorites, - handleRemoveFromFavoritesFolder, - } = props; + const { workspaceSlug, favorite, favoriteMap, handleRemoveFromFavorites, handleRemoveFromFavoritesFolder } = props; // store hooks const { sidebarCollapsed } = useAppTheme(); @@ -50,6 +41,8 @@ export const FavoriteRoot: FC = observer((props) => { const handleQuickAction = (value: boolean) => setIsMenuActive(value); + const { itemLink, itemIcon, itemTitle } = useFavoriteItemDetails(workspaceSlug, favorite); + // drag and drop useEffect(() => { const element = elementRef.current; diff --git a/web/core/components/workspace/sidebar/favorites/favorites-menu.tsx b/web/core/components/workspace/sidebar/favorites/favorites-menu.tsx index 42c3545cb15..17380b079cc 100644 --- a/web/core/components/workspace/sidebar/favorites/favorites-menu.tsx +++ b/web/core/components/workspace/sidebar/favorites/favorites-menu.tsx @@ -22,7 +22,7 @@ import useLocalStorage from "@/hooks/use-local-storage"; import { usePlatformOS } from "@/hooks/use-platform-os"; // plane web components import { FavoriteFolder } from "./favorite-folder"; -import { FavoriteItemDetail } from "./favorite-items/favorite-item-detail"; +import { FavoriteRoot } from "./favorite-items"; import { NewFavoriteFolder } from "./new-fav-folder"; export const SidebarFavoritesMenu = observer(() => { @@ -196,7 +196,7 @@ export const SidebarFavoritesMenu = observer(() => { handleRemoveFromFavoritesFolder={handleRemoveFromFavoritesFolder} /> ) : ( -