diff --git a/web/components/project/publish-project/modal.tsx b/web/components/project/publish-project/modal.tsx index dc2c0f537..3469ca60a 100644 --- a/web/components/project/publish-project/modal.tsx +++ b/web/components/project/publish-project/modal.tsx @@ -25,6 +25,7 @@ type Props = { }; type FormData = { + anchor: string; id: string | null; comments: boolean; reactions: boolean; @@ -34,6 +35,7 @@ type FormData = { }; const defaultValues: FormData = { + anchor: "", id: null, comments: false, reactions: false, @@ -48,34 +50,27 @@ const viewOptions: { }[] = [ { key: "list", label: "List" }, { key: "kanban", label: "Kanban" }, - // { key: "calendar", label: "Calendar" }, - // { key: "gantt", label: "Gantt" }, - // { key: "spreadsheet", label: "Spreadsheet" }, ]; export const PublishProjectModal: React.FC = observer((props) => { const { isOpen, project, onClose } = props; - // hooks - // const { instance } = useInstance(); // states const [isUnPublishing, setIsUnPublishing] = useState(false); const [isUpdateRequired, setIsUpdateRequired] = useState(false); - - // const plane_deploy_url = instance?.config?.space_base_url || ""; - const SPACE_URL = (SPACE_BASE_URL === "" ? window.location.origin : SPACE_BASE_URL) + SPACE_BASE_PATH; - // router const router = useRouter(); const { workspaceSlug } = router.query; // store hooks const { - projectPublishSettings, - getProjectSettingsAsync, + fetchPublishSettings, + getPublishSettingsByProjectID, publishProject, - updateProjectSettingsAsync, + updatePublishSettings, unPublishProject, fetchSettingsLoader, } = useProjectPublish(); + // derived values + const projectPublishSettings = getPublishSettingsByProjectID(project.id); // form info const { control, @@ -97,44 +92,44 @@ export const PublishProjectModal: React.FC = observer((props) => { // prefill form with the saved settings if the project is already published useEffect(() => { - if (projectPublishSettings && projectPublishSettings !== "not-initialized") { - let userBoards: TProjectPublishViews[] = []; + if (!projectPublishSettings) return; - if (projectPublishSettings?.views) { - const savedViews = projectPublishSettings?.views; + let userBoards: TProjectPublishViews[] = []; - if (!savedViews) return; + if (projectPublishSettings?.view_props) { + const savedViews = projectPublishSettings?.view_props; - if (savedViews.list) userBoards.push("list"); - if (savedViews.kanban) userBoards.push("kanban"); - if (savedViews.calendar) userBoards.push("calendar"); - if (savedViews.gantt) userBoards.push("gantt"); - if (savedViews.spreadsheet) userBoards.push("spreadsheet"); + if (!savedViews) return; - userBoards = userBoards && userBoards.length > 0 ? userBoards : ["list"]; - } + if (savedViews.list) userBoards.push("list"); + if (savedViews.kanban) userBoards.push("kanban"); + if (savedViews.calendar) userBoards.push("calendar"); + if (savedViews.gantt) userBoards.push("gantt"); + if (savedViews.spreadsheet) userBoards.push("spreadsheet"); - const updatedData = { - id: projectPublishSettings?.id || null, - comments: projectPublishSettings?.comments || false, - reactions: projectPublishSettings?.reactions || false, - votes: projectPublishSettings?.votes || false, - inbox: projectPublishSettings?.inbox || null, - views: userBoards, - }; - - reset({ ...updatedData }); + userBoards = userBoards && userBoards.length > 0 ? userBoards : ["list"]; } + + const updatedData = { + id: projectPublishSettings?.id || null, + comments: projectPublishSettings?.comments || false, + reactions: projectPublishSettings?.reactions || false, + votes: projectPublishSettings?.votes || false, + inbox: projectPublishSettings?.inbox || null, + views: userBoards, + }; + + reset({ ...updatedData }); }, [reset, projectPublishSettings, isOpen]); // fetch publish settings useEffect(() => { if (!workspaceSlug || !isOpen) return; - if (projectPublishSettings === "not-initialized") { - getProjectSettingsAsync(workspaceSlug.toString(), project.id); + if (!projectPublishSettings) { + fetchPublishSettings(workspaceSlug.toString(), project.id); } - }, [isOpen, workspaceSlug, project, projectPublishSettings, getProjectSettingsAsync]); + }, [fetchPublishSettings, isOpen, project, projectPublishSettings, workspaceSlug]); const handlePublishProject = async (payload: IProjectPublishSettings) => { if (!workspaceSlug) return; @@ -145,7 +140,7 @@ export const PublishProjectModal: React.FC = observer((props) => { const handleUpdatePublishSettings = async (payload: IProjectPublishSettings) => { if (!workspaceSlug) return; - await updateProjectSettingsAsync(workspaceSlug.toString(), project.id, payload.id ?? "", payload) + await updatePublishSettings(workspaceSlug.toString(), project.id, payload.id ?? "", payload) .then((res) => { setToast({ type: TOAST_TYPE.SUCCESS, @@ -172,7 +167,7 @@ export const PublishProjectModal: React.FC = observer((props) => { setToast({ type: TOAST_TYPE.ERROR, title: "Error!", - message: "Something went wrong while un-publishing the project.", + message: "Something went wrong while unpublishing the project.", }) ) .finally(() => setIsUnPublishing(false)); @@ -214,7 +209,7 @@ export const PublishProjectModal: React.FC = observer((props) => { reactions: formData.reactions, votes: formData.votes, inbox: formData.inbox, - views: { + view_props: { list: formData.views.includes("list"), kanban: formData.views.includes("kanban"), calendar: formData.views.includes("calendar"), @@ -223,13 +218,18 @@ export const PublishProjectModal: React.FC = observer((props) => { }, }; - if (project.is_deployed) await handleUpdatePublishSettings({ id: watch("id") ?? "", ...payload }); + if (project.is_deployed) + await handleUpdatePublishSettings({ + anchor: watch("anchor") ?? "", + id: watch("id") ?? "", + ...payload, + }); else await handlePublishProject(payload); }; // check if an update is required or not const checkIfUpdateIsRequired = () => { - if (!projectPublishSettings || projectPublishSettings === "not-initialized") return; + if (!projectPublishSettings || !projectPublishSettings) return; const currentSettings = projectPublishSettings; const newSettings = getValues(); @@ -245,7 +245,7 @@ export const PublishProjectModal: React.FC = observer((props) => { let viewCheckFlag = 0; viewOptions.forEach((option) => { - if (currentSettings.views[option.key] !== newSettings.views.includes(option.key)) viewCheckFlag++; + if (currentSettings.view_props?.[option.key] !== newSettings.views.includes(option.key)) viewCheckFlag++; }); if (viewCheckFlag !== 0) { @@ -256,6 +256,8 @@ export const PublishProjectModal: React.FC = observer((props) => { setIsUpdateRequired(false); }; + const SPACE_URL = (SPACE_BASE_URL === "" ? window.location.origin : SPACE_BASE_URL) + SPACE_BASE_PATH; + return ( @@ -293,7 +295,7 @@ export const PublishProjectModal: React.FC = observer((props) => { onClick={() => handleUnPublishProject(watch("id") ?? "")} loading={isUnPublishing} > - {isUnPublishing ? "Un-publishing..." : "Un-publish"} + {isUnPublishing ? "Unpublishing" : "Unpublish"} )} @@ -308,12 +310,12 @@ export const PublishProjectModal: React.FC = observer((props) => { ) : (
- {project.is_deployed && ( + {project.is_deployed && projectPublishSettings && ( <>
-
{`${SPACE_URL}/issues/`}
+
{`${SPACE_URL}/issues/${projectPublishSettings.anchor}`}
- +
diff --git a/web/services/project/project-publish.service.ts b/web/services/project/project-publish.service.ts index 677b37553..59c7ed089 100644 --- a/web/services/project/project-publish.service.ts +++ b/web/services/project/project-publish.service.ts @@ -34,7 +34,7 @@ export class ProjectPublishService extends APIService { projectID: string, project_publish_id: string, data: IProjectPublishSettings - ): Promise { + ): Promise { return this.patch( `/api/workspaces/${workspaceSlug}/projects/${projectID}/project-deploy-boards/${project_publish_id}/`, data diff --git a/web/store/project/project-publish.store.ts b/web/store/project/project-publish.store.ts index 4bcdf12f9..33b695a69 100644 --- a/web/store/project/project-publish.store.ts +++ b/web/store/project/project-publish.store.ts @@ -1,4 +1,5 @@ import set from "lodash/set"; +import unset from "lodash/unset"; import { observable, action, makeObservable, runInAction } from "mobx"; // types import { ProjectPublishService } from "@/services/project"; @@ -12,12 +13,13 @@ export type TProjectPublishViewsSettings = { }; export interface IProjectPublishSettings { + anchor?: string; id?: string; project?: string; comments: boolean; reactions: boolean; votes: boolean; - views: TProjectPublishViewsSettings; + view_props: TProjectPublishViewsSettings; inbox: string | null; } @@ -26,31 +28,31 @@ export interface IProjectPublishStore { generalLoader: boolean; fetchSettingsLoader: boolean; // observables - projectPublishSettings: IProjectPublishSettings | "not-initialized"; - // project settings actions - getProjectSettingsAsync: (workspaceSlug: string, projectId: string) => Promise; - updateProjectSettingsAsync: ( + publishSettingsMap: Record; // projectID => IProjectPublishSettings + // helpers + getPublishSettingsByProjectID: (projectID: string) => IProjectPublishSettings | undefined; + // actions + fetchPublishSettings: (workspaceSlug: string, projectID: string) => Promise; + updatePublishSettings: ( workspaceSlug: string, - projectId: string, + projectID: string, projectPublishId: string, data: IProjectPublishSettings - ) => Promise; - // project publish actions + ) => Promise; publishProject: ( workspaceSlug: string, - projectId: string, + projectID: string, data: IProjectPublishSettings ) => Promise; - unPublishProject: (workspaceSlug: string, projectId: string, projectPublishId: string) => Promise; + unPublishProject: (workspaceSlug: string, projectID: string, projectPublishId: string) => Promise; } export class ProjectPublishStore implements IProjectPublishStore { // states generalLoader: boolean = false; fetchSettingsLoader: boolean = false; - // actions - project_id: string | null = null; - projectPublishSettings: IProjectPublishSettings | "not-initialized" = "not-initialized"; + // observables + publishSettingsMap: Record = {}; // root store projectRootStore: ProjectRootStore; // services @@ -62,12 +64,10 @@ export class ProjectPublishStore implements IProjectPublishStore { generalLoader: observable.ref, fetchSettingsLoader: observable.ref, // observables - project_id: observable.ref, - projectPublishSettings: observable.ref, - // project settings actions - getProjectSettingsAsync: action, - updateProjectSettingsAsync: action, - // project publish actions + publishSettingsMap: observable, + // actions + fetchPublishSettings: action, + updatePublishSettings: action, publishProject: action, unPublishProject: action, }); @@ -77,29 +77,31 @@ export class ProjectPublishStore implements IProjectPublishStore { this.projectPublishService = new ProjectPublishService(); } + /** + * @description returns the publish settings of a particular project + * @param {string} projectID + * @returns {IProjectPublishSettings | undefined} + */ + getPublishSettingsByProjectID = (projectID: string): IProjectPublishSettings | undefined => + this.publishSettingsMap?.[projectID] ?? undefined; + /** * Fetches project publish settings * @param workspaceSlug - * @param projectId + * @param projectID * @returns */ - getProjectSettingsAsync = async (workspaceSlug: string, projectId: string) => { + fetchPublishSettings = async (workspaceSlug: string, projectID: string) => { try { runInAction(() => { this.fetchSettingsLoader = true; }); - const response = await this.projectPublishService.getProjectSettingsAsync(workspaceSlug, projectId); - if (response) { - runInAction(() => { - this.projectPublishSettings = response; - this.fetchSettingsLoader = false; - }); - } else { - runInAction(() => { - this.projectPublishSettings = "not-initialized"; - this.fetchSettingsLoader = false; - }); - } + const response = await this.projectPublishService.getProjectSettingsAsync(workspaceSlug, projectID); + + runInAction(() => { + set(this.publishSettingsMap, [projectID], response); + this.fetchSettingsLoader = false; + }); return response; } catch (error) { runInAction(() => { @@ -112,23 +114,21 @@ export class ProjectPublishStore implements IProjectPublishStore { /** * Publishes project and updates project publish status in the store * @param workspaceSlug - * @param projectId + * @param projectID * @param data * @returns */ - publishProject = async (workspaceSlug: string, projectId: string, data: IProjectPublishSettings) => { + publishProject = async (workspaceSlug: string, projectID: string, data: IProjectPublishSettings) => { try { runInAction(() => { this.generalLoader = true; }); - const response = await this.projectPublishService.createProjectSettingsAsync(workspaceSlug, projectId, data); - if (response) { - runInAction(() => { - this.projectPublishSettings = response; - set(this.projectRootStore.project.projectMap, [projectId, "is_deployed"], true); - this.generalLoader = false; - }); - } + const response = await this.projectPublishService.createProjectSettingsAsync(workspaceSlug, projectID, data); + runInAction(() => { + set(this.publishSettingsMap, [projectID], response); + set(this.projectRootStore.project.projectMap, [projectID, "is_deployed"], true); + this.generalLoader = false; + }); return response; } catch (error) { runInAction(() => { @@ -141,14 +141,14 @@ export class ProjectPublishStore implements IProjectPublishStore { /** * Updates project publish settings * @param workspaceSlug - * @param projectId + * @param projectID * @param projectPublishId * @param data * @returns */ - updateProjectSettingsAsync = async ( + updatePublishSettings = async ( workspaceSlug: string, - projectId: string, + projectID: string, projectPublishId: string, data: IProjectPublishSettings ) => { @@ -158,26 +158,15 @@ export class ProjectPublishStore implements IProjectPublishStore { }); const response = await this.projectPublishService.updateProjectSettingsAsync( workspaceSlug, - projectId, + projectID, projectPublishId, data ); - if (response) { - const _projectPublishSettings: IProjectPublishSettings = { - id: response?.id || null, - comments: response?.comments || false, - reactions: response?.reactions || false, - votes: response?.votes || false, - views: { ...response?.views }, - inbox: response?.inbox || null, - project: response?.project || null, - }; - runInAction(() => { - this.projectPublishSettings = _projectPublishSettings; - this.generalLoader = false; - }); - return response; - } + runInAction(() => { + set(this.publishSettingsMap, [projectID], response); + this.generalLoader = false; + }); + return response; } catch (error) { runInAction(() => { this.generalLoader = false; @@ -189,23 +178,23 @@ export class ProjectPublishStore implements IProjectPublishStore { /** * Unpublishes project and updates project publish status in the store * @param workspaceSlug - * @param projectId + * @param projectID * @param projectPublishId * @returns */ - unPublishProject = async (workspaceSlug: string, projectId: string, projectPublishId: string) => { + unPublishProject = async (workspaceSlug: string, projectID: string, projectPublishId: string) => { try { runInAction(() => { this.generalLoader = true; }); const response = await this.projectPublishService.deleteProjectSettingsAsync( workspaceSlug, - projectId, + projectID, projectPublishId ); runInAction(() => { - this.projectPublishSettings = "not-initialized"; - set(this.projectRootStore.project.projectMap, [projectId, "is_deployed"], false); + unset(this.publishSettingsMap, [projectID]); + set(this.projectRootStore.project.projectMap, [projectID, "is_deployed"], false); this.generalLoader = false; }); return response;