plane/web/store/page.store.ts

420 lines
12 KiB
TypeScript
Raw Normal View History

2023-12-12 12:17:02 +00:00
import { action, computed, makeObservable, observable, runInAction } from "mobx";
2023-12-12 15:21:09 +00:00
import set from "lodash/set";
2023-12-12 19:39:04 +00:00
import omit from "lodash/omit";
2023-12-12 12:17:02 +00:00
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";
2023-12-12 12:17:02 +00:00
export interface IPageStore {
pages: Record<string, IPage>;
archivedPages: Record<string, IPage>;
2023-12-12 19:39:04 +00:00
// project computed
projectPages: string[] | null;
favoriteProjectPages: string[] | null;
privateProjectPages: string[] | null;
publicProjectPages: string[] | null;
recentProjectPages: IRecentPages | null;
archivedProjectPages: string[] | null;
getUnArchivedPageById: (pageId: string) => IPage | null;
getArchivedPageById: (pageId: string) => IPage | null;
2023-12-12 19:39:04 +00:00
// fetch actions
fetchProjectPages: (workspaceSlug: string, projectId: string) => Promise<Record<string, IPage>>;
fetchArchivedProjectPages: (workspaceSlug: string, projectId: string) => Promise<Record<string, IPage>>;
2023-12-12 19:39:04 +00:00
// favorites actions
addToFavorites: (workspaceSlug: string, projectId: string, pageId: string) => Promise<void>;
removeFromFavorites: (workspaceSlug: string, projectId: string, pageId: string) => Promise<void>;
// crud
createPage: (workspaceSlug: string, projectId: string, data: Partial<IPage>) => Promise<IPage>;
updatePage: (workspaceSlug: string, projectId: string, pageId: string, data: Partial<IPage>) => Promise<IPage>;
2023-12-12 19:39:04 +00:00
deletePage: (workspaceSlug: string, projectId: string, pageId: string) => Promise<void>;
// access control actions
makePublic: (workspaceSlug: string, projectId: string, pageId: string) => Promise<void>;
makePrivate: (workspaceSlug: string, projectId: string, pageId: string) => Promise<void>;
// archive actions
archivePage: (workspaceSlug: string, projectId: string, pageId: string) => Promise<void>;
restorePage: (workspaceSlug: string, projectId: string, pageId: string) => Promise<void>;
2023-12-12 12:17:02 +00:00
}
export class PageStore implements IPageStore {
2023-12-12 12:17:02 +00:00
pages: Record<string, IPage> = {};
archivedPages: Record<string, IPage> = {};
// services
pageService;
// stores
rootStore;
2023-12-12 12:17:02 +00:00
constructor(rootStore: RootStore) {
2023-12-12 12:17:02 +00:00
makeObservable(this, {
2023-12-12 15:21:09 +00:00
pages: observable,
archivedPages: observable,
// computed
2023-12-12 12:17:02 +00:00
projectPages: computed,
favoriteProjectPages: computed,
2023-12-12 19:39:04 +00:00
publicProjectPages: computed,
2023-12-12 12:17:02 +00:00
privateProjectPages: computed,
2023-12-12 19:39:04 +00:00
archivedProjectPages: computed,
recentProjectPages: computed,
// computed actions
getUnArchivedPageById: action,
getArchivedPageById: action,
2023-12-12 19:39:04 +00:00
// fetch actions
2023-12-12 12:17:02 +00:00
fetchProjectPages: action,
2023-12-12 19:39:04 +00:00
fetchArchivedProjectPages: action,
// favorites actions
addToFavorites: action,
removeFromFavorites: action,
// crud
createPage: action,
updatePage: action,
deletePage: action,
// access control actions
makePublic: action,
makePrivate: action,
// archive actions
archivePage: action,
restorePage: action,
2023-12-12 12:17:02 +00:00
});
// stores
this.rootStore = rootStore;
2023-12-12 12:17:02 +00:00
// services
this.pageService = new PageService();
}
/**
* retrieves all pages for a projectId that is available in the url.
*/
get projectPages() {
const projectId = this.rootStore.app.router.projectId;
if (!projectId) return null;
const projectPagesIds = Object.keys(this.pages).filter((pageId) => this.pages?.[pageId]?.project === projectId);
return projectPagesIds ?? null;
2023-12-12 12:17:02 +00:00
}
/**
* retrieves all favorite pages for a projectId that is available in the url.
*/
get favoriteProjectPages() {
if (!this.projectPages) return null;
const favoritePagesIds = Object.keys(this.projectPages).filter((pageId) => this.pages?.[pageId]?.is_favorite);
return favoritePagesIds ?? null;
2023-12-12 12:17:02 +00:00
}
/**
* retrieves all private pages for a projectId that is available in the url.
*/
get privateProjectPages() {
if (!this.projectPages) return null;
const privatePagesIds = Object.keys(this.projectPages).filter((pageId) => this.pages?.[pageId]?.access === 1);
return privatePagesIds ?? null;
2023-12-12 12:17:02 +00:00
}
/**
* retrieves all shared pages which are public to everyone in the project for a projectId that is available in the url.
*/
2023-12-12 19:39:04 +00:00
get publicProjectPages() {
if (!this.projectPages) return null;
const publicPagesIds = Object.keys(this.projectPages).filter((pageId) => this.pages?.[pageId]?.access === 0);
return publicPagesIds ?? null;
2023-12-12 12:17:02 +00:00
}
/**
* 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 null;
2023-12-12 12:17:02 +00:00
const data: IRecentPages = { today: [], yesterday: [], this_week: [], older: [] };
data.today = this.projectPages.filter((p) => isToday(new Date(this.pages?.[p]?.created_at))) || [];
data.yesterday = this.projectPages.filter((p) => isYesterday(new Date(this.pages?.[p]?.created_at))) || [];
2023-12-12 12:17:02 +00:00
data.this_week =
this.projectPages.filter((p) => {
const pageCreatedAt = this.pages?.[p]?.created_at;
return (
isThisWeek(new Date(pageCreatedAt)) &&
!isToday(new Date(pageCreatedAt)) &&
!isYesterday(new Date(pageCreatedAt))
);
}) || [];
2023-12-12 12:17:02 +00:00
data.older =
this.projectPages.filter((p) => {
const pageCreatedAt = this.pages?.[p]?.created_at;
return !isThisWeek(new Date(pageCreatedAt)) && !isYesterday(new Date(pageCreatedAt));
}) || [];
2023-12-12 12:17:02 +00:00
return data;
}
/**
* retrieves all archived pages for a projectId that is available in the url.
*/
get archivedProjectPages() {
const projectId = this.rootStore.app.router.projectId;
if (!projectId) return null;
const archivedProjectPagesIds = Object.keys(this.archivedPages).filter(
(pageId) => this.archivedPages?.[pageId]?.project === projectId
);
return archivedProjectPagesIds ?? null;
2023-12-12 12:17:02 +00:00
}
/**
* retrieves a page from pages by id.
* @param pageId
* @returns IPage | null
*/
getUnArchivedPageById = (pageId: string) => this.pages?.[pageId] ?? null;
/**
* retrieves a page from archived pages by id.
* @param pageId
* @returns IPage | null
*/
getArchivedPageById = (pageId: string) => this.archivedPages?.[pageId] ?? null;
2023-12-12 12:17:02 +00:00
/**
* fetches all pages for a project.
* @param workspaceSlug
* @param projectId
* @returns Promise<IPage[]>
*/
fetchProjectPages = async (workspaceSlug: string, projectId: string) => {
try {
const response = await this.pageService.getProjectPages(workspaceSlug, projectId);
runInAction(() => {
Object.values(response).forEach((page) => {
set(this.pages, [page.id], page);
});
});
return response;
} catch (error) {
throw error;
}
};
2023-12-12 12:17:02 +00:00
/**
* fetches all archived pages for a project.
* @param workspaceSlug
* @param projectId
* @returns Promise<IPage[]>
*/
fetchArchivedProjectPages = async (workspaceSlug: string, projectId: string) => {
try {
const response = await this.pageService.getArchivedPages(workspaceSlug, projectId);
runInAction(() => {
Object.values(response).forEach((page) => {
set(this.archivedPages, [page.id], page);
});
});
return response;
} catch (error) {
throw error;
}
};
2023-12-12 12:17:02 +00:00
/**
* Add Page to users favorites list
* @param workspaceSlug
* @param projectId
* @param pageId
*/
addToFavorites = async (workspaceSlug: string, projectId: string, pageId: string) => {
try {
runInAction(() => {
set(this.pages, [pageId, "is_favorite"], true);
2023-12-12 12:17:02 +00:00
});
2023-12-12 12:17:02 +00:00
await this.pageService.addPageToFavorites(workspaceSlug, projectId, pageId);
} catch (error) {
runInAction(() => {
set(this.pages, [pageId, "is_favorite"], false);
2023-12-12 12:17:02 +00:00
});
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(() => {
set(this.pages, [pageId, "is_favorite"], false);
2023-12-12 12:17:02 +00:00
});
2023-12-12 12:17:02 +00:00
await this.pageService.removePageFromFavorites(workspaceSlug, projectId, pageId);
} catch (error) {
runInAction(() => {
set(this.pages, [pageId, "is_favorite"], true);
2023-12-12 12:17:02 +00:00
});
throw error;
}
};
2023-12-12 15:21:09 +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>) => {
try {
const response = await this.pageService.createPage(workspaceSlug, projectId, data);
runInAction(() => {
set(this.pages, [response.id], response);
});
return response;
} catch (error) {
throw error;
}
2023-12-12 15:21:09 +00:00
};
/**
* updates the page using the api and updates the local state in store
* @param workspaceSlug
* @param projectId
* @param pageId
* @param data
* @returns
*/
updatePage = async (workspaceSlug: string, projectId: string, pageId: string, data: Partial<IPage>) => {
const originalPage = this.getUnArchivedPageById(pageId);
2023-12-12 15:21:09 +00:00
try {
runInAction(() => {
set(this.pages, [pageId], { ...originalPage, ...data });
2023-12-12 15:21:09 +00:00
});
2023-12-12 15:21:09 +00:00
const response = await this.pageService.patchPage(workspaceSlug, projectId, pageId, data);
2023-12-12 15:21:09 +00:00
return response;
} catch (error) {
runInAction(() => {
set(this.pages, [pageId], originalPage);
2023-12-12 15:21:09 +00:00
});
throw error;
}
};
2023-12-12 19:39:04 +00:00
/**
* 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) => {
try {
const response = await this.pageService.deletePage(workspaceSlug, projectId, pageId);
2023-12-12 19:39:04 +00:00
runInAction(() => {
omit(this.archivedPages, [pageId]);
2023-12-12 19:39:04 +00:00
});
return response;
} catch (error) {
throw error;
}
};
/**
* make a page public
* @param workspaceSlug
* @param projectId
* @param pageId
* @returns
*/
makePublic = async (workspaceSlug: string, projectId: string, pageId: string) => {
try {
runInAction(() => {
set(this.pages, [pageId, "access"], 0);
2023-12-12 19:39:04 +00:00
});
await this.pageService.patchPage(workspaceSlug, projectId, pageId, { access: 0 });
2023-12-12 19:39:04 +00:00
} catch (error) {
runInAction(() => {
set(this.pages, [pageId, "access"], 1);
2023-12-12 19:39:04 +00:00
});
throw error;
}
};
/**
* Make a page private
* @param workspaceSlug
* @param projectId
* @param pageId
* @returns
*/
makePrivate = async (workspaceSlug: string, projectId: string, pageId: string) => {
try {
runInAction(() => {
set(this.pages, [pageId, "access"], 1);
2023-12-12 19:39:04 +00:00
});
await this.pageService.patchPage(workspaceSlug, projectId, pageId, { access: 1 });
2023-12-12 19:39:04 +00:00
} catch (error) {
runInAction(() => {
set(this.pages, [pageId, "access"], 0);
2023-12-12 19:39:04 +00:00
});
throw error;
}
};
/**
* Mark a page archived
* @param workspaceSlug
* @param projectId
* @param pageId
*/
archivePage = async (workspaceSlug: string, projectId: string, pageId: string) => {
await this.pageService.archivePage(workspaceSlug, projectId, pageId);
2023-12-12 19:39:04 +00:00
runInAction(() => {
set(this.archivedPages, [pageId], this.pages[pageId]);
omit(this.pages, [pageId]);
2023-12-12 19:39:04 +00:00
});
};
/**
* Restore a page from archived pages to pages
* @param workspaceSlug
* @param projectId
* @param pageId
*/
restorePage = async (workspaceSlug: string, projectId: string, pageId: string) => {
await this.pageService.restorePage(workspaceSlug, projectId, pageId);
2023-12-12 19:39:04 +00:00
runInAction(() => {
set(this.pages, [pageId], this.archivedPages[pageId]);
omit(this.archivedPages, [pageId]);
2023-12-12 19:39:04 +00:00
});
};
2023-12-12 12:17:02 +00:00
}