diff --git a/apps/app/components/onboarding/break-into-modules.tsx b/apps/app/components/onboarding/break-into-modules.tsx deleted file mode 100644 index e9f8c170b..000000000 --- a/apps/app/components/onboarding/break-into-modules.tsx +++ /dev/null @@ -1,33 +0,0 @@ -// next -import Image from "next/image"; -// images -import Module from "public/onboarding/module.png"; - -const BreakIntoModules: React.FC = () => ( -
-
-
- Plane- Modules -
-
-

Break into Modules

-

- Modules break your big thing into Projects or Features, to help you organize better. -

-

4/5

-
-
-); - -export default BreakIntoModules; diff --git a/apps/app/components/onboarding/command-menu.tsx b/apps/app/components/onboarding/command-menu.tsx deleted file mode 100644 index 43fa02c11..000000000 --- a/apps/app/components/onboarding/command-menu.tsx +++ /dev/null @@ -1,24 +0,0 @@ -// next -import Image from "next/image"; -// images -import Commands from "public/onboarding/command-menu.png"; - -const CommandMenu: React.FC = () => ( -
-
-
Open the contextual menu with:
-
- Plane- Issues -
-
-
-

Command Menu

-

- With Command Menu, you can create, update and navigate across the platform. -

-

5/5

-
-
- ); - -export default CommandMenu; diff --git a/apps/app/components/onboarding/index.ts b/apps/app/components/onboarding/index.ts new file mode 100644 index 000000000..4708aaaf8 --- /dev/null +++ b/apps/app/components/onboarding/index.ts @@ -0,0 +1,4 @@ +export * from "./invite-members"; +export * from "./onboarding-card"; +export * from "./user-details"; +export * from "./workspace"; \ No newline at end of file diff --git a/apps/app/components/onboarding/invite-members.tsx b/apps/app/components/onboarding/invite-members.tsx index e6fc54e37..669c30a48 100644 --- a/apps/app/components/onboarding/invite-members.tsx +++ b/apps/app/components/onboarding/invite-members.tsx @@ -4,14 +4,15 @@ import useToast from "hooks/use-toast"; import workspaceService from "services/workspace.service"; import { IUser } from "types"; // ui components -import { MultiInput, OutlineButton } from "components/ui"; +import { MultiInput, PrimaryButton, SecondaryButton } from "components/ui"; + type Props = { setStep: React.Dispatch>; workspace: any; }; -const InviteMembers: React.FC = ({ setStep, workspace }) => { +export const InviteMembers: React.FC = ({ setStep, workspace }) => { const { setToastAlert } = useToast(); const { @@ -39,43 +40,50 @@ const InviteMembers: React.FC = ({ setStep, workspace }) => { return (
{ if (e.code === "Enter") e.preventDefault(); }} > -
-
-

Invite co-workers to your team

-
-
+
+
+

Invite co-workers to your team

+
+ Email +
-
- - setStep(4)}> Skip - +
); }; - -export default InviteMembers; diff --git a/apps/app/components/onboarding/move-with-cycles.tsx b/apps/app/components/onboarding/move-with-cycles.tsx deleted file mode 100644 index d4f00370d..000000000 --- a/apps/app/components/onboarding/move-with-cycles.tsx +++ /dev/null @@ -1,34 +0,0 @@ -// next -import Image from "next/image"; -// images -import Cycle from "public/onboarding/cycle.png"; - -const MoveWithCycles: React.FC = () => ( -
-
-
- Plane- Cycles -
-
-

Move with Cycles

-

- Cycles help you and your team to progress faster, similar to the sprints commonly used in - agile development. -

-

3/5

-
-
- ); - -export default MoveWithCycles; diff --git a/apps/app/components/onboarding/onboarding-card.tsx b/apps/app/components/onboarding/onboarding-card.tsx new file mode 100644 index 000000000..d11ff14c4 --- /dev/null +++ b/apps/app/components/onboarding/onboarding-card.tsx @@ -0,0 +1,24 @@ +import React from "react"; +import Image from "next/image"; + +interface IOnboardingCard { + step: string; + title: string; + description: React.ReactNode | string; + imgURL: string; +} + +type Props = { + data: IOnboardingCard; +}; + +export const OnboardingCard: React.FC = ({ data }) => ( + <> +
+ {data.title} +
+

{data.title}

+

{data.description}

+ {data.step} + +); diff --git a/apps/app/components/onboarding/plan-with-issues.tsx b/apps/app/components/onboarding/plan-with-issues.tsx deleted file mode 100644 index cc2d3f80e..000000000 --- a/apps/app/components/onboarding/plan-with-issues.tsx +++ /dev/null @@ -1,34 +0,0 @@ -// next -import Image from "next/image"; -// images -import Issue from "public/onboarding/issue.png"; - -const PlanWithIssues: React.FC = () => ( -
-
-
- Plane- Issues -
-
-

