diff --git a/backend/src/helpers/signup.ts b/backend/src/helpers/signup.ts index 410c442b35..e26b9b3606 100644 --- a/backend/src/helpers/signup.ts +++ b/backend/src/helpers/signup.ts @@ -106,7 +106,7 @@ const initializeDefaultOrg = async ({ // initialize a default workspace inside the new organization const workspace = await createWorkspace({ - name: `${user.firstName}'s Project`, + name: `Example Project`, organizationId: organization._id.toString() }); diff --git a/frontend/components/basic/InputField.js b/frontend/components/basic/InputField.tsx similarity index 89% rename from frontend/components/basic/InputField.js rename to frontend/components/basic/InputField.tsx index 8368d97976..02bb8a8cc8 100644 --- a/frontend/components/basic/InputField.js +++ b/frontend/components/basic/InputField.tsx @@ -1,19 +1,27 @@ -import React from "react"; -import { useState } from "react"; +import React, { useState } from "react"; import { useRouter } from "next/router"; -import { - faCircle, - faCircleExclamation, - faE, - faEye, - faEyeSlash, -} from "@fortawesome/free-solid-svg-icons"; +import { faCircle, faEye, faEyeSlash } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import guidGenerator from "../utilities/randomId"; -import Error from "./Error"; -const InputField = (props) => { +interface InputFieldProps { + static?: boolean; + label: string; + type: string; + value: string; + placeholder?: string; + isRequired: boolean; + disabled?: boolean; + error?: boolean; + text?: string; + name?: string; + blurred?: boolean; + errorText?: string; + onChangeHandler: (value: string) => void; +} + +const InputField = (props: InputFieldProps) => { const [passwordVisible, setPasswordVisible] = useState(false); const router = useRouter(); @@ -67,7 +75,7 @@ const InputField = (props) => { > props.onChangeHandler(e.target.value)} - type={passwordVisible == false ? props.type : "text"} + type={passwordVisible === false ? props.type : "text"} placeholder={props.placeholder} value={props.value} required={props.isRequired} diff --git a/frontend/components/basic/layout.js b/frontend/components/basic/Layout.tsx similarity index 55% rename from frontend/components/basic/layout.js rename to frontend/components/basic/Layout.tsx index effe389427..4a40fdef08 100644 --- a/frontend/components/basic/layout.js +++ b/frontend/components/basic/Layout.tsx @@ -1,3 +1,4 @@ +/* eslint-disable no-unexpected-multiline */ /* eslint-disable react-hooks/exhaustive-deps */ import { useEffect, useState } from "react"; import Link from "next/link"; @@ -22,6 +23,7 @@ import getWorkspaces from "~/pages/api/workspace/getWorkspaces"; import uploadKeys from "~/pages/api/workspace/uploadKeys"; import NavBarDashboard from "../navigation/NavBarDashboard"; +import { tempLocalStorage } from "../utilities/checks/tempLocalStorage"; import { decryptAssymmetric, encryptAssymmetric, @@ -30,13 +32,17 @@ import Button from "./buttons/Button"; import AddWorkspaceDialog from "./dialog/AddWorkspaceDialog"; import Listbox from "./Listbox"; -export default function Layout({ children }) { +interface LayoutProps { + children: React.ReactNode; +} + +export default function Layout({ children }: LayoutProps) { const router = useRouter(); const [workspaceList, setWorkspaceList] = useState([]); const [workspaceMapping, setWorkspaceMapping] = useState([{ 1: 2 }]); const [workspaceSelected, setWorkspaceSelected] = useState("∞"); - let [newWorkspaceName, setNewWorkspaceName] = useState(""); - let [isOpen, setIsOpen] = useState(false); + const [newWorkspaceName, setNewWorkspaceName] = useState(""); + const [isOpen, setIsOpen] = useState(false); const [loading, setLoading] = useState(false); const [error, setError] = useState(false); @@ -44,158 +50,186 @@ export default function Layout({ children }) { setIsOpen(false); } + function openModal() { + setIsOpen(true); + } + // TODO: what to do about the fact that 2ids can have the same name /** * When a user creates a new workspace, redirect them to the page of the new workspace. * @param {*} workspaceName */ - async function submitModal(workspaceName, addAllUsers) { + async function submitModal(workspaceName: string, addAllUsers: boolean) { setLoading(true); + // timeout code. setTimeout(() => setLoading(false), 1500); - const workspaces = await getWorkspaces(); - const currentWorkspaces = workspaces.map((workspace) => workspace.name); - if (!currentWorkspaces.includes(workspaceName)) { - const newWorkspace = await createWorkspace({ - workspaceName, - organizationId: localStorage.getItem("orgData.id") - }); - let newWorkspaceId; - try { - newWorkspaceId = newWorkspace._id; - } catch (error) { - console.log(error); - } - if (addAllUsers) { - let orgUsers = await getOrganizationUsers({ - orgId: localStorage.getItem("orgData.id"), + + try { + const workspaces = await getWorkspaces(); + const currentWorkspaces = workspaces.map((workspace) => workspace.name); + if (!currentWorkspaces.includes(workspaceName)) { + const newWorkspace = await createWorkspace({ + workspaceName, + organizationId: tempLocalStorage("orgData.id"), }); - orgUsers.map(async (user) => { - if (user.status == "accepted") { - let result = await addUserToWorkspace( - user.user.email, - newWorkspaceId - ); - if (result?.invitee && result?.latestKey) { - const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY"); + const newWorkspaceId = newWorkspace._id; - // assymmetrically decrypt symmetric key with local private key - const key = decryptAssymmetric({ - ciphertext: result.latestKey.encryptedKey, - nonce: result.latestKey.nonce, - publicKey: result.latestKey.sender.publicKey, - privateKey: PRIVATE_KEY, - }); + if (addAllUsers) { + const orgUsers = await getOrganizationUsers({ + orgId: tempLocalStorage("orgData.id"), + }); + orgUsers.map(async (user: any) => { + if (user.status == "accepted") { + const result = await addUserToWorkspace( + user.user.email, + newWorkspaceId + ); + if (result?.invitee && result?.latestKey) { + const PRIVATE_KEY = tempLocalStorage("PRIVATE_KEY"); - const { ciphertext, nonce } = encryptAssymmetric({ - plaintext: key, - publicKey: result.invitee.publicKey, - privateKey: PRIVATE_KEY, - }); + // assymmetrically decrypt symmetric key with local private key + const key = decryptAssymmetric({ + ciphertext: result.latestKey.encryptedKey, + nonce: result.latestKey.nonce, + publicKey: result.latestKey.sender.publicKey, + privateKey: PRIVATE_KEY, + }); - uploadKeys(newWorkspaceId, result.invitee._id, ciphertext, nonce); + const { ciphertext, nonce } = encryptAssymmetric({ + plaintext: key, + publicKey: result.invitee.publicKey, + privateKey: PRIVATE_KEY, + }) as { ciphertext: string; nonce: string }; + + uploadKeys( + newWorkspaceId, + result.invitee._id, + ciphertext, + nonce + ); + } } - } - }); + }); + } + router.push("/dashboard/" + newWorkspaceId + "?Development"); + setIsOpen(false); + setNewWorkspaceName(""); + } else { + console.error("A project with this name already exists."); + setError(true); + setLoading(false); } - router.push("/dashboard/" + newWorkspaceId + "?Development"); - setIsOpen(false); - setNewWorkspaceName(""); - } else { - setError("A project with this name already exists."); + } catch (err) { + console.error(err); + setError(true); setLoading(false); } } - function openModal() { - setIsOpen(true); - } - const menuItems = [ { href: - "/dashboard/" + workspaceMapping[workspaceSelected] + "?Development", + "/dashboard/" + + workspaceMapping[workspaceSelected as any] + + "?Development", title: "Secrets", emoji: , }, { - href: "/users/" + workspaceMapping[workspaceSelected], + href: "/users/" + workspaceMapping[workspaceSelected as any], title: "Members", emoji: , }, { - href: "/integrations/" + workspaceMapping[workspaceSelected], + href: "/integrations/" + workspaceMapping[workspaceSelected as any], title: "Integrations", emoji: , }, { - href: "/settings/project/" + workspaceMapping[workspaceSelected], + href: "/settings/project/" + workspaceMapping[workspaceSelected as any], title: "Project Settings", emoji: , }, ]; - useEffect(async () => { + useEffect(() => { // Put a user in a workspace if they're not in one yet - if ( - localStorage.getItem("orgData.id") == null || - localStorage.getItem("orgData.id") == "" - ) { - const userOrgs = await getOrganizations(); - localStorage.setItem("orgData.id", userOrgs[0]._id); - } + const putUserInWorkSpace = async () => { + if (tempLocalStorage("orgData.id") === "") { + const userOrgs = await getOrganizations(); + localStorage.setItem("orgData.id", userOrgs[0]._id); + } - let orgUserProjects = await getOrganizationUserProjects({ - orgId: localStorage.getItem("orgData.id"), - }); - let userWorkspaces = orgUserProjects; - if ( - userWorkspaces.length == 0 && - router.asPath != "/noprojects" && - !router.asPath.includes("settings") - ) { - router.push("/noprojects"); - } else if (router.asPath != "/noprojects") { - const intendedWorkspaceId = router.asPath - .split("/")[router.asPath.split("/").length - 1].split("?")[0]; - // If a user is not a member of a workspace they are trying to access, just push them to one of theirs + const orgUserProjects = await getOrganizationUserProjects({ + orgId: tempLocalStorage("orgData.id"), + }); + const userWorkspaces = orgUserProjects; if ( - intendedWorkspaceId != "heroku" && - !userWorkspaces - .map((workspace) => workspace._id) - .includes(intendedWorkspaceId) + userWorkspaces.length == 0 && + router.asPath != "/noprojects" && + !router.asPath.includes("settings") ) { - router.push("/dashboard/" + userWorkspaces[0]._id + "?Development"); - } else { - setWorkspaceList(userWorkspaces.map((workspace) => workspace.name)); - setWorkspaceMapping( - Object.fromEntries( - userWorkspaces.map((workspace) => [workspace.name, workspace._id]) - ) - ); - setWorkspaceSelected( - Object.fromEntries( - userWorkspaces.map((workspace) => [workspace._id, workspace.name]) - )[ - router.asPath - .split("/")[router.asPath.split("/").length - 1].split("?")[0]] - ); + router.push("/noprojects"); + } else if (router.asPath != "/noprojects") { + const intendedWorkspaceId = router.asPath + .split("/") + [router.asPath.split("/").length - 1].split("?")[0]; + // If a user is not a member of a workspace they are trying to access, just push them to one of theirs + if ( + intendedWorkspaceId != "heroku" && + !userWorkspaces + .map((workspace: { _id: string }) => workspace._id) + .includes(intendedWorkspaceId) + ) { + router.push("/dashboard/" + userWorkspaces[0]._id + "?Development"); + } else { + setWorkspaceList( + userWorkspaces.map((workspace: any) => workspace.name) + ); + setWorkspaceMapping( + Object.fromEntries( + userWorkspaces.map((workspace: any) => [ + workspace.name, + workspace._id, + ]) + ) as any + ); + setWorkspaceSelected( + Object.fromEntries( + userWorkspaces.map((workspace: any) => [ + workspace._id, + workspace.name, + ]) + )[ + router.asPath + .split("/") + [router.asPath.split("/").length - 1].split("?")[0] + ] + ); + } } - } + }; + putUserInWorkSpace(); }, []); useEffect(() => { try { if ( - workspaceMapping[workspaceSelected] && - workspaceMapping[workspaceSelected] !== + workspaceMapping[Number(workspaceSelected)] && + `${workspaceMapping[Number(workspaceSelected)]}` !== router.asPath - .split("/")[router.asPath.split("/").length - 1].split("?")[0] + .split("/") + [router.asPath.split("/").length - 1].split("?")[0] ) { - router.push("/dashboard/" + workspaceMapping[workspaceSelected] + "?Development"); + router.push( + "/dashboard/" + + workspaceMapping[Number(workspaceSelected)] + + "?Development" + ); localStorage.setItem( "projectData.id", - workspaceMapping[workspaceSelected] + `${workspaceMapping[Number(workspaceSelected)]}` ); } } catch (error) { @@ -212,18 +246,18 @@ export default function Layout({ children }) {