import React, { useEffect, useState } from "react"; import { useRouter } from "next/router"; import useSWR, { mutate } from "swr"; // react-hook-form import { Controller, useForm } from "react-hook-form"; // services import { WorkspaceService } from "services/workspace.service"; import { FileService } from "services/file.service"; // hooks import useToast from "hooks/use-toast"; import useUserAuth from "hooks/use-user-auth"; // layouts import { WorkspaceSettingLayout } from "layouts/setting-layout/workspace-setting-layout"; // components import { ImageUploadModal } from "components/core"; import { DeleteWorkspaceModal } from "components/workspace"; import { WorkspaceSettingHeader } from "components/headers"; // ui import { Disclosure, Transition } from "@headlessui/react"; import { CustomSelect } from "components/ui"; import { Button, Input, Spinner } from "@plane/ui"; // icons import { ChevronDown, ChevronUp, Pencil } from "lucide-react"; // types import type { IWorkspace } from "types"; import type { NextPage } from "next"; // fetch-keys import { WORKSPACE_DETAILS, USER_WORKSPACES, WORKSPACE_MEMBERS_ME } from "constants/fetch-keys"; // constants import { ORGANIZATION_SIZE } from "constants/workspace"; const defaultValues: Partial = { name: "", url: "", organization_size: "2-10", logo: null, }; // services const workspaceService = new WorkspaceService(); const fileService = new FileService(); const WorkspaceSettings: NextPage = () => { const [isOpen, setIsOpen] = useState(false); const [isImageUploading, setIsImageUploading] = useState(false); const [isImageRemoving, setIsImageRemoving] = useState(false); const [isImageUploadModalOpen, setIsImageUploadModalOpen] = useState(false); const router = useRouter(); const { workspaceSlug } = router.query; const { user } = useUserAuth(); const { data: memberDetails } = useSWR( workspaceSlug ? WORKSPACE_MEMBERS_ME(workspaceSlug.toString()) : null, workspaceSlug ? () => workspaceService.workspaceMemberMe(workspaceSlug.toString()) : null ); const { setToastAlert } = useToast(); const { data: activeWorkspace } = useSWR(workspaceSlug ? WORKSPACE_DETAILS(workspaceSlug as string) : null, () => workspaceSlug ? workspaceService.getWorkspace(workspaceSlug as string) : null ); const { handleSubmit, control, reset, watch, setValue, formState: { errors, isSubmitting }, } = useForm({ defaultValues: { ...defaultValues, ...activeWorkspace }, }); useEffect(() => { if (activeWorkspace) reset({ ...activeWorkspace }); }, [activeWorkspace, reset]); const onSubmit = async (formData: IWorkspace) => { if (!activeWorkspace) return; const payload: Partial = { logo: formData.logo, name: formData.name, organization_size: formData.organization_size, }; await workspaceService .updateWorkspace(activeWorkspace.slug, payload, user) .then((res) => { mutate(USER_WORKSPACES, (prevData) => prevData?.map((workspace) => (workspace.id === res.id ? res : workspace)) ); mutate(WORKSPACE_DETAILS(workspaceSlug as string), (prevData) => { if (!prevData) return prevData; return { ...prevData, logo: formData.logo, }; }); setToastAlert({ title: "Success", type: "success", message: "Workspace updated successfully", }); }) .catch((err) => console.error(err)); }; const handleDelete = (url: string | null | undefined) => { if (!activeWorkspace || !url) return; setIsImageRemoving(true); fileService.deleteFile(activeWorkspace.id, url).then(() => { workspaceService .updateWorkspace(activeWorkspace.slug, { logo: "" }, user) .then((res) => { setToastAlert({ type: "success", title: "Success!", message: "Workspace picture removed successfully.", }); mutate(USER_WORKSPACES, (prevData) => prevData?.map((workspace) => (workspace.id === res.id ? res : workspace)) ); mutate(WORKSPACE_DETAILS(workspaceSlug as string), (prevData) => { if (!prevData) return prevData; return { ...prevData, logo: "", }; }); setIsImageUploadModalOpen(false); }) .catch(() => { setToastAlert({ type: "error", title: "Error!", message: "There was some error in deleting your profile picture. Please try again.", }); }) .finally(() => setIsImageRemoving(false)); }); }; const isAdmin = memberDetails?.role === 20; return ( }> setIsImageUploadModalOpen(false)} isRemoving={isImageRemoving} handleDelete={() => handleDelete(activeWorkspace?.logo)} onSuccess={(imageUrl) => { setIsImageUploading(true); setValue("logo", imageUrl); setIsImageUploadModalOpen(false); handleSubmit(onSubmit)().then(() => setIsImageUploading(false)); }} value={watch("logo")} /> { setIsOpen(false); }} data={activeWorkspace ?? null} user={user} /> {activeWorkspace ? (

{watch("name")}

{`${ typeof window !== "undefined" && window.location.origin.replace("http://", "").replace("https://", "") }/${activeWorkspace.slug}`}

Workspace Name

( )} />

Company Size

( c === value) ?? "Select organization size"} width="w-full" input disabled={!isAdmin} > {ORGANIZATION_SIZE?.map((item) => ( {item} ))} )} />

Workspace URL

( )} />
{isAdmin && ( {({ open }) => (
Delete Workspace {/* */} {open ? : }
The danger zone of the workspace delete page is a critical area that requires careful consideration and attention. When deleting a workspace, all of the data and resources within that workspace will be permanently removed and cannot be recovered.
)}
)}
) : (
)}
); }; export default WorkspaceSettings;