diff --git a/web/components/headers/project-issues.tsx b/web/components/headers/project-issues.tsx index 05f88cf75..f1cdef4c0 100644 --- a/web/components/headers/project-issues.tsx +++ b/web/components/headers/project-issues.tsx @@ -1,9 +1,9 @@ -import { useCallback, useState, FC } from "react"; +import { useCallback, useState } from "react"; import Link from "next/link"; import { useRouter } from "next/router"; import { observer } from "mobx-react-lite"; -import { ArrowLeft, Plus } from "lucide-react"; -// hooks +import { ArrowLeft, Circle, ExternalLink, Plus } from "lucide-react"; +// mobx store import { useMobxStore } from "lib/mobx/store-provider"; // components import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "components/issues"; @@ -17,7 +17,7 @@ import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "constants/issue"; // helper import { truncateText } from "helpers/string.helper"; -export const ProjectIssuesHeader: FC = observer(() => { +export const ProjectIssuesHeader: React.FC = observer(() => { const [analyticsModal, setAnalyticsModal] = useState(false); const router = useRouter(); @@ -93,6 +93,8 @@ export const ProjectIssuesHeader: FC = observer(() => { const inboxDetails = projectId ? inboxStore.inboxesList?.[projectId.toString()]?.[0] : undefined; + const deployUrl = process.env.NEXT_PUBLIC_DEPLOY_URL; + return ( <> { + {projectDetails?.is_deployed && deployUrl && ( + + + Public + + + )}
= observer((props) => {
- {layout === "month" ? ( + {layout === "month" && (
{allWeeksOfActiveMonth && Object.values(allWeeksOfActiveMonth).map((week: ICalendarWeek, weekIndex) => ( ))}
- ) : ( + )} + {layout === "week" && ( )}
diff --git a/web/components/project/index.ts b/web/components/project/index.ts index 9191a88bc..ff0213d52 100644 --- a/web/components/project/index.ts +++ b/web/components/project/index.ts @@ -15,3 +15,4 @@ export * from "./join-project-modal"; export * from "./form"; export * from "./form-loader"; export * from "./delete-project-section"; +export * from "./publish-project"; diff --git a/web/components/project/publish-project/modal.tsx b/web/components/project/publish-project/modal.tsx index 85f8c4171..fe31dfe65 100644 --- a/web/components/project/publish-project/modal.tsx +++ b/web/components/project/publish-project/modal.tsx @@ -1,27 +1,24 @@ import React, { useEffect, useState } from "react"; -// next imports import { useRouter } from "next/router"; -// react-hook-form +import { observer } from "mobx-react-lite"; import { Controller, useForm } from "react-hook-form"; -// headless ui import { Dialog, Transition } from "@headlessui/react"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; // ui components import { Button, Loader, ToggleSwitch } from "@plane/ui"; import { Check, CircleDot, Globe2 } from "lucide-react"; import { CustomPopover } from "./popover"; -// mobx react lite -import { observer } from "mobx-react-lite"; -// mobx store -import { useMobxStore } from "lib/mobx/store-provider"; -import { RootStore } from "store/root"; import { IProjectPublishSettings, TProjectPublishViews } from "store/project"; // hooks import useToast from "hooks/use-toast"; -import useProjectDetails from "hooks/use-project-details"; -import useUser from "hooks/use-user"; +// types +import { IProject } from "types"; type Props = { - // user: IUser | undefined; + isOpen: boolean; + project: IProject; + onClose: () => void; }; type FormData = { @@ -53,26 +50,24 @@ const viewOptions: { // { key: "spreadsheet", label: "Spreadsheet" }, ]; -export const PublishProjectModal: React.FC = observer(() => { +export const PublishProjectModal: React.FC = observer((props) => { + const { isOpen, project, onClose } = props; + const [isUnpublishing, setIsUnpublishing] = useState(false); const [isUpdateRequired, setIsUpdateRequired] = useState(false); let plane_deploy_url = process.env.NEXT_PUBLIC_DEPLOY_URL; - if (typeof window !== "undefined" && !plane_deploy_url) { + if (typeof window !== "undefined" && !plane_deploy_url) plane_deploy_url = window.location.protocol + "//" + window.location.host + "/spaces"; - } - // router + const router = useRouter(); const { workspaceSlug } = router.query; - // store - const store: RootStore = useMobxStore(); - const { projectPublish } = store; - // hooks - const { user } = useUser(); - const { mutateProjectDetails } = useProjectDetails(); + + const { projectPublish: projectPublishStore } = useMobxStore(); + const { setToastAlert } = useToast(); - // form info + const { control, formState: { isSubmitting }, @@ -80,23 +75,27 @@ export const PublishProjectModal: React.FC = observer(() => { handleSubmit, reset, watch, - } = useForm({ + } = useForm({ defaultValues, }); const handleClose = () => { - projectPublish.handleProjectModal(null); + onClose(); + setIsUpdateRequired(false); reset({ ...defaultValues }); }; // prefill form with the saved settings if the project is already published useEffect(() => { - if (projectPublish.projectPublishSettings && projectPublish.projectPublishSettings !== "not-initialized") { + if ( + projectPublishStore.projectPublishSettings && + projectPublishStore.projectPublishSettings !== "not-initialized" + ) { let userBoards: TProjectPublishViews[] = []; - if (projectPublish.projectPublishSettings?.views) { - const savedViews = projectPublish.projectPublishSettings?.views; + if (projectPublishStore.projectPublishSettings?.views) { + const savedViews = projectPublishStore.projectPublishSettings?.views; if (!savedViews) return; @@ -110,61 +109,46 @@ export const PublishProjectModal: React.FC = observer(() => { } const updatedData = { - id: projectPublish.projectPublishSettings?.id || null, - comments: projectPublish.projectPublishSettings?.comments || false, - reactions: projectPublish.projectPublishSettings?.reactions || false, - votes: projectPublish.projectPublishSettings?.votes || false, - inbox: projectPublish.projectPublishSettings?.inbox || null, + id: projectPublishStore.projectPublishSettings?.id || null, + comments: projectPublishStore.projectPublishSettings?.comments || false, + reactions: projectPublishStore.projectPublishSettings?.reactions || false, + votes: projectPublishStore.projectPublishSettings?.votes || false, + inbox: projectPublishStore.projectPublishSettings?.inbox || null, views: userBoards, }; reset({ ...updatedData }); } - }, [reset, projectPublish.projectPublishSettings]); + }, [reset, projectPublishStore.projectPublishSettings]); // fetch publish settings useEffect(() => { - if (!workspaceSlug) return; + if (!workspaceSlug || !isOpen) return; - if ( - projectPublish.projectPublishModal && - projectPublish.project_id !== null && - projectPublish?.projectPublishSettings === "not-initialized" - ) { - projectPublish.getProjectSettingsAsync(workspaceSlug.toString(), projectPublish.project_id, null); + if (projectPublishStore.projectPublishSettings === "not-initialized") { + projectPublishStore.getProjectSettingsAsync(workspaceSlug.toString(), project.id); } - }, [workspaceSlug, projectPublish, projectPublish.projectPublishModal]); + }, [isOpen, workspaceSlug, project, projectPublishStore]); const handlePublishProject = async (payload: IProjectPublishSettings) => { - if (!workspaceSlug || !user) return; + if (!workspaceSlug) return; - const projectId = projectPublish.project_id; - - return projectPublish - .publishProject(workspaceSlug.toString(), projectId?.toString() ?? "", payload, user) + return projectPublishStore + .publishProject(workspaceSlug.toString(), project.id, payload) .then((res) => { - mutateProjectDetails(); handleClose(); - if (projectId) window.open(`${plane_deploy_url}/${workspaceSlug}/${projectId}`, "_blank"); + // window.open(`${plane_deploy_url}/${workspaceSlug}/${project.id}`, "_blank"); return res; }) .catch((err) => err); }; const handleUpdatePublishSettings = async (payload: IProjectPublishSettings) => { - if (!workspaceSlug || !user) return; + if (!workspaceSlug) return; - await projectPublish - .updateProjectSettingsAsync( - workspaceSlug.toString(), - projectPublish.project_id?.toString() ?? "", - payload.id ?? "", - payload, - user - ) + await projectPublishStore + .updateProjectSettingsAsync(workspaceSlug.toString(), project.id, payload.id ?? "", payload) .then((res) => { - mutateProjectDetails(); - setToastAlert({ type: "success", title: "Success!", @@ -185,15 +169,19 @@ export const PublishProjectModal: React.FC = observer(() => { setIsUnpublishing(true); - projectPublish - .unPublishProject(workspaceSlug.toString(), projectPublish.project_id as string, publishId, null) + await projectPublishStore + .unPublishProject(workspaceSlug.toString(), project.id, publishId) .then((res) => { - mutateProjectDetails(); - handleClose(); return res; }) - .catch((err) => err) + .catch(() => + setToastAlert({ + type: "error", + title: "Error!", + message: "Something went wrong while unpublishing the project.", + }) + ) .finally(() => setIsUnpublishing(false)); }; @@ -242,15 +230,16 @@ export const PublishProjectModal: React.FC = observer(() => { }, }; - if (watch("id")) await handleUpdatePublishSettings({ id: watch("id") ?? "", ...payload }); + if (project.is_deployed) await handleUpdatePublishSettings({ id: watch("id") ?? "", ...payload }); else await handlePublishProject(payload); }; // check if an update is required or not const checkIfUpdateIsRequired = () => { - if (!projectPublish.projectPublishSettings || projectPublish.projectPublishSettings === "not-initialized") return; + if (!projectPublishStore.projectPublishSettings || projectPublishStore.projectPublishSettings === "not-initialized") + return; - const currentSettings = projectPublish.projectPublishSettings as IProjectPublishSettings; + const currentSettings = projectPublishStore.projectPublishSettings as IProjectPublishSettings; const newSettings = getValues(); if ( @@ -276,7 +265,7 @@ export const PublishProjectModal: React.FC = observer(() => { }; return ( - + = observer(() => { leaveFrom="opacity-100 translate-y-0 sm:scale-100" leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" > - +
{/* heading */}
Publish
- {projectPublish.projectPublishSettings !== "not-initialized" && ( + {project.is_deployed && (
{/* content */} - {projectPublish.fetchSettingsLoader ? ( + {projectPublishStore.fetchSettingsLoader ? ( @@ -327,16 +316,14 @@ export const PublishProjectModal: React.FC = observer(() => { ) : (
- {watch("id") && ( + {project.is_deployed && ( <>
- {`${plane_deploy_url}/${workspaceSlug}/${projectPublish.project_id}`} + {`${plane_deploy_url}/${workspaceSlug}/${project.id}`}
- +
@@ -454,6 +441,7 @@ export const PublishProjectModal: React.FC = observer(() => { />
+ {/* toggle inbox */} {/*
Allow issue proposals
= observer(() => {
Anyone with the link can access
- {!projectPublish.fetchSettingsLoader && ( + {!projectPublishStore.fetchSettingsLoader && (
- {watch("id") ? ( + {project.is_deployed ? ( <> {isUpdateRequired && (