diff --git a/web/services/page.service.ts b/web/services/page.service.ts index 83b19c926..5ee2692ed 100644 --- a/web/services/page.service.ts +++ b/web/services/page.service.ts @@ -50,6 +50,14 @@ export class PageService extends APIService { }); } + async getProjectPages(workspaceSlug: string, projectId: string) { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/pages/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + async getPagesWithParams( workspaceSlug: string, projectId: string, diff --git a/web/store/application/router.store.ts b/web/store/application/router.store.ts index f275f0898..222d896e3 100644 --- a/web/store/application/router.store.ts +++ b/web/store/application/router.store.ts @@ -1,5 +1,5 @@ import { action, makeObservable, observable } from "mobx"; -import { ParsedUrlQuery } from "querystring"; +import { ParsedUrlQuery } from "node:querystring"; export interface IRouterStore { query: ParsedUrlQuery; diff --git a/web/store/page.store.ts b/web/store/page.store.ts new file mode 100644 index 000000000..b27beec86 --- /dev/null +++ b/web/store/page.store.ts @@ -0,0 +1,196 @@ +import { action, computed, makeObservable, observable, runInAction } from "mobx"; +import keyBy from "lodash/keyBy"; +import isToday from "date-fns/isToday"; +import isThisWeek from "date-fns/isThisWeek"; +import isYesterday from "date-fns/isYesterday"; +// services +import { PageService } from "services/page.service"; +// types +import { IPage, IRecentPages } from "types"; +// store +import { RootStore } from "./root.store"; + +export interface IPageStore { + pages: Record; + archivedPages: Record; + + projectPages: IPage[] | undefined; + favoriteProjectPages: IPage[] | undefined; + privateProjectPages: IPage[] | undefined; + sharedProjectPages: IPage[] | undefined; + + fetchProjectPages: (workspaceSlug: string, projectId: string) => Promise; +} + +export class PageStore { + pages: Record = {}; + archivedPages: Record = {}; + // services + pageService; + // stores + router; + + constructor(_rootStore: RootStore) { + makeObservable(this, { + pages: observable.ref, + archivedPages: observable.ref, + // computed + projectPages: computed, + favoriteProjectPages: computed, + sharedProjectPages: computed, + privateProjectPages: computed, + // actions + fetchProjectPages: action, + }); + // stores + this.router = _rootStore.app.router; + // services + this.pageService = new PageService(); + } + + /** + * retrieves all pages for a projectId that is available in the url. + */ + get projectPages() { + if (!this.router.projectId) return; + return Object.values(this.pages).filter((page) => page.project === this.router.query.projectId); + } + + /** + * retrieves all favorite pages for a projectId that is available in the url. + */ + get favoriteProjectPages() { + if (!this.projectPages) return; + return this.projectPages.filter((page) => page.is_favorite); + } + + /** + * retrieves all private pages for a projectId that is available in the url. + */ + get privateProjectPages() { + if (!this.projectPages) return; + return this.projectPages.filter((page) => page.access === 1); + } + + /** + * retrieves all shared pages which are public to everyone in the project for a projectId that is available in the url. + */ + get sharedProjectPages() { + if (!this.projectPages) return; + return this.projectPages.filter((page) => page.access === 0); + } + + /** + * retrieves all recent pages for a projectId that is available in the url. + * In format where today, yesterday, this_week, older are keys. + */ + get recentProjectPages() { + if (!this.projectPages) return; + const data: IRecentPages = { today: [], yesterday: [], this_week: [], older: [] }; + data.today = this.projectPages.filter((p) => isToday(new Date(p.created_at))) || []; + data.yesterday = this.projectPages.filter((p) => isYesterday(new Date(p.created_at))) || []; + data.this_week = + this.projectPages.filter( + (p) => + isThisWeek(new Date(p.created_at)) && !isToday(new Date(p.created_at)) && !isYesterday(new Date(p.created_at)) + ) || []; + data.older = + this.projectPages.filter((p) => !isThisWeek(new Date(p.created_at)) && !isYesterday(new Date(p.created_at))) || + []; + return data; + } + + /** + * retrieves all archived pages for a projectId that is available in the url. + */ + get archivedProjectPages() { + if (!this.router.projectId) return; + return Object.values(this.archivedPages).filter((page) => page.project === this.router.projectId); + } + + /** + * fetches all pages for a project. + * @param workspaceSlug + * @param projectId + * @returns Promise + */ + async fetchProjectPages(workspaceSlug: string, projectId: string) { + const response = await this.pageService.getProjectPages(workspaceSlug, projectId); + runInAction(() => { + this.pages = { + ...this.pages, + ...keyBy(response, "id"), + }; + }); + return response; + } + + /** + * fetches all archived pages for a project. + * @param workspaceSlug + * @param projectId + * @returns Promise + */ + async fetchArchivedProjectPages(workspaceSlug: string, projectId: string) { + const response = await this.pageService.getArchivedPages(workspaceSlug, projectId); + runInAction(() => { + this.archivedPages = { + ...this.archivedPages, + ...keyBy(response, "id"), + }; + }); + return response; + } + + /** + * Add Page to users favorites list + * @param workspaceSlug + * @param projectId + * @param pageId + */ + addToFavorites = async (workspaceSlug: string, projectId: string, pageId: string) => { + try { + runInAction(() => { + this.pages = { + ...this.pages, + [pageId]: { ...this.pages[pageId], is_favorite: true }, + }; + }); + await this.pageService.addPageToFavorites(workspaceSlug, projectId, pageId); + } catch (error) { + runInAction(() => { + this.pages = { + ...this.pages, + [pageId]: { ...this.pages[pageId], is_favorite: false }, + }; + }); + throw error; + } + }; + + /** + * Remove page from the users favorites list + * @param workspaceSlug + * @param projectId + * @param pageId + */ + removeFromFavorites = async (workspaceSlug: string, projectId: string, pageId: string) => { + try { + runInAction(() => { + this.pages = { + ...this.pages, + [pageId]: { ...this.pages[pageId], is_favorite: false }, + }; + }); + await this.pageService.removePageFromFavorites(workspaceSlug, projectId, pageId); + } catch (error) { + runInAction(() => { + this.pages = { + ...this.pages, + [pageId]: { ...this.pages[pageId], is_favorite: true }, + }; + }); + throw error; + } + }; +}