Skip to content

Commit

Permalink
Merge pull request #203 from Infisical/signup-flow
Browse files Browse the repository at this point in the history
Refactor of the signup flow
  • Loading branch information
vmatsiiako authored Jan 8, 2023
2 parents f3f6871 + 6de4eca commit 0312891
Show file tree
Hide file tree
Showing 16 changed files with 716 additions and 516 deletions.
6 changes: 3 additions & 3 deletions frontend/components/basic/Error.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";

export default function Error({ text }: { text: string }): JSX.Element {
return (
<div className="relative bg-red-500 opacity-100 border flex flex-row justify-center m-auto items-center w-fit rounded-full mb-4">
<div className="relative flex flex-row justify-center m-auto items-center w-fit rounded-full">
<FontAwesomeIcon
icon={faExclamationTriangle}
className="text-white mt-1.5 mb-2 mx-2"
className="text-red mt-1.5 mb-2 mx-2"
/>
{text && (
<p className="relative top-0 text-white mr-2 text-sm py-1">{text}</p>
<p className="relative top-0 text-red mr-2 text-sm py-1">{text}</p>
)}
</div>
);
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/basic/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {
faKey,
faMobile,
faPlug,
faTimeline,
faUser,
} from "@fortawesome/free-solid-svg-icons";
import { faPlus } from "@fortawesome/free-solid-svg-icons";
Expand Down Expand Up @@ -184,6 +183,7 @@ export default function Layout({ children }: LayoutProps) {
if (
userWorkspaces.length == 0 &&
router.asPath != "/noprojects" &&
!router.asPath.includes("home")&&
!router.asPath.includes("settings")
) {
router.push("/noprojects");
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/dashboard/DropZone.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ const DropZone = ({
<div className="z-10 mb-6">
<Button
color="mineshaft"
text="Create a new .env file"
text={String(t("dashboard:add-secret"))}
onButtonPressed={createNewFile}
size="md"
/>
Expand Down
9 changes: 9 additions & 0 deletions frontend/components/navigation/NavBarDashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
faGear,
faPlus,
faRightFromBracket,
faUpRightFromSquare,
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Menu, Transition } from "@headlessui/react";
Expand Down Expand Up @@ -107,6 +108,14 @@ export default function Navbar() {
</div>
</div>
<div className="relative flex justify-start items-center mx-2 z-40">
<a
href="https://infisical.com/docs/getting-started/introduction"
target="_blank"
rel="noopener noreferrer"
className="text-gray-200 hover:text-primary duration-200">
Docs
<FontAwesomeIcon icon={faUpRightFromSquare} className="text-xs mb-[0.1rem] mr-5 ml-1.5" />
</a>
<Menu as="div" className="relative inline-block text-left">
<div className="mr-4">
<Menu.Button className="inline-flex w-full justify-center rounded-md px-2 py-2 text-sm font-medium text-gray-200 rounded-md hover:bg-white/10 duration-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75">
Expand Down
136 changes: 136 additions & 0 deletions frontend/components/signup/CodeInputStep.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import React, { useState } from "react";
import ReactCodeInput from "react-code-input";
import { useTranslation } from "next-i18next";

import sendVerificationEmail from "~/pages/api/auth/SendVerificationEmail";

import Button from "../basic/buttons/Button";
import Error from "../basic/Error";


// The style for the verification code input
const props = {
inputStyle: {
fontFamily: "monospace",
margin: "4px",
MozAppearance: "textfield",
width: "55px",
borderRadius: "5px",
fontSize: "24px",
height: "55px",
paddingLeft: "7",
backgroundColor: "#0d1117",
color: "white",
border: "1px solid #2d2f33",
textAlign: "center",
outlineColor: "#8ca542",
borderColor: "#2d2f33"
},
} as const;
const propsPhone = {
inputStyle: {
fontFamily: "monospace",
margin: "4px",
MozAppearance: "textfield",
width: "40px",
borderRadius: "5px",
fontSize: "24px",
height: "40px",
paddingLeft: "7",
backgroundColor: "#0d1117",
color: "white",
border: "1px solid #2d2f33",
textAlign: "center",
outlineColor: "#8ca542",
borderColor: "#2d2f33"
},
} as const;

interface CodeInputStepProps {
email: string;
incrementStep: () => void;
setCode: (value: string) => void;
codeError: boolean;
}

/**
* This is the second step of sign up where users need to verify their email
* @param {object} obj
* @param {string} obj.email - user's email to which we just sent a verification email
* @param {function} obj.incrementStep - goes to the next step of signup
* @param {function} obj.setCode - state updating function that set the current value of the emai verification code
* @param {boolean} obj.codeError - whether the code was inputted wrong or now
* @returns
*/
export default function CodeInputStep({ email, incrementStep, setCode, codeError }: CodeInputStepProps): JSX.Element {
const [isLoading, setIsLoading] = useState(false);
const [isResendingVerificationEmail, setIsResendingVerificationEmail] =
useState(false);
const { t } = useTranslation();

const resendVerificationEmail = async () => {
setIsResendingVerificationEmail(true);
setIsLoading(true);
sendVerificationEmail(email);
setTimeout(() => {
setIsLoading(false);
setIsResendingVerificationEmail(false);
}, 2000);
};

return (
<div className="bg-bunker w-max mx-auto h-7/12 pt-10 pb-4 px-8 rounded-xl drop-shadow-xl mb-64 md:mb-16">
<p className="text-l flex justify-center text-bunker-300">
{"We've"} sent a verification email to{" "}
</p>
<p className="text-l flex justify-center font-semibold my-2 text-bunker-300">
{email}{" "}
</p>
<div className="hidden md:block">
<ReactCodeInput
name=""
inputMode="tel"
type="text"
fields={6}
onChange={setCode}
{...props}
className="mt-6 mb-2"
/>
</div>
<div className="block md:hidden">
<ReactCodeInput
name=""
inputMode="tel"
type="text"
fields={6}
onChange={setCode}
{...propsPhone}
className="mt-2 mb-6"
/>
</div>
{codeError && <Error text={t("signup:step2-code-error")} />}
<div className="flex max-w-max min-w-28 flex-col items-center justify-center md:p-2 max-h-24 mx-auto text-lg px-4 mt-4 mb-2">
<Button
text={t("signup:verify") ?? ""}
onButtonPressed={incrementStep}
size="lg"
/>
</div>
<div className="flex flex-col items-center justify-center w-full max-h-24 max-w-md mx-auto pt-2">
<div className="flex flex-row items-baseline gap-1 text-sm">
<span className="text-bunker-400">
Not seeing an email?
</span>
<u className={`font-normal ${isResendingVerificationEmail ? 'text-bunker-400' : 'text-primary-700 hover:text-primary duration-200'}`}>
<button disabled={isLoading} onClick={resendVerificationEmail}>
{isResendingVerificationEmail ? "Resending..." : "Resend"}
</button>
</u>
</div>
<p className="text-sm text-bunker-400 pb-2">
{t("signup:step2-spam-alert")}
</p>
</div>
</div>
);
}
60 changes: 60 additions & 0 deletions frontend/components/signup/DonwloadBackupPDFStep.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import React from "react";
import { useTranslation } from "next-i18next";
import { faWarning } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";

import Button from "../basic/buttons/Button";
import issueBackupKey from "../utilities/cryptography/issueBackupKey";


interface DownloadBackupPDFStepProps {
incrementStep: () => void;
email: string;
password: string;
name: string;
}

/**
* This is the step of the signup flow where the user downloads the backup pdf
* @param {object} obj
* @param {function} obj.incrementStep - function that moves the user on to the next stage of signup
* @param {string} obj.email - user's email
* @param {string} obj.password - user's password
* @param {string} obj.name - user's name
* @returns
*/
export default function DonwloadBackupPDFStep({ incrementStep, email, password, name }: DownloadBackupPDFStepProps): JSX.Element {
const { t } = useTranslation();

return (
<div className="bg-bunker flex flex-col items-center w-full max-w-xs md:max-w-lg mx-auto h-7/12 py-8 px-4 md:px-6 mx-1 mb-36 md:mb-16 rounded-xl drop-shadow-xl">
<p className="text-4xl text-center font-semibold flex justify-center text-transparent bg-clip-text bg-gradient-to-br from-sky-400 to-primary">
{t("signup:step4-message")}
</p>
<div className="flex flex-col items-center justify-center w-full mt-4 md:mt-8 max-w-md text-gray-400 text-md rounded-md px-2">
<div>{t("signup:step4-description1")}</div>
<div className="mt-3">{t("signup:step4-description2")}</div>
</div>
<div className="w-full p-2 flex flex-row items-center bg-white/10 text-gray-400 rounded-md max-w-xs md:max-w-md mx-auto mt-4">
<FontAwesomeIcon icon={faWarning} className="ml-2 mr-4 text-4xl" />
{t("signup:step4-description3")}
</div>
<div className="flex flex-col items-center justify-center md:px-4 md:py-5 mt-2 px-2 py-3 max-h-24 max-w-max mx-auto text-lg">
<Button
text="Download PDF"
onButtonPressed={async () => {
await issueBackupKey({
email,
password,
personalName: name,
setBackupKeyError: (value: boolean) => {},
setBackupKeyIssued: (value: boolean) => {},
});
incrementStep();
}}
size="lg"
/>
</div>
</div>
);
}
97 changes: 97 additions & 0 deletions frontend/components/signup/EnterEmailStep.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import React, { useState } from "react";
import Link from "next/link";
import { useTranslation } from "next-i18next";

import sendVerificationEmail from "~/pages/api/auth/SendVerificationEmail";

import Button from "../basic/buttons/Button";
import InputField from "../basic/InputField";


interface DownloadBackupPDFStepProps {
incrementStep: () => void;
email: string;
setEmail: (value: string) => void;
}

/**
* This is the first step of the sign up process - users need to enter their email
* @param {object} obj
* @param {string} obj.email - email of a user signing up
* @param {function} obj.setEmail - funciton that manages the state of the email variable
* @param {function} obj.incrementStep - function to go to the next step of the signup flow
* @returns
*/
export default function EnterEmailStep({ email, setEmail, incrementStep }: DownloadBackupPDFStepProps): JSX.Element {
const [emailError, setEmailError] = useState(false);
const [emailErrorMessage, setEmailErrorMessage] = useState("");
const { t } = useTranslation();

/**
* Verifies if the entered email "looks" correct
*/
const emailCheck = () => {
let emailCheckBool = false;
if (!email) {
setEmailError(true);
setEmailErrorMessage("Please enter your email.");
emailCheckBool = true;
} else if (
!email.includes("@") ||
!email.includes(".") ||
!/[a-z]/.test(email)
) {
setEmailError(true);
setEmailErrorMessage("Please enter a valid email.");
emailCheckBool = true;
} else {
setEmailError(false);
}

// If everything is correct, go to the next step
if (!emailCheckBool) {
sendVerificationEmail(email);
incrementStep();
}
};

return (
<div>
<div className="bg-bunker w-full max-w-md mx-auto h-7/12 py-8 md:px-6 mx-1 rounded-xl drop-shadow-xl">
<p className="text-4xl font-semibold flex justify-center text-primary">
{'Let\''}s get started
</p>
<div className="flex items-center justify-center w-5/6 md:w-full m-auto md:p-2 rounded-lg max-h-24 mt-4">
<InputField
label="Email"
onChangeHandler={setEmail}
type="email"
value={email}
placeholder=""
isRequired
error={emailError}
errorText={emailErrorMessage}
autoComplete="username"
/>
</div>
<div className="flex flex-col items-center justify-center w-5/6 md:w-full md:p-2 max-h-28 max-w-xs md:max-w-md mx-auto mt-4 md:mt-4 text-sm text-center md:text-left">
<p className="text-gray-400 mt-2 md:mx-0.5">
{t("signup:step1-privacy")}
</p>
<div className="text-l mt-6 m-2 md:m-8 px-8 py-1 text-lg">
<Button text="Get Started" type="submit" onButtonPressed={emailCheck} size="lg" />
</div>
</div>
</div>
<div className="flex flex-col items-center justify-center w-full md:pb-2 max-w-md mx-auto pt-2 mb-48 md:mb-16 mt-2">
<Link href="/login">
<button type="button" className="w-max pb-3 hover:opacity-90 duration-200">
<u className="font-normal text-sm text-primary-500">
{t("signup:already-have-account")}
</u>
</button>
</Link>
</div>
</div>
);
}
Loading

5 comments on commit 0312891

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coverage report for backend

St.
Category Percentage Covered / Total
🟡 Statements 72.97% 54/74
🔴 Branches 0% 0/5
🔴 Functions 50% 1/2
🟡 Lines 73.97% 54/73

Test suite run success

1 tests passing in 1 suite.

Report generated by 🧪jest coverage report action from 0312891

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coverage report for backend

St.
Category Percentage Covered / Total
🟡 Statements 72.97% 54/74
🔴 Branches 0% 0/5
🔴 Functions 50% 1/2
🟡 Lines 73.97% 54/73

Test suite run success

1 tests passing in 1 suite.

Report generated by 🧪jest coverage report action from 0312891

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coverage report for backend

St.
Category Percentage Covered / Total
🟡 Statements 72.97% 54/74
🔴 Branches 0% 0/5
🔴 Functions 50% 1/2
🟡 Lines 73.97% 54/73

Test suite run success

1 tests passing in 1 suite.

Report generated by 🧪jest coverage report action from 0312891

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coverage report for backend

St.
Category Percentage Covered / Total
🟡 Statements 72.97% 54/74
🔴 Branches 0% 0/5
🔴 Functions 50% 1/2
🟡 Lines 73.97% 54/73

Test suite run success

1 tests passing in 1 suite.

Report generated by 🧪jest coverage report action from 0312891

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coverage report for backend

St.
Category Percentage Covered / Total
🟡 Statements 72.97% 54/74
🔴 Branches 0% 0/5
🔴 Functions 50% 1/2
🟡 Lines 73.97% 54/73

Test suite run success

1 tests passing in 1 suite.

Report generated by 🧪jest coverage report action from 0312891

Please sign in to comment.