2024-03-06 13:09:14 +00:00
|
|
|
import { isThisWeek, isToday, isYesterday } from "date-fns";
|
2024-01-07 06:35:52 +00:00
|
|
|
import { set } from "lodash";
|
2024-03-06 13:09:14 +00:00
|
|
|
import { makeObservable, observable, runInAction, action, computed } from "mobx";
|
2024-01-07 06:35:52 +00:00
|
|
|
// services
|
2024-03-19 14:38:35 +00:00
|
|
|
import { PageService } from "@/services/page.service";
|
2024-01-07 06:35:52 +00:00
|
|
|
// store
|
2024-03-19 14:38:35 +00:00
|
|
|
import { PageStore, IPageStore } from "@/store/page.store";
|
2024-01-07 06:35:52 +00:00
|
|
|
// types
|
2024-01-19 09:48:47 +00:00
|
|
|
import { IPage, IRecentPages } from "@plane/types";
|
|
|
|
import { RootStore } from "./root.store";
|
2024-03-20 08:14:08 +00:00
|
|
|
//helpers
|
|
|
|
import { getDate } from "helpers/date-time.helper";
|
2024-01-07 06:35:52 +00:00
|
|
|
|
|
|
|
export interface IProjectPageStore {
|
2024-01-24 13:42:54 +00:00
|
|
|
loader: boolean;
|
2024-01-25 12:30:45 +00:00
|
|
|
archivedPageLoader: boolean;
|
2024-01-19 09:48:47 +00:00
|
|
|
projectPageMap: Record<string, Record<string, IPageStore>>;
|
|
|
|
projectArchivedPageMap: Record<string, Record<string, IPageStore>>;
|
|
|
|
|
|
|
|
projectPageIds: string[] | undefined;
|
|
|
|
archivedPageIds: string[] | undefined;
|
|
|
|
favoriteProjectPageIds: string[] | undefined;
|
|
|
|
privateProjectPageIds: string[] | undefined;
|
|
|
|
publicProjectPageIds: string[] | undefined;
|
|
|
|
recentProjectPages: IRecentPages | undefined;
|
2024-01-07 06:35:52 +00:00
|
|
|
// fetch actions
|
2024-01-19 09:48:47 +00:00
|
|
|
fetchProjectPages: (workspaceSlug: string, projectId: string) => Promise<void>;
|
|
|
|
fetchArchivedProjectPages: (workspaceSlug: string, projectId: string) => Promise<void>;
|
2024-01-07 06:35:52 +00:00
|
|
|
// crud actions
|
2024-01-19 09:48:47 +00:00
|
|
|
createPage: (workspaceSlug: string, projectId: string, data: Partial<IPage>) => Promise<IPage>;
|
|
|
|
deletePage: (workspaceSlug: string, projectId: string, pageId: string) => Promise<void>;
|
|
|
|
archivePage: (workspaceSlug: string, projectId: string, pageId: string) => Promise<void>;
|
|
|
|
restorePage: (workspaceSlug: string, projectId: string, pageId: string) => Promise<void>;
|
2024-01-07 06:35:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
export class ProjectPageStore implements IProjectPageStore {
|
2024-01-24 13:42:54 +00:00
|
|
|
loader: boolean = false;
|
2024-01-25 12:30:45 +00:00
|
|
|
archivedPageLoader: boolean = false;
|
2024-01-19 09:48:47 +00:00
|
|
|
projectPageMap: Record<string, Record<string, IPageStore>> = {}; // { projectId: [page1, page2] }
|
|
|
|
projectArchivedPageMap: Record<string, Record<string, IPageStore>> = {}; // { projectId: [page1, page2] }
|
2024-01-07 06:35:52 +00:00
|
|
|
|
2024-01-19 09:48:47 +00:00
|
|
|
// root store
|
|
|
|
rootStore;
|
2024-01-07 06:35:52 +00:00
|
|
|
|
2024-01-19 09:48:47 +00:00
|
|
|
pageService;
|
|
|
|
constructor(_rootStore: RootStore) {
|
2024-01-07 06:35:52 +00:00
|
|
|
makeObservable(this, {
|
2024-01-24 13:42:54 +00:00
|
|
|
loader: observable.ref,
|
2024-01-25 12:30:45 +00:00
|
|
|
archivedPageLoader: observable.ref,
|
2024-01-19 09:48:47 +00:00
|
|
|
projectPageMap: observable,
|
|
|
|
projectArchivedPageMap: observable,
|
|
|
|
|
|
|
|
projectPageIds: computed,
|
|
|
|
archivedPageIds: computed,
|
|
|
|
favoriteProjectPageIds: computed,
|
|
|
|
privateProjectPageIds: computed,
|
|
|
|
publicProjectPageIds: computed,
|
|
|
|
recentProjectPages: computed,
|
|
|
|
|
2024-01-07 06:35:52 +00:00
|
|
|
// fetch actions
|
|
|
|
fetchProjectPages: action,
|
|
|
|
fetchArchivedProjectPages: action,
|
|
|
|
// crud actions
|
|
|
|
createPage: action,
|
|
|
|
deletePage: action,
|
|
|
|
});
|
2024-01-19 09:48:47 +00:00
|
|
|
this.rootStore = _rootStore;
|
|
|
|
|
2024-01-07 06:35:52 +00:00
|
|
|
this.pageService = new PageService();
|
|
|
|
}
|
|
|
|
|
2024-01-19 09:48:47 +00:00
|
|
|
get projectPageIds() {
|
|
|
|
const projectId = this.rootStore.app.router.projectId;
|
|
|
|
if (!projectId || !this.projectPageMap?.[projectId]) return [];
|
|
|
|
|
|
|
|
const allProjectIds = Object.keys(this.projectPageMap[projectId]);
|
|
|
|
return allProjectIds.sort((a, b) => {
|
2024-03-20 08:14:08 +00:00
|
|
|
const dateA = getDate(this.projectPageMap[projectId]?.[a]?.created_at)?.getTime() ?? 0;
|
|
|
|
const dateB = getDate(this.projectPageMap[projectId]?.[b]?.created_at)?.getTime() ?? 0;
|
2024-01-19 09:48:47 +00:00
|
|
|
return dateB - dateA;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
get archivedPageIds() {
|
|
|
|
const projectId = this.rootStore.app.router.projectId;
|
|
|
|
if (!projectId || !this.projectArchivedPageMap[projectId]) return [];
|
|
|
|
const archivedPages = Object.keys(this.projectArchivedPageMap[projectId]);
|
|
|
|
return archivedPages.sort((a, b) => {
|
2024-03-20 08:14:08 +00:00
|
|
|
const dateA = getDate(this.projectArchivedPageMap[projectId]?.[a]?.created_at)?.getTime() ?? 0;
|
|
|
|
const dateB = getDate(this.projectArchivedPageMap[projectId]?.[b]?.created_at)?.getTime() ?? 0;
|
2024-01-19 09:48:47 +00:00
|
|
|
return dateB - dateA;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
get favoriteProjectPageIds() {
|
|
|
|
const projectId = this.rootStore.app.router.projectId;
|
|
|
|
if (!this.projectPageIds || !projectId) return [];
|
|
|
|
|
|
|
|
const favouritePages: string[] = this.projectPageIds.filter(
|
|
|
|
(page) => this.projectPageMap[projectId][page].is_favorite
|
|
|
|
);
|
|
|
|
return favouritePages;
|
|
|
|
}
|
|
|
|
|
|
|
|
get privateProjectPageIds() {
|
|
|
|
const projectId = this.rootStore.app.router.projectId;
|
|
|
|
if (!this.projectPageIds || !projectId) return [];
|
|
|
|
|
|
|
|
const privatePages: string[] = this.projectPageIds.filter(
|
|
|
|
(page) => this.projectPageMap[projectId][page].access === 1
|
|
|
|
);
|
|
|
|
return privatePages;
|
|
|
|
}
|
|
|
|
|
|
|
|
get publicProjectPageIds() {
|
|
|
|
const projectId = this.rootStore.app.router.projectId;
|
|
|
|
const userId = this.rootStore.user.currentUser?.id;
|
|
|
|
if (!this.projectPageIds || !projectId || !userId) return [];
|
|
|
|
|
|
|
|
const publicPages: string[] = this.projectPageIds.filter(
|
|
|
|
(page) =>
|
|
|
|
this.projectPageMap[projectId][page].access === 0 && this.projectPageMap[projectId][page].owned_by === userId
|
|
|
|
);
|
|
|
|
return publicPages;
|
|
|
|
}
|
|
|
|
|
|
|
|
get recentProjectPages() {
|
|
|
|
const projectId = this.rootStore.app.router.projectId;
|
|
|
|
if (!this.projectPageIds || !projectId) return;
|
|
|
|
|
2024-03-20 08:14:08 +00:00
|
|
|
const today: string[] = this.projectPageIds.filter((page) => {
|
|
|
|
const updatedAt = getDate(this.projectPageMap[projectId]?.[page]?.updated_at);
|
|
|
|
return updatedAt && isToday(updatedAt);
|
|
|
|
});
|
2024-01-19 09:48:47 +00:00
|
|
|
|
2024-03-20 08:14:08 +00:00
|
|
|
const yesterday: string[] = this.projectPageIds.filter((page) => {
|
|
|
|
const updatedAt = getDate(this.projectPageMap[projectId]?.[page]?.updated_at);
|
|
|
|
return updatedAt && isYesterday(updatedAt);
|
|
|
|
});
|
2024-01-19 09:48:47 +00:00
|
|
|
|
|
|
|
const this_week: string[] = this.projectPageIds.filter((page) => {
|
2024-03-20 08:14:08 +00:00
|
|
|
const pageUpdatedAt = getDate(this.projectPageMap[projectId]?.[page]?.updated_at);
|
|
|
|
return pageUpdatedAt && isThisWeek(pageUpdatedAt) && !isToday(pageUpdatedAt) && !isYesterday(pageUpdatedAt);
|
2024-01-19 09:48:47 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
const older: string[] = this.projectPageIds.filter((page) => {
|
2024-03-20 08:14:08 +00:00
|
|
|
const pageUpdatedAt = getDate(this.projectPageMap[projectId]?.[page]?.updated_at);
|
|
|
|
return pageUpdatedAt && !isThisWeek(pageUpdatedAt) && !isYesterday(pageUpdatedAt);
|
2024-01-19 09:48:47 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
return { today, yesterday, this_week, older };
|
|
|
|
}
|
|
|
|
|
2024-01-07 06:35:52 +00:00
|
|
|
/**
|
|
|
|
* Fetching all the pages for a specific project
|
|
|
|
* @param workspaceSlug
|
|
|
|
* @param projectId
|
|
|
|
*/
|
|
|
|
fetchProjectPages = async (workspaceSlug: string, projectId: string) => {
|
2024-01-19 09:48:47 +00:00
|
|
|
try {
|
2024-01-24 13:42:54 +00:00
|
|
|
this.loader = true;
|
2024-01-19 09:48:47 +00:00
|
|
|
await this.pageService.getProjectPages(workspaceSlug, projectId).then((response) => {
|
|
|
|
runInAction(() => {
|
|
|
|
for (const page of response) {
|
|
|
|
set(this.projectPageMap, [projectId, page.id], new PageStore(page, this.rootStore));
|
|
|
|
}
|
2024-01-24 13:42:54 +00:00
|
|
|
this.loader = false;
|
2024-01-19 09:48:47 +00:00
|
|
|
});
|
|
|
|
return response;
|
|
|
|
});
|
|
|
|
} catch (e) {
|
2024-01-24 13:42:54 +00:00
|
|
|
this.loader = false;
|
|
|
|
|
2024-01-19 09:48:47 +00:00
|
|
|
throw e;
|
|
|
|
}
|
2024-01-07 06:35:52 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* fetches all archived pages for a project.
|
|
|
|
* @param workspaceSlug
|
|
|
|
* @param projectId
|
|
|
|
* @returns Promise<IPage[]>
|
|
|
|
*/
|
2024-01-19 09:48:47 +00:00
|
|
|
fetchArchivedProjectPages = async (workspaceSlug: string, projectId: string) => {
|
|
|
|
try {
|
2024-01-25 12:30:45 +00:00
|
|
|
this.archivedPageLoader = true;
|
2024-01-19 09:48:47 +00:00
|
|
|
await this.pageService.getArchivedPages(workspaceSlug, projectId).then((response) => {
|
|
|
|
runInAction(() => {
|
|
|
|
for (const page of response) {
|
|
|
|
set(this.projectArchivedPageMap, [projectId, page.id], new PageStore(page, this.rootStore));
|
|
|
|
}
|
2024-01-25 12:30:45 +00:00
|
|
|
this.archivedPageLoader = false;
|
2024-01-19 09:48:47 +00:00
|
|
|
});
|
|
|
|
return response;
|
2024-01-07 06:35:52 +00:00
|
|
|
});
|
2024-01-19 09:48:47 +00:00
|
|
|
} catch (e) {
|
2024-01-25 12:30:45 +00:00
|
|
|
this.archivedPageLoader = false;
|
2024-01-19 09:48:47 +00:00
|
|
|
throw e;
|
|
|
|
}
|
|
|
|
};
|
2024-01-07 06:35:52 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates a new page using the api and updated the local state in store
|
|
|
|
* @param workspaceSlug
|
|
|
|
* @param projectId
|
|
|
|
* @param data
|
|
|
|
*/
|
|
|
|
createPage = async (workspaceSlug: string, projectId: string, data: Partial<IPage>) => {
|
|
|
|
const response = await this.pageService.createPage(workspaceSlug, projectId, data);
|
|
|
|
runInAction(() => {
|
2024-01-19 09:48:47 +00:00
|
|
|
set(this.projectPageMap, [projectId, response.id], new PageStore(response, this.rootStore));
|
2024-01-07 06:35:52 +00:00
|
|
|
});
|
|
|
|
return response;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* delete a page using the api and updates the local state in store
|
|
|
|
* @param workspaceSlug
|
|
|
|
* @param projectId
|
|
|
|
* @param pageId
|
|
|
|
* @returns
|
|
|
|
*/
|
|
|
|
deletePage = async (workspaceSlug: string, projectId: string, pageId: string) => {
|
|
|
|
const response = await this.pageService.deletePage(workspaceSlug, projectId, pageId);
|
|
|
|
runInAction(() => {
|
2024-01-19 09:48:47 +00:00
|
|
|
delete this.projectArchivedPageMap[projectId][pageId];
|
2024-01-07 06:35:52 +00:00
|
|
|
});
|
|
|
|
return response;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Mark a page archived
|
|
|
|
* @param workspaceSlug
|
|
|
|
* @param projectId
|
|
|
|
* @param pageId
|
|
|
|
*/
|
|
|
|
archivePage = async (workspaceSlug: string, projectId: string, pageId: string) => {
|
|
|
|
runInAction(() => {
|
2024-01-19 09:48:47 +00:00
|
|
|
set(this.projectArchivedPageMap, [projectId, pageId], this.projectPageMap[projectId][pageId]);
|
|
|
|
set(this.projectArchivedPageMap[projectId][pageId], "archived_at", new Date().toISOString());
|
|
|
|
delete this.projectPageMap[projectId][pageId];
|
|
|
|
});
|
|
|
|
const response = await this.pageService.archivePage(workspaceSlug, projectId, pageId).catch(() => {
|
|
|
|
runInAction(() => {
|
|
|
|
set(this.projectPageMap, [projectId, pageId], this.projectArchivedPageMap[projectId][pageId]);
|
|
|
|
set(this.projectPageMap[projectId][pageId], "archived_at", null);
|
|
|
|
delete this.projectArchivedPageMap[projectId][pageId];
|
|
|
|
});
|
2024-01-07 06:35:52 +00:00
|
|
|
});
|
|
|
|
return response;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Restore a page from archived pages to pages
|
|
|
|
* @param workspaceSlug
|
|
|
|
* @param projectId
|
|
|
|
* @param pageId
|
|
|
|
*/
|
2024-01-19 09:48:47 +00:00
|
|
|
restorePage = async (workspaceSlug: string, projectId: string, pageId: string) => {
|
|
|
|
const pageArchivedAt = this.projectArchivedPageMap[projectId][pageId].archived_at;
|
|
|
|
runInAction(() => {
|
|
|
|
set(this.projectPageMap, [projectId, pageId], this.projectArchivedPageMap[projectId][pageId]);
|
|
|
|
set(this.projectPageMap[projectId][pageId], "archived_at", null);
|
|
|
|
delete this.projectArchivedPageMap[projectId][pageId];
|
|
|
|
});
|
|
|
|
await this.pageService.restorePage(workspaceSlug, projectId, pageId).catch(() => {
|
2024-01-07 06:35:52 +00:00
|
|
|
runInAction(() => {
|
2024-01-19 09:48:47 +00:00
|
|
|
set(this.projectArchivedPageMap, [projectId, pageId], this.projectPageMap[projectId][pageId]);
|
|
|
|
set(this.projectArchivedPageMap[projectId][pageId], "archived_at", pageArchivedAt);
|
|
|
|
delete this.projectPageMap[projectId][pageId];
|
2024-01-07 06:35:52 +00:00
|
|
|
});
|
|
|
|
});
|
2024-01-19 09:48:47 +00:00
|
|
|
};
|
2024-01-07 06:35:52 +00:00
|
|
|
}
|