diff --git a/packages/types/src/home.d.ts b/packages/types/src/home.d.ts index 4dc320bda2..52d057a10c 100644 --- a/packages/types/src/home.d.ts +++ b/packages/types/src/home.d.ts @@ -67,3 +67,10 @@ export type TLinkMap = { export type TLinkIdMap = { [workspace_slug: string]: string[]; }; + +export type TWidgetEntityData = { + key: string; + name: string; + is_enabled: boolean; + sort_order: number; +}; diff --git a/web/core/components/home/home-dashboard-widgets.tsx b/web/core/components/home/home-dashboard-widgets.tsx index 57940d0fca..c7daac656f 100644 --- a/web/core/components/home/home-dashboard-widgets.tsx +++ b/web/core/components/home/home-dashboard-widgets.tsx @@ -1,15 +1,15 @@ import { observer } from "mobx-react"; import { useParams } from "next/navigation"; // types -import { THomeWidgetKeys, THomeWidgetProps, TWidgetKeys } from "@plane/types"; +import { THomeWidgetKeys, THomeWidgetProps } from "@plane/types"; // hooks import { useHome } from "@/hooks/store/use-home"; // components import { HomePageHeader } from "@/plane-web/components/home/header"; +import { StickiesWidget } from "@/plane-web/components/stickies"; import { RecentActivityWidget } from "./widgets"; import { DashboardQuickLinks } from "./widgets/links"; import { ManageWidgetsModal } from "./widgets/manage"; -import { StickiesWidget } from "@/plane-web/components/stickies"; const WIDGETS_LIST: { [key in THomeWidgetKeys]: { component: React.FC; fullWidth: boolean }; diff --git a/web/core/components/home/user-greetings.tsx b/web/core/components/home/user-greetings.tsx index 24c66ddaca..c30f9cdd29 100644 --- a/web/core/components/home/user-greetings.tsx +++ b/web/core/components/home/user-greetings.tsx @@ -50,14 +50,14 @@ export const UserGreetingsView: FC = (props) => { {weekDay}, {date} {timeString} - {" "} - + */} ); }; diff --git a/web/core/services/workspace.service.ts b/web/core/services/workspace.service.ts index 6c3885c488..a4d2e7fdcc 100644 --- a/web/core/services/workspace.service.ts +++ b/web/core/services/workspace.service.ts @@ -15,6 +15,7 @@ import { TLink, TSearchResponse, TSearchEntityRequestPayload, + TWidgetEntityData, } from "@plane/types"; import { APIService } from "@/services/api.service"; // helpers @@ -306,7 +307,7 @@ export class WorkspaceService extends APIService { }); } - async deleteWorkspaceLink(workspaceSlug: string, linkId: string): Promise { + async deleteWorkspaceLink(workspaceSlug: string, linkId: string): Promise { return this.delete(`/api/workspaces/${workspaceSlug}/quick-links/${linkId}/`) .then((response) => response?.data) .catch((error) => { @@ -339,4 +340,25 @@ export class WorkspaceService extends APIService { throw error?.response; }); } + + // widgets + async fetchWorkspaceWidgets(workspaceSlug: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/home-preferences/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } + + async updateWorkspaceWidget( + workspaceSlug: string, + widgetKey: string, + data: Partial + ): Promise { + return this.patch(`/api/workspaces/${workspaceSlug}/home-preferences/${widgetKey}/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response; + }); + } } diff --git a/web/core/store/workspace/home.ts b/web/core/store/workspace/home.ts index 355bdd86a2..48166bf654 100644 --- a/web/core/store/workspace/home.ts +++ b/web/core/store/workspace/home.ts @@ -1,22 +1,28 @@ +import orderBy from "lodash/orderBy"; +import set from "lodash/set"; import { action, makeObservable, observable, runInAction } from "mobx"; -import { IWorkspaceLinkStore, WorkspaceLinkStore } from "./link.store"; +import { TWidgetEntityData } from "@plane/types"; import { WorkspaceService } from "@/plane-web/services"; +import { IWorkspaceLinkStore, WorkspaceLinkStore } from "./link.store"; export interface IHomeStore { // observables showWidgetSettings: boolean; - widgetsMap: Record; + widgetsMap: Record; //stores quickLinks: IWorkspaceLinkStore; // actions toggleWidgetSettings: (value?: boolean) => void; - reorderWidgets: (workspaceSlug: string, widgetId: string, destinationId: string, edge: string | undefined) => void; + fetchWidgets: (workspaceSlug: string) => Promise; + reorderWidget: (workspaceSlug: string, widgetKey: string, destinationId: string, edge: string | undefined) => void; + toggleWidget: (workspaceSlug: string, widgetKey: string, is_enabled: boolean) => void; } export class HomeStore implements IHomeStore { // observables showWidgetSettings = false; - widgetsMap: Record = {}; + widgetsMap: Record = {}; + widgets: string[] = []; // stores quickLinks: IWorkspaceLinkStore; // services @@ -27,9 +33,12 @@ export class HomeStore implements IHomeStore { // observables showWidgetSettings: observable, widgetsMap: observable, + widgets: observable, // actions toggleWidgetSettings: action, - reorderWidgets: action, + fetchWidgets: action, + reorderWidget: action, + toggleWidget: action, }); // services this.workspaceService = new WorkspaceService(); @@ -42,44 +51,64 @@ export class HomeStore implements IHomeStore { this.showWidgetSettings = value !== undefined ? value : !this.showWidgetSettings; }; - reorderWidgets = async (workspaceSlug: string, widgetId: string, destinationId: string, edge: string | undefined) => { - // try { - // let resultSequence = 10000; - // if (edge) { - // const sortedIds = orderBy(Object.values(this.favoriteMap), "sequence", "desc").map((fav) => fav.id); - // const destinationSequence = this.favoriteMap[destinationId]?.sequence || undefined; - // if (destinationSequence) { - // const destinationIndex = sortedIds.findIndex((id) => id === destinationId); - // if (edge === "reorder-above") { - // const prevSequence = this.favoriteMap[sortedIds[destinationIndex - 1]]?.sequence || undefined; - // if (prevSequence) { - // resultSequence = (destinationSequence + prevSequence) / 2; - // } else { - // resultSequence = destinationSequence + resultSequence; - // } - // } else { - // resultSequence = destinationSequence - resultSequence; - // } - // } - // } - // await this.dashboardService.updateDashboardWidget(workspaceSlug, dashboardId, widgetId, { - // sequence: resultSequence, - // }); - // runInAction(() => { - // set(this.favoriteMap, [favoriteId, "sequence"], resultSequence); - // }); - // } catch (error) { - // console.error("Failed to move favorite folder"); - // throw error; - // } + fetchWidgets = async (workspaceSlug: string) => { + try { + const widgets = await this.workspaceService.fetchWorkspaceWidgets(workspaceSlug); + runInAction(() => { + this.widgets = widgets.map((widget) => widget.key); + widgets.forEach((widget) => { + this.widgetsMap[widget.key] = widget; + }); + }); + } catch (error) { + console.error("Failed to fetch widgets"); + throw error; + } }; - // fetchRecentActivity = async (workspaceSlug: string) => { - // try { - // const response = await this.workspaceService.fetchWorkspaceRecents(workspaceSlug); - // } catch (error) { - // console.error("Failed to fetch recent activity"); - // throw error; - // } - // }; + toggleWidget = async (workspaceSlug: string, widgetKey: string, is_enabled: boolean) => { + try { + await this.workspaceService.updateWorkspaceWidget(workspaceSlug, widgetKey, { + is_enabled, + }); + runInAction(() => { + this.widgetsMap[widgetKey].is_enabled = is_enabled; + }); + } catch (error) { + console.error("Failed to toggle widget"); + throw error; + } + }; + + reorderWidget = async (workspaceSlug: string, widgetKey: string, destinationId: string, edge: string | undefined) => { + try { + let resultSequence = 10000; + if (edge) { + const sortedIds = orderBy(Object.values(this.widgetsMap), "sort_order", "desc").map((widget) => widget.key); + const destinationSequence = this.widgetsMap[destinationId]?.sort_order || undefined; + if (destinationSequence) { + const destinationIndex = sortedIds.findIndex((id) => id === destinationId); + if (edge === "reorder-above") { + const prevSequence = this.widgetsMap[sortedIds[destinationIndex - 1]]?.sort_order || undefined; + if (prevSequence) { + resultSequence = (destinationSequence + prevSequence) / 2; + } else { + resultSequence = destinationSequence + resultSequence; + } + } else { + resultSequence = destinationSequence - resultSequence; + } + } + } + await this.workspaceService.updateWorkspaceWidget(workspaceSlug, widgetKey, { + sort_order: resultSequence, + }); + runInAction(() => { + set(this.widgetsMap, [widgetKey, "sort_order"], resultSequence); + }); + } catch (error) { + console.error("Failed to move widget"); + throw error; + } + }; }