From 143de12d67960f782821dcef6746dc5eae555b1e Mon Sep 17 00:00:00 2001 From: Daniel Hougaard <62331820+DanielHougaard@users.noreply.github.com> Date: Sat, 9 Mar 2024 09:03:01 +0100 Subject: [PATCH] Feat: Select organization on login --- frontend/src/hooks/api/auth/index.tsx | 1 + frontend/src/hooks/api/auth/queries.tsx | 22 +++ .../src/pages/login/select-organization.tsx | 146 ++++++++++++++++++ 3 files changed, 169 insertions(+) create mode 100644 frontend/src/pages/login/select-organization.tsx diff --git a/frontend/src/hooks/api/auth/index.tsx b/frontend/src/hooks/api/auth/index.tsx index 66208a487..8b918c7ab 100644 --- a/frontend/src/hooks/api/auth/index.tsx +++ b/frontend/src/hooks/api/auth/index.tsx @@ -1,6 +1,7 @@ export { useGetAuthToken, useResetPassword, + useSelectOrganization, useSendMfaToken, useSendPasswordResetEmail, useSendVerificationEmail, diff --git a/frontend/src/hooks/api/auth/queries.tsx b/frontend/src/hooks/api/auth/queries.tsx index 41f1b02f5..9bc7bb034 100644 --- a/frontend/src/hooks/api/auth/queries.tsx +++ b/frontend/src/hooks/api/auth/queries.tsx @@ -1,5 +1,6 @@ import { useMutation, useQuery } from "@tanstack/react-query"; +import SecurityClient from "@app/components/utilities/SecurityClient"; import { apiRequest } from "@app/config/request"; import { setAuthToken } from "@app/reactQuery"; @@ -56,6 +57,27 @@ export const useLogin1 = () => { }); }; +export const selectOrganization = async (data: { organizationId: string }) => { + const { data: res } = await apiRequest.post<{ token: string }>( + "/api/v3/auth/select-organization", + data + ); + return res; +}; + +export const useSelectOrganization = () => { + return useMutation({ + mutationFn: async (details: { organizationId: string }) => { + const data = await selectOrganization(details); + + SecurityClient.setToken(data.token); + SecurityClient.setProviderAuthToken(""); + + return data; + } + }); +}; + export const useLogin2 = () => { return useMutation({ mutationFn: async (details: { diff --git a/frontend/src/pages/login/select-organization.tsx b/frontend/src/pages/login/select-organization.tsx new file mode 100644 index 000000000..d60a06fd3 --- /dev/null +++ b/frontend/src/pages/login/select-organization.tsx @@ -0,0 +1,146 @@ +/* eslint-disable jsx-a11y/no-static-element-interactions */ +/* eslint-disable jsx-a11y/click-events-have-key-events */ +import { useCallback, useEffect } from "react"; +import { useTranslation } from "react-i18next"; +import Head from "next/head"; +import Image from "next/image"; +import Link from "next/link"; +import { useRouter } from "next/router"; +import { faArrowRight } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; + +import { Button, Spinner } from "@app/components/v2"; +import { useUser } from "@app/context"; +import { useGetOrganizations, useLogoutUser, useSelectOrganization } from "@app/hooks/api"; +import { isLoggedIn } from "@app/reactQuery"; +import { navigateUserToOrg } from "@app/views/Login/Login.utils"; + +const LoadingScreen = () => { + return ( +
+ +

Loading, please wait

+
+ ); +}; + +export default function LoginPage() { + const router = useRouter(); + const { t } = useTranslation(); + + const organizations = useGetOrganizations(); + const selectOrg = useSelectOrganization(); + const { user, isLoading: userLoading } = useUser(); + + const logout = useLogoutUser(true); + const handleLogout = useCallback(async () => { + try { + console.log("Logging out..."); + await logout.mutateAsync(); + router.push("/login"); + } catch (error) { + console.error(error); + } + }, [logout, router]); + + const handleSelectOrganization = useCallback( + async (orgId: string) => { + console.log("Selected organization: ", orgId); + + const { token } = await selectOrg.mutateAsync({ organizationId: orgId }); + + console.log("Organization selected successfully", { token }); + + navigateUserToOrg(router, orgId); + }, + [selectOrg] + ); + + useEffect(() => { + if (!isLoggedIn()) { + router.push("/login"); + } + }, [router]); + + if (userLoading || !user) { + return ; + } + + return ( +
+ + {t("common.head-title", { title: t("login.title") })} + + + + + +
+ +
+ Infisical logo +
+ +
console.log("submit")} + className="mx-auto flex w-full flex-col items-center justify-center" + > +
+

+ Choose your organization +

+ +
+

+ You‘re currently logged in as {user.email} +

+

+ Not you?{" "} + +

+
+
+
+ {organizations.isLoading ? ( + + ) : ( + organizations.data + ?.concat(organizations.data) + .concat(organizations.data) + .map((org) => ( +
handleSelectOrganization(org.id)} + key={org.id} + className="group flex cursor-pointer items-center justify-between rounded-md bg-mineshaft-700 px-4 py-3 capitalize text-gray-200 shadow-md transition-colors hover:bg-mineshaft-600" + > +

{org.name}

+ + +
+ )) + )} +
+ + +
+
+ +
+
+ ); +}