Plan with Issues

-

- The issue is the building block of the Plane. Most concepts in Plane are either associated - with issues and their properties. -

-

2/5

-
-
- ); - -export default PlanWithIssues; diff --git a/apps/app/components/onboarding/user-details.tsx b/apps/app/components/onboarding/user-details.tsx index 99d4d5168..adff0fc11 100644 --- a/apps/app/components/onboarding/user-details.tsx +++ b/apps/app/components/onboarding/user-details.tsx @@ -1,15 +1,17 @@ import { useEffect } from "react"; -import { useForm } from "react-hook-form"; +import { Controller, useForm } from "react-hook-form"; // hooks import useToast from "hooks/use-toast"; // services import userService from "services/user.service"; // ui -import { Input } from "components/ui"; +import { CustomSelect, Input, PrimaryButton } from "components/ui"; // types import { IUser } from "types"; +// constant +import { USER_ROLE } from "constants/workspace"; const defaultValues: Partial = { first_name: "", @@ -22,12 +24,13 @@ type Props = { setStep: React.Dispatch>; }; -const UserDetails: React.FC = ({ user, setStep }) => { +export const UserDetails: React.FC = ({ user, setStep }) => { const { setToastAlert } = useToast(); const { register, handleSubmit, + control, reset, formState: { errors, isSubmitting }, } = useForm({ @@ -59,61 +62,72 @@ const UserDetails: React.FC = ({ user, setStep }) => { }, [user, reset]); return ( -
-
-
-
- + +
+
+
+
+ First name + +
+
+ Last name + +
-
- -
-
- +
+ What is your role? +
+ ( + + {USER_ROLE?.map((item) => ( + + {item.label} + + ))} + + )} + /> +
-
- +
); }; - -export default UserDetails; diff --git a/apps/app/components/onboarding/welcome.tsx b/apps/app/components/onboarding/welcome.tsx deleted file mode 100644 index dcb5b13da..000000000 --- a/apps/app/components/onboarding/welcome.tsx +++ /dev/null @@ -1,21 +0,0 @@ -// next -import Image from "next/image"; -// icons -import Logo from "public/logo.png"; - -const Welcome: React.FC = () => ( -
-
- Plane Logo -
-
-

Welcome to Plane

-

- Plane helps you plan your issues, cycles, and product modules to ship faster. -

-

1/5

