From 69323f4164753e5d6b793991495eaecaed36987b Mon Sep 17 00:00:00 2001 From: Prateek Shourya Date: Tue, 18 Nov 2025 13:52:29 +0530 Subject: [PATCH] [WEB-5442] fix: favorites list on workspace switch (#8131) --- .../sidebar/favorites/favorite-folder.tsx | 6 +- apps/web/core/store/favorite.store.ts | 75 +++++++++++++------ packages/types/src/favorite/favorite.ts | 1 + 3 files changed, 58 insertions(+), 24 deletions(-) diff --git a/apps/web/core/components/workspace/sidebar/favorites/favorite-folder.tsx b/apps/web/core/components/workspace/sidebar/favorites/favorite-folder.tsx index b718a7f0a..7b7970123 100644 --- a/apps/web/core/components/workspace/sidebar/favorites/favorite-folder.tsx +++ b/apps/web/core/components/workspace/sidebar/favorites/favorite-folder.tsx @@ -45,7 +45,7 @@ type Props = { export const FavoriteFolder: React.FC = (props) => { const { favorite, handleRemoveFromFavorites, isLastChild, handleDrop } = props; // store hooks - const { getGroupedFavorites } = useFavorite(); + const { fetchGroupedFavorites } = useFavorite(); const { isMobile } = usePlatformOS(); const { workspaceSlug } = useParams(); // states @@ -61,9 +61,9 @@ export const FavoriteFolder: React.FC = (props) => { useEffect(() => { if (favorite.children === undefined && workspaceSlug) { - getGroupedFavorites(workspaceSlug.toString(), favorite.id); + fetchGroupedFavorites(workspaceSlug.toString(), favorite.id); } - }, [favorite.id, favorite.children, workspaceSlug, getGroupedFavorites]); + }, [favorite.id, favorite.children, workspaceSlug, fetchGroupedFavorites]); useEffect(() => { const element = elementRef.current; diff --git a/apps/web/core/store/favorite.store.ts b/apps/web/core/store/favorite.store.ts index 2fce54b63..69af5c514 100644 --- a/apps/web/core/store/favorite.store.ts +++ b/apps/web/core/store/favorite.store.ts @@ -7,7 +7,6 @@ import type { CoreRootStore } from "./root.store"; export interface IFavoriteStore { // observables - favoriteIds: string[]; favoriteMap: { [favoriteId: string]: IFavorite; @@ -24,7 +23,7 @@ export interface IFavoriteStore { addFavorite: (workspaceSlug: string, data: Partial) => Promise; updateFavorite: (workspaceSlug: string, favoriteId: string, data: Partial) => Promise; deleteFavorite: (workspaceSlug: string, favoriteId: string) => Promise; - getGroupedFavorites: (workspaceSlug: string, favoriteId: string) => Promise; + fetchGroupedFavorites: (workspaceSlug: string, favoriteId: string) => Promise; moveFavoriteToFolder: (workspaceSlug: string, favoriteId: string, data: Partial) => Promise; removeFavoriteEntity: (workspaceSlug: string, entityId: string) => Promise; reOrderFavorite: ( @@ -48,6 +47,7 @@ export class FavoriteStore implements IFavoriteStore { } = {}; // service favoriteService; + rootStore; viewStore; projectStore; pageStore; @@ -61,13 +61,14 @@ export class FavoriteStore implements IFavoriteStore { entityMap: observable, favoriteIds: observable, //computed + currentWorkspaceFavorites: computed, existingFolders: computed, groupedFavorites: computed, // action fetchFavorite: action, // CRUD actions addFavorite: action, - getGroupedFavorites: action, + fetchGroupedFavorites: action, moveFavoriteToFolder: action, removeFavoriteEntity: action, reOrderFavorite: action, @@ -75,6 +76,7 @@ export class FavoriteStore implements IFavoriteStore { removeFromFavoriteFolder: action, }); this.favoriteService = new FavoriteService(); + this.rootStore = _rootStore; this.viewStore = _rootStore.projectView; this.projectStore = _rootStore.projectRoot.project; this.moduleStore = _rootStore.module; @@ -82,12 +84,26 @@ export class FavoriteStore implements IFavoriteStore { this.pageStore = _rootStore.projectPages; } + get currentWorkspaceFavorites() { + const currentWorkspace = this.rootStore.workspaceRoot.currentWorkspace; + if (!currentWorkspace) return {}; + return Object.values(this.favoriteMap) + .filter((fav: IFavorite) => fav.workspace_id === currentWorkspace.id) + .reduce( + (acc, fav) => { + acc[fav.id] = fav; + return acc; + }, + {} as { [favoriteId: string]: IFavorite } + ); + } + get existingFolders() { return Object.values(this.favoriteMap).map((fav) => fav.name); } get groupedFavorites() { - const data: { [favoriteId: string]: IFavorite } = JSON.parse(JSON.stringify(this.favoriteMap)); + const data: { [favoriteId: string]: IFavorite } = JSON.parse(JSON.stringify(this.currentWorkspaceFavorites)); Object.values(data).forEach((fav) => { if (fav.parent && data[fav.parent]) { @@ -118,7 +134,9 @@ export class FavoriteStore implements IFavoriteStore { // optimistic addition runInAction(() => { set(this.favoriteMap, [id], data); - data.entity_identifier && set(this.entityMap, [data.entity_identifier], data); + if (data.entity_identifier) { + set(this.entityMap, [data.entity_identifier], data); + } this.favoriteIds = [id, ...this.favoriteIds]; }); const response = await this.favoriteService.addFavorite(workspaceSlug, data); @@ -127,13 +145,19 @@ export class FavoriteStore implements IFavoriteStore { runInAction(() => { delete this.favoriteMap[id]; set(this.favoriteMap, [response.id], response); - response.entity_identifier && set(this.entityMap, [response.entity_identifier], response); + if (response.entity_identifier) { + set(this.entityMap, [response.entity_identifier], response); + } this.favoriteIds = [response.id, ...this.favoriteIds.filter((favId) => favId !== id)]; }); return response; } catch (error) { - delete this.favoriteMap[id]; - data.entity_identifier && delete this.entityMap[data.entity_identifier]; + runInAction(() => { + delete this.favoriteMap[id]; + if (data.entity_identifier) { + delete this.entityMap[data.entity_identifier]; + } + }); this.favoriteIds = this.favoriteIds.filter((favId) => favId !== id); console.error("Failed to create favorite from favorite store"); @@ -281,11 +305,15 @@ export class FavoriteStore implements IFavoriteStore { await this.favoriteService.deleteFavorite(workspaceSlug, favoriteId); runInAction(() => { delete this.favoriteMap[favoriteId]; - entity_identifier && delete this.entityMap[entity_identifier]; + if (entity_identifier) { + delete this.entityMap[entity_identifier]; + } this.favoriteIds = this.favoriteIds.filter((id) => id !== favoriteId); }); runInAction(() => { - entity_identifier && this.removeFavoriteEntityFromStore(entity_identifier, initialState.entity_type); + if (entity_identifier) { + this.removeFavoriteEntityFromStore(entity_identifier, initialState.entity_type); + } if (children) { children.forEach((child) => { if (!child.entity_identifier) return; @@ -298,7 +326,9 @@ export class FavoriteStore implements IFavoriteStore { runInAction(() => { if (parent) set(this.favoriteMap, [parent, "children"], [...this.favoriteMap[parent].children, initialState]); set(this.favoriteMap, [favoriteId], initialState); - entity_identifier && set(this.entityMap, [entity_identifier], initialState); + if (entity_identifier) { + set(this.entityMap, [entity_identifier], initialState); + } this.favoriteIds = [favoriteId, ...this.favoriteIds]; }); throw error; @@ -333,16 +363,20 @@ export class FavoriteStore implements IFavoriteStore { (fav) => fav.project_id === entity_identifier && fav.entity_type !== "project" ); runInAction(() => { - projectData && + if (projectData) { projectData.forEach(async (fav) => { - this.removeFavoriteFromStore(fav.entity_identifier!); - this.removeFavoriteEntityFromStore(fav.entity_identifier!, fav.entity_type); + if (fav.entity_identifier) { + this.removeFavoriteFromStore(fav.entity_identifier); + this.removeFavoriteEntityFromStore(fav.entity_identifier, fav.entity_type); + } }); + } if (!favoriteId) return; delete this.favoriteMap[favoriteId]; - this.removeFavoriteEntityFromStore(entity_identifier!, oldData.entity_type); - + if (entity_identifier) { + this.removeFavoriteEntityFromStore(entity_identifier, oldData.entity_type); + } delete this.entityMap[entity_identifier]; this.favoriteIds = this.favoriteIds.filter((id) => id !== favoriteId); }); @@ -357,7 +391,7 @@ export class FavoriteStore implements IFavoriteStore { * @param favoriteId * @returns Promise */ - getGroupedFavorites = async (workspaceSlug: string, favoriteId: string) => { + fetchGroupedFavorites = async (workspaceSlug: string, favoriteId: string) => { if (!favoriteId) return []; try { const response = await this.favoriteService.getGroupedFavorites(workspaceSlug, favoriteId); @@ -386,15 +420,14 @@ export class FavoriteStore implements IFavoriteStore { */ fetchFavorite = async (workspaceSlug: string) => { try { - this.favoriteIds = []; - this.favoriteMap = {}; - this.entityMap = {}; const favorites = await this.favoriteService.getFavorites(workspaceSlug); runInAction(() => { favorites.forEach((favorite) => { set(this.favoriteMap, [favorite.id], favorite); this.favoriteIds.push(favorite.id); - favorite.entity_identifier && set(this.entityMap, [favorite.entity_identifier], favorite); + if (favorite.entity_identifier) { + set(this.entityMap, [favorite.entity_identifier], favorite); + } }); }); return favorites; diff --git a/packages/types/src/favorite/favorite.ts b/packages/types/src/favorite/favorite.ts index b5404167e..6191c579f 100644 --- a/packages/types/src/favorite/favorite.ts +++ b/packages/types/src/favorite/favorite.ts @@ -16,4 +16,5 @@ export type IFavorite = { children: IFavorite[]; project_id: string | null; sequence: number; + workspace_id: string; };