From 441cf39d2ce25af1c407341951a7efc937f2aba1 Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com> Date: Sat, 11 Mar 2023 17:23:23 +0530 Subject: [PATCH] refactor: global workspace form (#421) --- apps/app/components/onboarding/workspace.tsx | 145 ++--------------- .../workspace/create-workspace-form.tsx | 154 ++++++++++++++++++ ...eletion.tsx => delete-workspace-modal.tsx} | 4 +- apps/app/components/workspace/index.ts | 2 + .../pages/[workspaceSlug]/settings/index.tsx | 4 +- apps/app/pages/create-workspace.tsx | 151 +---------------- .../index.tsx => magic-sign-in.tsx} | 0 .../{onboarding/index.tsx => onboarding.tsx} | 0 8 files changed, 173 insertions(+), 287 deletions(-) create mode 100644 apps/app/components/workspace/create-workspace-form.tsx rename apps/app/components/workspace/{confirm-workspace-deletion.tsx => delete-workspace-modal.tsx} (98%) rename apps/app/pages/{magic-sign-in/index.tsx => magic-sign-in.tsx} (100%) rename apps/app/pages/{onboarding/index.tsx => onboarding.tsx} (100%) diff --git a/apps/app/components/onboarding/workspace.tsx b/apps/app/components/onboarding/workspace.tsx index b8011a2c0..cacb9966e 100644 --- a/apps/app/components/onboarding/workspace.tsx +++ b/apps/app/components/onboarding/workspace.tsx @@ -1,85 +1,33 @@ -import { useEffect, useState } from "react"; +import { useState } from "react"; import Image from "next/image"; import useSWR from "swr"; -import { Controller, useForm } from "react-hook-form"; - +// headless ui import { Tab } from "@headlessui/react"; - -// hooks -import useToast from "hooks/use-toast"; // services import workspaceService from "services/workspace.service"; -// ui -import { CustomSelect, Input } from "components/ui"; // types -import { IWorkspace, IWorkspaceMemberInvitation } from "types"; +import { IWorkspaceMemberInvitation } from "types"; // fetch-keys import { USER_WORKSPACE_INVITATIONS } from "constants/fetch-keys"; // constants -import { COMPANY_SIZE } from "constants/workspace"; +import { CreateWorkspaceForm } from "components/workspace"; type Props = { setStep: React.Dispatch>; setWorkspace: React.Dispatch>; }; -const defaultValues: Partial = { - name: "", - slug: "", - company_size: null, -}; - const Workspace: React.FC = ({ setStep, setWorkspace }) => { - const [slugError, setSlugError] = useState(false); const [isJoiningWorkspaces, setIsJoiningWorkspaces] = useState(false); const [invitationsRespond, setInvitationsRespond] = useState([]); - const { setToastAlert } = useToast(); - const { data: invitations, mutate } = useSWR(USER_WORKSPACE_INVITATIONS, () => workspaceService.userWorkspaceInvitations() ); - const { - register, - handleSubmit, - control, - setValue, - reset, - formState: { errors, isSubmitting }, - } = useForm({ defaultValues }); - - const handleCreateWorkspace = async (formData: IWorkspace) => { - await workspaceService - .workspaceSlugCheck(formData.slug) - .then(async (res) => { - if (res.status === true) { - setSlugError(false); - await workspaceService - .createWorkspace(formData) - .then((res) => { - console.log(res); - setToastAlert({ - type: "success", - title: "Success!", - message: "Workspace created successfully.", - }); - setWorkspace(res); - setStep(3); - }) - .catch((err) => { - console.error(err); - }); - } else setSlugError(true); - }) - .catch((err) => { - console.error(err); - }); - }; - const handleInvitation = ( workspace_invitation: IWorkspaceMemberInvitation, action: "accepted" | "withdraw" @@ -109,10 +57,6 @@ const Workspace: React.FC = ({ setStep, setWorkspace }) => { }); }; - useEffect(() => { - reset(defaultValues); - }, [reset]); - return (
@@ -136,80 +80,13 @@ const Workspace: React.FC = ({ setStep, setWorkspace }) => { - -
-
-
-
- - setValue("slug", e.target.value.toLocaleLowerCase().replace(/ /g, "-")) - } - validations={{ - required: "Workspace name is required", - }} - error={errors.name} - /> -
-
-
Workspace slug
-
- {"https://app.plane.so/"} - -
- {slugError && ( - - Workspace URL is already taken! - - )} -
-
- ( - - {COMPANY_SIZE?.map((item) => ( - - {item.label} - - ))} - - )} - /> - {errors.company_size && ( - {errors.company_size.message} - )} -
-
-
-
- -
-
+ + { + setWorkspace(res); + setStep(3); + }} + />
diff --git a/apps/app/components/workspace/create-workspace-form.tsx b/apps/app/components/workspace/create-workspace-form.tsx new file mode 100644 index 000000000..4e6dc7511 --- /dev/null +++ b/apps/app/components/workspace/create-workspace-form.tsx @@ -0,0 +1,154 @@ +import { useEffect, useState } from "react"; + +import { mutate } from "swr"; + +// react-hook-form +import { Controller, useForm } from "react-hook-form"; +// services +import workspaceService from "services/workspace.service"; +// hooks +import useToast from "hooks/use-toast"; +// ui +import { CustomSelect, Input } from "components/ui"; +// types +import { IWorkspace } from "types"; +// fetch-keys +import { USER_WORKSPACES } from "constants/fetch-keys"; +// constants +import { COMPANY_SIZE } from "constants/workspace"; + +type Props = { + onSubmit: (res: IWorkspace) => void; +}; + +const defaultValues = { + name: "", + slug: "", + company_size: null, +}; + +export const CreateWorkspaceForm: React.FC = ({ onSubmit }) => { + const [slugError, setSlugError] = useState(false); + + const { setToastAlert } = useToast(); + + const { + register, + handleSubmit, + control, + setValue, + reset, + formState: { errors, isSubmitting }, + } = useForm({ defaultValues }); + + const handleCreateWorkspace = async (formData: IWorkspace) => { + await workspaceService + .workspaceSlugCheck(formData.slug) + .then(async (res) => { + if (res.status === true) { + setSlugError(false); + await workspaceService + .createWorkspace(formData) + .then((res) => { + setToastAlert({ + type: "success", + title: "Success!", + message: "Workspace created successfully.", + }); + mutate(USER_WORKSPACES, (prevData) => [res, ...(prevData ?? [])]); + onSubmit(res); + }) + .catch((err) => { + console.error(err); + }); + } else setSlugError(true); + }) + .catch(() => { + setToastAlert({ + type: "error", + title: "Error!", + message: "Some error occurred while creating workspace. Please try again.", + }); + }); + }; + + useEffect(() => { + reset(defaultValues); + }, [reset]); + + return ( +
+
+
+
+ + setValue("slug", e.target.value.toLocaleLowerCase().trim().replace(/ /g, "-")) + } + validations={{ + required: "Workspace name is required", + }} + error={errors.name} + /> +
+
+
Workspace slug
+
+ {"https://app.plane.so/"} + +
+ {slugError && ( + Workspace URL is already taken! + )} +
+
+
Company size
+ ( + + {COMPANY_SIZE?.map((item) => ( + + {item.label} + + ))} + + )} + /> + {errors.company_size && ( + {errors.company_size.message} + )} +
+
+
+
+ +
+
+ ); +}; diff --git a/apps/app/components/workspace/confirm-workspace-deletion.tsx b/apps/app/components/workspace/delete-workspace-modal.tsx similarity index 98% rename from apps/app/components/workspace/confirm-workspace-deletion.tsx rename to apps/app/components/workspace/delete-workspace-modal.tsx index f8a407615..63ae374c6 100644 --- a/apps/app/components/workspace/confirm-workspace-deletion.tsx +++ b/apps/app/components/workspace/delete-workspace-modal.tsx @@ -25,7 +25,7 @@ type Props = { onClose: () => void; }; -const ConfirmWorkspaceDeletion: React.FC = ({ isOpen, data, onClose }) => { +export const DeleteWorkspaceModal: React.FC = ({ isOpen, data, onClose }) => { const cancelButtonRef = useRef(null); const [isDeleteLoading, setIsDeleteLoading] = useState(false); const [confirmProjectName, setConfirmProjectName] = useState(""); @@ -194,5 +194,3 @@ const ConfirmWorkspaceDeletion: React.FC = ({ isOpen, data, onClose }) => ); }; - -export default ConfirmWorkspaceDeletion; diff --git a/apps/app/components/workspace/index.ts b/apps/app/components/workspace/index.ts index 024389994..645aaed82 100644 --- a/apps/app/components/workspace/index.ts +++ b/apps/app/components/workspace/index.ts @@ -1,3 +1,5 @@ +export * from "./create-workspace-form"; +export * from "./delete-workspace-modal"; export * from "./sidebar-dropdown"; export * from "./sidebar-menu"; export * from "./help-section"; diff --git a/apps/app/pages/[workspaceSlug]/settings/index.tsx b/apps/app/pages/[workspaceSlug]/settings/index.tsx index ac38dd0ca..31ce42f1f 100644 --- a/apps/app/pages/[workspaceSlug]/settings/index.tsx +++ b/apps/app/pages/[workspaceSlug]/settings/index.tsx @@ -20,7 +20,7 @@ import AppLayout from "layouts/app-layout"; import useToast from "hooks/use-toast"; // components import { ImageUploadModal } from "components/core"; -import ConfirmWorkspaceDeletion from "components/workspace/confirm-workspace-deletion"; +import { DeleteWorkspaceModal } from "components/workspace"; // ui import { Spinner, Button, Input, CustomSelect, OutlineButton } from "components/ui"; import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; @@ -120,7 +120,7 @@ const WorkspaceSettings: NextPage = (props) => { }} value={watch("logo")} /> - { setIsOpen(false); diff --git a/apps/app/pages/create-workspace.tsx b/apps/app/pages/create-workspace.tsx index 0af942a06..2f1facb22 100644 --- a/apps/app/pages/create-workspace.tsx +++ b/apps/app/pages/create-workspace.tsx @@ -1,92 +1,22 @@ -import React, { useEffect, useState } from "react"; +import React from "react"; import { useRouter } from "next/router"; import Image from "next/image"; -import { mutate } from "swr"; - -// react-hook-form -import { Controller, useForm } from "react-hook-form"; -// services -import workspaceService from "services/workspace.service"; -// hooks -import useToast from "hooks/use-toast"; // constants import { requiredAuth } from "lib/auth"; // layouts import DefaultLayout from "layouts/default-layout"; -// ui -import { CustomSelect, Input } from "components/ui"; // images import Logo from "public/onboarding/logo.svg"; // types -import type { IWorkspace } from "types"; import type { NextPage, NextPageContext } from "next"; -// fetch-keys -import { USER_WORKSPACES } from "constants/fetch-keys"; // constants -import { COMPANY_SIZE } from "constants/workspace"; - -const defaultValues = { - name: "", - slug: "", - company_size: null, -}; +import { CreateWorkspaceForm } from "components/workspace"; const CreateWorkspace: NextPage = () => { - const [slugError, setSlugError] = useState(false); - const router = useRouter(); - const { setToastAlert } = useToast(); - - const { - register, - handleSubmit, - control, - setError, - setValue, - reset, - formState: { errors, isSubmitting }, - } = useForm({ defaultValues }); - - const onSubmit = async (formData: IWorkspace) => { - await workspaceService - .workspaceSlugCheck(formData.slug) - .then(async (res) => { - if (res.status === true) { - setSlugError(false); - await workspaceService - .createWorkspace(formData) - .then((res) => { - setToastAlert({ - type: "success", - title: "Success!", - message: "Workspace created successfully.", - }); - mutate(USER_WORKSPACES, (prevData) => [res, ...(prevData ?? [])]); - router.push(`/${formData.slug}`); - }) - .catch((err) => { - console.error(err); - }); - } else setSlugError(true); - }) - .catch((err) => { - Object.keys(err).map((key) => { - const errorMessage = err?.[key]; - if (!errorMessage) return; - setError(key as keyof IWorkspace, { - message: Array.isArray(errorMessage) ? errorMessage.join(", ") : errorMessage, - }); - }); - }); - }; - - useEffect(() => { - reset(defaultValues); - }, [reset]); - return (
@@ -96,82 +26,7 @@ const CreateWorkspace: NextPage = () => {
-
-
-
-
- - setValue( - "slug", - e.target.value.toLocaleLowerCase().trim().replace(/ /g, "-") - ) - } - validations={{ - required: "Workspace name is required", - }} - error={errors.name} - /> -
-
-
Workspace slug
-
- {"https://app.plane.so/"} - -
- {slugError && ( - - Workspace URL is already taken! - - )} -
-
- ( - - {COMPANY_SIZE?.map((item) => ( - - {item.label} - - ))} - - )} - /> - {errors.company_size && ( - {errors.company_size.message} - )} -
-
-
-
- -
-
+ router.push(`/${res.slug}`)} />
diff --git a/apps/app/pages/magic-sign-in/index.tsx b/apps/app/pages/magic-sign-in.tsx similarity index 100% rename from apps/app/pages/magic-sign-in/index.tsx rename to apps/app/pages/magic-sign-in.tsx diff --git a/apps/app/pages/onboarding/index.tsx b/apps/app/pages/onboarding.tsx similarity index 100% rename from apps/app/pages/onboarding/index.tsx rename to apps/app/pages/onboarding.tsx