-
-
- ); - -export default Welcome; diff --git a/apps/app/components/onboarding/workspace.tsx b/apps/app/components/onboarding/workspace.tsx index cacb9966e..cb151526f 100644 --- a/apps/app/components/onboarding/workspace.tsx +++ b/apps/app/components/onboarding/workspace.tsx @@ -14,13 +14,16 @@ import { IWorkspaceMemberInvitation } from "types"; import { USER_WORKSPACE_INVITATIONS } from "constants/fetch-keys"; // constants import { CreateWorkspaceForm } from "components/workspace"; +// ui +import { PrimaryButton } from "components/ui"; + type Props = { setStep: React.Dispatch>; setWorkspace: React.Dispatch>; }; -const Workspace: React.FC = ({ setStep, setWorkspace }) => { +export const Workspace: React.FC = ({ setStep, setWorkspace }) => { const [isJoiningWorkspaces, setIsJoiningWorkspaces] = useState(false); const [invitationsRespond, setInvitationsRespond] = useState([]); @@ -59,28 +62,39 @@ const Workspace: React.FC = ({ setStep, setWorkspace }) => { return (
- + - `rounded-lg px-6 py-2 ${selected ? "bg-gray-300" : "hover:bg-gray-200"}` + `rounded-3xl border px-5 py-2 outline-none ${ + selected + ? "border-theme bg-theme text-white" + : "border-gray-300 bg-white hover:bg-hover-gray" + }` } > - New workspace + New Workspace - `rounded-lg px-6 py-2 ${selected ? "bg-gray-300" : "hover:bg-gray-200"}` + `rounded-3xl border px-5 py-2 outline-none ${ + selected + ? "border-theme bg-theme text-white" + : "border-gray-300 bg-white hover:bg-hover-gray" + }` } > - Invited workspaces + Invited Workspace - + { setWorkspace(res); @@ -89,8 +103,8 @@ const Workspace: React.FC = ({ setStep, setWorkspace }) => { /> -
-
+
+
{invitations && invitations.length > 0 ? ( invitations.map((invitation) => (
@@ -149,19 +163,19 @@ const Workspace: React.FC = ({ setStep, setWorkspace }) => {
)}
-
- +
@@ -170,5 +184,3 @@ const Workspace: React.FC = ({ setStep, setWorkspace }) => {
); }; - -export default Workspace; diff --git a/apps/app/components/workspace/create-workspace-form.tsx b/apps/app/components/workspace/create-workspace-form.tsx index 4e6dc7511..189121b27 100644 --- a/apps/app/components/workspace/create-workspace-form.tsx +++ b/apps/app/components/workspace/create-workspace-form.tsx @@ -9,7 +9,7 @@ import workspaceService from "services/workspace.service"; // hooks import useToast from "hooks/use-toast"; // ui -import { CustomSelect, Input } from "components/ui"; +import { CustomSelect, Input, PrimaryButton } from "components/ui"; // types import { IWorkspace } from "types"; // fetch-keys @@ -17,6 +17,7 @@ import { USER_WORKSPACES } from "constants/fetch-keys"; // constants import { COMPANY_SIZE } from "constants/workspace"; + type Props = { onSubmit: (res: IWorkspace) => void; }; @@ -77,78 +78,87 @@ export const CreateWorkspaceForm: React.FC = ({ onSubmit }) => { }, [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/"} + +
+
+
+
+ Workspace name + setValue("slug", e.target.value.toLocaleLowerCase().trim().replace(/ /g, "-")) + } + validations={{ + required: "Workspace name is required", + }} + error={errors.name} />
- {slugError && ( - Workspace URL is already taken! - )} -
-
-
Company size
- ( - - {COMPANY_SIZE?.map((item) => ( - - {item.label} - - ))} - +
+ Workspace URL +
+ {"https://app.plane.so/"} + +
+ {slugError && ( + Workspace URL is already taken! )} - /> - {errors.company_size && ( +
+
+ +
+ How large is your company +
+ ( + + {COMPANY_SIZE?.map((item) => ( + + {item.label} + + ))} + + )} + /> + {errors.company_size && ( {errors.company_size.message} )} +
+
+ +
+ + {isSubmitting ? "Creating..." : "Create Workspace"} +
-
- -
); }; diff --git a/apps/app/constants/workspace.ts b/apps/app/constants/workspace.ts index 0feb114cb..8fdc4ee97 100644 --- a/apps/app/constants/workspace.ts +++ b/apps/app/constants/workspace.ts @@ -1,3 +1,9 @@ +import Welcome from "public/onboarding/welcome.svg"; +import Issue from "public/onboarding/issue.svg"; +import Cycle from "public/onboarding/cycle.svg"; +import Module from "public/onboarding/module.svg"; +import CommandMenu from "public/onboarding/command-menu.svg"; + export const ROLE = { 5: "Guest", 10: "Viewer", @@ -11,3 +17,49 @@ export const COMPANY_SIZE = [ { value: 25, label: "25" }, { value: 50, label: "50" }, ]; + +export const USER_ROLE = [ + { value: "Founder or leadership team", label: "Founder or leadership team" }, + { value: "Product manager", label: "Product manager" }, + { value: "Designer", label: "Designer" }, + { value: "Software developer", label: "Software developer" }, + { value: "Freelancer", label: "Freelancer" }, + { value: "Other", label: "Other" }, +]; + +export const ONBOARDING_CARDS = { + welcome: { + imgURL: Welcome, + step: "1/5", + title: "Welcome to Plane", + description: + "Plane helps you plan your issues, cycles, and product modules to ship faster.", + }, + issue: { + imgURL: Issue, + step: "2/5", + title: "Plan with Issues", + description: + "The issue is the building block of the Plane. Most concepts in Plane are either associated with issues and their properties.", + }, + cycle: { + imgURL: Cycle, + step: "3/5", + title: "Move with Cycles", + description: + "Cycles help you and your team to progress faster, similar to the sprints commonly used in agile development.", + }, + module: { + imgURL: Module, + step: "4/5", + title: "Break into Modules ", + description: + "Modules break your big think into Projects or Features , to help you organize better.", + }, + commandMenu: { + imgURL: CommandMenu, + step: "5 /5", + title: "Command Menu", + description: "With Command Menu, you can create, update and navigate across the platform.", + }, +}; diff --git a/apps/app/pages/onboarding.tsx b/apps/app/pages/onboarding.tsx index 9bae9bf9a..b2a7e987f 100644 --- a/apps/app/pages/onboarding.tsx +++ b/apps/app/pages/onboarding.tsx @@ -12,14 +12,11 @@ import useUser from "hooks/use-user"; // layouts import DefaultLayout from "layouts/default-layout"; // components -import Welcome from "components/onboarding/welcome"; -import PlanWithIssues from "components/onboarding/plan-with-issues"; -import MoveWithCycles from "components/onboarding/move-with-cycles"; -import BreakIntoModules from "components/onboarding/break-into-modules"; -import UserDetails from "components/onboarding/user-details"; -import Workspace from "components/onboarding/workspace"; -import InviteMembers from "components/onboarding/invite-members"; -import CommandMenu from "components/onboarding/command-menu"; +import { InviteMembers, OnboardingCard, UserDetails, Workspace } from "components/onboarding"; +// ui +import { PrimaryButton } from "components/ui"; +// constant +import { ONBOARDING_CARDS } from "constants/workspace"; // images import Logo from "public/onboarding/logo.svg"; // types @@ -38,9 +35,9 @@ const Onboarding: NextPage = () => {
{step <= 3 ? ( -
-
- Plane Logo +
+
+ Plane Logo
{step === 1 ? ( @@ -51,39 +48,40 @@ const Onboarding: NextPage = () => { )}
) : ( -
-
+
+
{step === 4 ? ( - + ) : step === 5 ? ( - + ) : step === 6 ? ( - + ) : step === 7 ? ( - + ) : ( - + )} -
-
- +
+ { + if (step === 8) { + userService + .updateUserOnBoard() + .then(() => { + router.push("/"); + }) + .catch((err) => { + console.log(err); + }); + } else setStep((prevData) => prevData + 1); + }} + > + {step === 4 || step === 8 ? "Get Started" : "Next"} + +
)} diff --git a/apps/app/public/onboarding/command-menu.png b/apps/app/public/onboarding/command-menu.png deleted file mode 100644 index a9b369023..000000000 Binary files a/apps/app/public/onboarding/command-menu.png and /dev/null differ diff --git a/apps/app/public/onboarding/command-menu.svg b/apps/app/public/onboarding/command-menu.svg new file mode 100644 index 000000000..71975d55e --- /dev/null +++ b/apps/app/public/onboarding/command-menu.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/apps/app/public/onboarding/cycle.png b/apps/app/public/onboarding/cycle.png deleted file mode 100644 index 8a2f2643d..000000000 Binary files a/apps/app/public/onboarding/cycle.png and /dev/null differ diff --git a/apps/app/public/onboarding/cycle.svg b/apps/app/public/onboarding/cycle.svg new file mode 100644 index 000000000..6fe945867 --- /dev/null +++ b/apps/app/public/onboarding/cycle.svg @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/app/public/onboarding/issue.png b/apps/app/public/onboarding/issue.png deleted file mode 100644 index d0e251edd..000000000 Binary files a/apps/app/public/onboarding/issue.png and /dev/null differ diff --git a/apps/app/public/onboarding/issue.svg b/apps/app/public/onboarding/issue.svg new file mode 100644 index 000000000..d1c2bb364 --- /dev/null +++ b/apps/app/public/onboarding/issue.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/app/public/onboarding/module.png b/apps/app/public/onboarding/module.png deleted file mode 100644 index 201863673..000000000 Binary files a/apps/app/public/onboarding/module.png and /dev/null differ diff --git a/apps/app/public/onboarding/module.svg b/apps/app/public/onboarding/module.svg new file mode 100644 index 000000000..87fab93c6 --- /dev/null +++ b/apps/app/public/onboarding/module.svg @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/app/public/onboarding/welcome.svg b/apps/app/public/onboarding/welcome.svg new file mode 100644 index 000000000..d53ed2d77 --- /dev/null +++ b/apps/app/public/onboarding/welcome.svg @@ -0,0 +1,5 @@ + + + + +