diff --git a/frontend/components/basic/Error.tsx b/frontend/components/basic/Error.tsx index 79cc6e5f17..b5f0b7a4c7 100644 --- a/frontend/components/basic/Error.tsx +++ b/frontend/components/basic/Error.tsx @@ -4,13 +4,13 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; export default function Error({ text }: { text: string }): JSX.Element { return ( -
+
{text && ( -

{text}

+

{text}

)}
); diff --git a/frontend/components/basic/Layout.tsx b/frontend/components/basic/Layout.tsx index 8ac9ec92b6..ef8eda727c 100644 --- a/frontend/components/basic/Layout.tsx +++ b/frontend/components/basic/Layout.tsx @@ -11,7 +11,6 @@ import { faKey, faMobile, faPlug, - faTimeline, faUser, } from "@fortawesome/free-solid-svg-icons"; import { faPlus } from "@fortawesome/free-solid-svg-icons"; @@ -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"); diff --git a/frontend/components/dashboard/DropZone.tsx b/frontend/components/dashboard/DropZone.tsx index 38e293f4e3..ffde34566a 100644 --- a/frontend/components/dashboard/DropZone.tsx +++ b/frontend/components/dashboard/DropZone.tsx @@ -216,7 +216,7 @@ const DropZone = ({
+ + Docs + +
diff --git a/frontend/components/signup/CodeInputStep.tsx b/frontend/components/signup/CodeInputStep.tsx new file mode 100644 index 0000000000..05c4973a87 --- /dev/null +++ b/frontend/components/signup/CodeInputStep.tsx @@ -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 ( +
+

+ {"We've"} sent a verification email to{" "} +

+

+ {email}{" "} +

+
+ +
+
+ +
+ {codeError && } +
+
+
+
+ + Not seeing an email? + + + + +
+

+ {t("signup:step2-spam-alert")} +

+
+
+ ); +} diff --git a/frontend/components/signup/DonwloadBackupPDFStep.tsx b/frontend/components/signup/DonwloadBackupPDFStep.tsx new file mode 100644 index 0000000000..786c49fd22 --- /dev/null +++ b/frontend/components/signup/DonwloadBackupPDFStep.tsx @@ -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 ( +
+

+ {t("signup:step4-message")} +

+
+
{t("signup:step4-description1")}
+
{t("signup:step4-description2")}
+
+
+ + {t("signup:step4-description3")} +
+
+
+
+ ); +} diff --git a/frontend/components/signup/EnterEmailStep.tsx b/frontend/components/signup/EnterEmailStep.tsx new file mode 100644 index 0000000000..5f98710b75 --- /dev/null +++ b/frontend/components/signup/EnterEmailStep.tsx @@ -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 ( +
+
+

+ {'Let\''}s get started +

+
+ +
+
+

+ {t("signup:step1-privacy")} +

+
+
+
+
+
+ + + +
+
+ ); +} diff --git a/frontend/components/signup/TeamInviteStep.tsx b/frontend/components/signup/TeamInviteStep.tsx new file mode 100644 index 0000000000..e2639b88fd --- /dev/null +++ b/frontend/components/signup/TeamInviteStep.tsx @@ -0,0 +1,72 @@ +import React, { useState } from "react"; +import { useRouter } from "next/router"; +import { useTranslation } from "next-i18next"; + +import addUserToOrg from "~/pages/api/organization/addUserToOrg"; +import getWorkspaces from "~/pages/api/workspace/getWorkspaces"; + +import Button from "../basic/buttons/Button"; + + +/** + * This is the last step of the signup flow. People can optionally invite their teammates here. + */ +export default function TeamInviteStep(): JSX.Element { + const [emails, setEmails] = useState(""); + const { t } = useTranslation(); + const router = useRouter(); + + // Redirect user to the getting started page + const redirectToHome = async () => { + const userWorkspaces = await getWorkspaces(); + const userWorkspace = userWorkspaces[0]._id; + router.push("/home/" + userWorkspace); + + } + + const inviteUsers = async ({ emails }: { emails: string; }) => { + emails + .split(',') + .map(email => email.trim()) + .map(async (email) => await addUserToOrg(email, String(localStorage.getItem('orgData.id')))); + + await redirectToHome(); + } + + return ( +
+

+ {t("signup:step5-invite-team")} +

+

+ {t("signup:step5-subtitle")} +

+
+
+
+ +
+
+