import { observable, action, computed, makeObservable, runInAction } from "mobx"; import isYesterday from "date-fns/isYesterday"; import isToday from "date-fns/isToday"; import isThisWeek from "date-fns/isThisWeek"; // services import { ProjectService } from "services/project"; import { PageService } from "services/page.service"; // helpers import { renderDateFormat } from "helpers/date-time.helper"; // types import { RootStore } from "./root"; import { IPage, IRecentPages } from "types"; export interface IPageStore { loader: boolean; error: any | null; pages: { [project_id: string]: IPage[]; }; archivedPages: { [project_id: string]: IPage[]; }; //computed projectPages: IPage[] | undefined; recentProjectPages: IRecentPages | undefined; favoriteProjectPages: IPage[] | undefined; privateProjectPages: IPage[] | undefined; sharedProjectPages: IPage[] | undefined; archivedProjectPages: IPage[] | undefined; // actions fetchPages: (workspaceSlug: string, projectId: string) => Promise; createPage: (workspaceSlug: string, projectId: string, data: Partial) => Promise; updatePage: (workspaceSlug: string, projectId: string, pageId: string, data: Partial) => Promise; deletePage: (workspaceSlug: string, projectId: string, pageId: string) => Promise; addToFavorites: (workspaceSlug: string, projectId: string, pageId: string) => Promise; removeFromFavorites: (workspaceSlug: string, projectId: string, pageId: string) => Promise; makePublic: (workspaceSlug: string, projectId: string, pageId: string) => Promise; makePrivate: (workspaceSlug: string, projectId: string, pageId: string) => Promise; fetchArchivedPages: (workspaceSlug: string, projectId: string) => Promise; archivePage: (workspaceSlug: string, projectId: string, pageId: string) => Promise; restorePage: (workspaceSlug: string, projectId: string, pageId: string) => Promise; } export class PageStore implements IPageStore { loader: boolean = false; error: any | null = null; pages: { [project_id: string]: IPage[] } = {}; archivedPages: { [project_id: string]: IPage[] } = {}; // root store rootStore; // service projectService; pageService; constructor(_rootStore: RootStore) { makeObservable(this, { // observable loader: observable, error: observable, pages: observable.ref, archivedPages: observable.ref, // computed projectPages: computed, recentProjectPages: computed, favoriteProjectPages: computed, privateProjectPages: computed, sharedProjectPages: computed, archivedProjectPages: computed, // action fetchPages: action, createPage: action, updatePage: action, deletePage: action, addToFavorites: action, removeFromFavorites: action, makePublic: action, makePrivate: action, archivePage: action, restorePage: action, fetchArchivedPages: action, }); this.rootStore = _rootStore; this.projectService = new ProjectService(); this.pageService = new PageService(); } get projectPages() { if (!this.rootStore.project.projectId) return; return this.pages?.[this.rootStore.project.projectId] || []; } get recentProjectPages() { if (!this.rootStore.project.projectId) return; const data: IRecentPages = { today: [], yesterday: [], this_week: [] }; data["today"] = this.pages[this.rootStore.project.projectId]?.filter((p) => isToday(new Date(p.created_at))) || []; data["yesterday"] = this.pages[this.rootStore.project.projectId]?.filter((p) => isYesterday(new Date(p.created_at))) || []; data["this_week"] = this.pages[this.rootStore.project.projectId]?.filter((p) => isThisWeek(new Date(p.created_at))) || []; return data; } get favoriteProjectPages() { if (!this.rootStore.project.projectId) return; return this.pages[this.rootStore.project.projectId]?.filter((p) => p.is_favorite); } get privateProjectPages() { if (!this.rootStore.project.projectId) return; return this.pages[this.rootStore.project.projectId]?.filter((p) => p.access === 1); } get sharedProjectPages() { if (!this.rootStore.project.projectId) return; return this.pages[this.rootStore.project.projectId]?.filter((p) => p.access === 0); } get archivedProjectPages() { if (!this.rootStore.project.projectId) return; return this.archivedPages[this.rootStore.project.projectId]; } addToFavorites = async (workspaceSlug: string, projectId: string, pageId: string) => { try { runInAction(() => { this.pages = { ...this.pages, [projectId]: this.pages[projectId].map((page) => { if (page.id === pageId) { return { ...page, is_favorite: true }; } return page; }), }; }); await this.pageService.addPageToFavorites(workspaceSlug, projectId, pageId); } catch (error) { throw error; } }; removeFromFavorites = async (workspaceSlug: string, projectId: string, pageId: string) => { try { runInAction(() => { this.pages = { ...this.pages, [projectId]: this.pages[projectId].map((page) => { if (page.id === pageId) { return { ...page, is_favorite: false }; } return page; }), }; }); await this.pageService.removePageFromFavorites(workspaceSlug, projectId, pageId); } catch (error) { throw error; } }; fetchPages = async (workspaceSlug: string, projectId: string) => { try { this.loader = true; this.error = null; const response = await this.pageService.getPagesWithParams(workspaceSlug, projectId, "all"); runInAction(() => { this.pages = { ...this.pages, [projectId]: response, }; this.loader = false; this.error = null; }); return response; } catch (error) { console.error("Failed to fetch project pages in project store", error); this.loader = false; this.error = error; throw error; } }; createPage = async (workspaceSlug: string, projectId: string, data: Partial) => { try { const response = await this.pageService.createPage(workspaceSlug, projectId, data); runInAction(() => { this.pages = { ...this.pages, [projectId]: [...this.pages[projectId], response], }; }); return response; } catch (error) { throw error; } }; updatePage = async (workspaceSlug: string, projectId: string, pageId: string, data: Partial) => { try { runInAction(() => { this.pages = { ...this.pages, [projectId]: this.pages[projectId]?.map((page) => { if (page.id === pageId) { return { ...page, ...data }; } return page; }), }; }); const response = await this.pageService.patchPage(workspaceSlug, projectId, pageId, data); return response; } catch (error) { throw error; } }; deletePage = async (workspaceSlug: string, projectId: string, pageId: string) => { try { runInAction(() => { this.archivedPages = { ...this.archivedPages, [projectId]: this.archivedPages[projectId]?.filter((page) => page.id !== pageId), }; }); const response = await this.pageService.deletePage(workspaceSlug, projectId, pageId); return response; } catch (error) { throw error; } }; makePublic = async (workspaceSlug: string, projectId: string, pageId: string) => { try { runInAction(() => { this.pages = { ...this.pages, [projectId]: this.pages[projectId]?.map((page) => ({ ...page, access: page.id === pageId ? 0 : page.access, })), }; }); const response = await this.pageService.patchPage(workspaceSlug, projectId, pageId, { access: 0 }); return response; } catch (error) { throw error; } }; makePrivate = async (workspaceSlug: string, projectId: string, pageId: string) => { try { runInAction(() => { this.pages = { ...this.pages, [projectId]: this.pages[projectId]?.map((page) => ({ ...page, access: page.id === pageId ? 1 : page.access, })), }; }); const response = await this.pageService.patchPage(workspaceSlug, projectId, pageId, { access: 1 }); return response; } catch (error) { throw error; } }; fetchArchivedPages = async (workspaceSlug: string, projectId: string) => { try { const response = await this.pageService.getArchivedPages(workspaceSlug, projectId); runInAction(() => { this.archivedPages = { ...this.archivedPages, [projectId]: response, }; }); return response; } catch (error) { throw error; } }; archivePage = async (workspaceSlug: string, projectId: string, pageId: string) => { try { const archivedPage = this.pages[projectId]?.find((page) => page.id === pageId); if (archivedPage) { runInAction(() => { this.pages = { ...this.pages, [projectId]: [...this.pages[projectId]?.filter((page) => page.id != pageId)], }; this.archivedPages = { ...this.archivedPages, [projectId]: [ ...this.archivedPages[projectId], { ...archivedPage, archived_at: renderDateFormat(new Date()) }, ], }; }); } await this.pageService.archivePage(workspaceSlug, projectId, pageId); } catch (error) { throw error; } }; restorePage = async (workspaceSlug: string, projectId: string, pageId: string) => { try { const restoredPage = this.archivedPages[projectId]?.find((page) => page.id === pageId); if (restoredPage) { runInAction(() => { this.pages = { ...this.pages, [projectId]: [...this.pages[projectId], { ...restoredPage, archived_at: null }], }; this.archivedPages = { ...this.archivedPages, [projectId]: [...this.archivedPages[projectId]?.filter((page) => page.id != pageId)], }; }); } await this.pageService.restorePage(workspaceSlug, projectId, pageId); } catch (error) { throw error; } }; }