From 45cec2905c541b9fbfda09d4e57baa0dc573ada7 Mon Sep 17 00:00:00 2001 From: vidya khandekar Date: Mon, 20 Jan 2025 15:55:07 +0530 Subject: [PATCH 1/8] Task #233633-Implement Authentication Through Keycloak by Redirecting User to Keycloak Login Page with Google Authentication --- src/components/KeyCloakLogin.tsx | 13 +++++++++++++ src/pages/login.tsx | 2 ++ 2 files changed, 15 insertions(+) create mode 100644 src/components/KeyCloakLogin.tsx diff --git a/src/components/KeyCloakLogin.tsx b/src/components/KeyCloakLogin.tsx new file mode 100644 index 0000000..25354cd --- /dev/null +++ b/src/components/KeyCloakLogin.tsx @@ -0,0 +1,13 @@ +import { Button } from "@mui/material"; +import React from "react"; + +const KeyCloakLogin = () => { + const handleGoogleLogin = () => { + window.location.href = + "https://all-saas-keycloak.tekdinext.com/auth/realms/ALL-SaaS/protocol/openid-connect/auth?client_id=ALL-SaaS&response_type=code"; + }; + + return ; +}; + +export default KeyCloakLogin; diff --git a/src/pages/login.tsx b/src/pages/login.tsx index 8786a7f..3c8a4cb 100644 --- a/src/pages/login.tsx +++ b/src/pages/login.tsx @@ -39,6 +39,7 @@ import PersonIcon from "@mui/icons-material/Person"; import KeyIcon from "@mui/icons-material/VpnKey"; import GoogleSignInButton from "@/components/GoogleSignInButton"; import { GoogleOAuthProvider } from "@react-oauth/google"; +import KeyCloakLogin from "@/components/KeyCloakLogin"; const LoginPage = () => { const { t } = useTranslation(); @@ -436,6 +437,7 @@ const LoginPage = () => { + From 7208dfd8c015a05c0b98cdfc6e46dd64117c6eda Mon Sep 17 00:00:00 2001 From: vidya khandekar Date: Thu, 23 Jan 2025 12:01:51 +0530 Subject: [PATCH 2/8] Task #233633: Implement Authentication Through Keycloak by Redirecting User to Keycloak Login Page with Google Authentication --- package-lock.json | 7 +++ package.json | 1 + src/components/layouts/header/Profile.tsx | 7 ++- src/pages/_app.tsx | 70 +++++++++++++++++------ src/pages/logout.tsx | 9 +-- src/utils/keycloak.ts | 33 +++++++++++ tsconfig.json | 2 +- 7 files changed, 102 insertions(+), 27 deletions(-) create mode 100644 src/utils/keycloak.ts diff --git a/package-lock.json b/package-lock.json index 367dcd5..09baa33 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,6 +30,7 @@ "i18next": "^23.11.5", "jquery": "^3.7.1", "ka-table": "^11.0.2", + "keycloak-js": "^26.1.0", "next": "^14.2.4", "next-i18next": "^15.3.0", "papaparse": "^5.4.1", @@ -12131,6 +12132,12 @@ "react": "^16.8.3 || ^17.0.0-0 || ^18.0.0-0" } }, + "node_modules/keycloak-js": { + "version": "26.1.0", + "resolved": "https://registry.npmjs.org/keycloak-js/-/keycloak-js-26.1.0.tgz", + "integrity": "sha512-3CTelLNADK6sIxGHCQmKlT3ezcIp8O3Iimmg+ybS78RHy+HAUkkoBaW/YuHGdYkfEDMBlrqD3u+CQ4vLsrmyFA==", + "license": "Apache-2.0" + }, "node_modules/keygrip": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz", diff --git a/package.json b/package.json index 593af74..66168d9 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "i18next": "^23.11.5", "jquery": "^3.7.1", "ka-table": "^11.0.2", + "keycloak-js": "^26.1.0", "next": "^14.2.4", "next-i18next": "^15.3.0", "papaparse": "^5.4.1", diff --git a/src/components/layouts/header/Profile.tsx b/src/components/layouts/header/Profile.tsx index 1145c9a..8d8b6a4 100644 --- a/src/components/layouts/header/Profile.tsx +++ b/src/components/layouts/header/Profile.tsx @@ -15,6 +15,7 @@ import MailIcon from "@mui/icons-material/Mail"; import PhoneIcon from "@mui/icons-material/Phone"; import { Box, Button, Divider, Menu, Typography } from "@mui/material"; import { useRouter } from "next/router"; +import { logout } from "@/utils/keycloak"; const Profile = () => { const [anchorEl4, setAnchorEl4] = React.useState(null); const [profileClick, setProfileClick] = React.useState(false); @@ -45,11 +46,11 @@ const Profile = () => { setAnchorEl4(null); }; - const handleLogout = () => { + const handleLogout = async () => { if (typeof window !== "undefined" && window.localStorage) { - localStorage.removeItem("token"); + // localStorage.removeItem("token"); + await logout(router); } - router.push("/logout"); }; const mapFields = (formFields: any, response: any) => { diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 4452535..73ead1f 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -1,5 +1,4 @@ // import "@/styles/globals.css"; - import "@/styles/globals.css"; import type { AppProps } from "next/app"; import { appWithTranslation } from "next-i18next"; @@ -13,23 +12,64 @@ import FullLayout from "@/components/layouts/FullLayout"; import { Experimental_CssVarsProvider as CssVarsProvider } from "@mui/material/styles"; import customTheme from "../styles/customTheme"; import "./../styles/style.css"; - - -import { QueryClientProvider, QueryClient } from "@tanstack/react-query" -import { ReactQueryDevtools } from "@tanstack/react-query-devtools" +import keycloak from "../utils/keycloak"; +import { QueryClientProvider, QueryClient } from "@tanstack/react-query"; +import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; import "react-circular-progressbar/dist/styles.css"; +import { log } from "console"; +import { useRouter } from "next/router"; function App({ Component, pageProps }: AppProps) { + const [isLogin, setLogin] = useState(false); + const [userInfo, setUserInfo] = useState(null); + const [accessToken, setAccessToken] = useState(null); + const router = useRouter(); + + // Analytics initialization useEffect(() => { telemetryFactory.init(); }, []); + useEffect(() => { if (!window.GA_INITIALIZED) { initGA(`G-6NVMB20J4Z`); window.GA_INITIALIZED = true; } - }); + }, []); + + // Keycloak initialization + useEffect(() => { + const initializeKeycloak = async () => { + try { + if (!keycloak.authenticated) { + const authenticated = await keycloak.init({ + onLoad: "login-required", + }); + + setLogin(authenticated); + + if (authenticated) { + setAccessToken(keycloak.token); + localStorage.setItem("token", keycloak.token); + localStorage.setItem("refreshToken", keycloak.refreshToken); + + try { + const profile = await keycloak.loadUserProfile(); + setUserInfo(profile); + // router.push("/tenant"); + } catch (err) { + console.error("Failed to load user profile:", err); + } + } + } + } catch (error) { + console.error("Failed to initialize Keycloak:", error); + } + }; + + initializeKeycloak(); + }, []); const renderComponent = () => { if (pageProps.noLayout) { @@ -43,25 +83,22 @@ function App({ Component, pageProps }: AppProps) { } }; - const [client] = useState(new QueryClient( - { + const [client] = useState( + new QueryClient({ defaultOptions: { queries: { - gcTime: 1000 * 60 * 60 * 24, // 24 hours - staleTime: 1000 * 60 * 60 * 24, // 24 hours + gcTime: 1000 * 60 * 60 * 24, + staleTime: 1000 * 60 * 60 * 24, }, }, - } - )); + }) + ); return ( - - + - {renderComponent()} - - ); } diff --git a/src/pages/logout.tsx b/src/pages/logout.tsx index ca6cd4b..1788929 100644 --- a/src/pages/logout.tsx +++ b/src/pages/logout.tsx @@ -1,20 +1,17 @@ import { useEffect } from "react"; import { useRouter } from "next/router"; -import { logout } from "../services/LoginService"; + import { serverSideTranslations } from "next-i18next/serverSideTranslations"; import Loader from "@/components/Loader"; import { useTranslation } from "react-i18next"; - +import { logout } from "@/utils/keycloak"; function Logout() { const router = useRouter(); const { t } = useTranslation(); useEffect(() => { const userLogout = async () => { try { - const refreshToken = localStorage.getItem("refreshToken"); - if (refreshToken) { - await logout(refreshToken); - } + // await logout(router); } catch (error) { console.log(error); } diff --git a/src/utils/keycloak.ts b/src/utils/keycloak.ts new file mode 100644 index 0000000..9f2c44d --- /dev/null +++ b/src/utils/keycloak.ts @@ -0,0 +1,33 @@ +import Keycloak from "keycloak-js"; + + +export const logout = async (router) => { + + try { + if (keycloakInstance) { + console.log("calling logout"); + + await keycloakInstance.logout({redirectUri: window.location.origin + '/login' }); + + + // Clear local storage + localStorage.removeItem("token"); + localStorage.removeItem("userProfile"); + router.replace("/login"); + } + } catch (error) { + console.error("Logout failed:", error); + } +}; + +const keycloakConfig = { + url: "https://all-saas-keycloak.tekdinext.com/auth", + realm: "ALL-SaaS", + clientId: "ALL-SaaS", +}; + +// Initialize Keycloak instance +const keycloakInstance = + typeof window !== "undefined" ? new Keycloak(keycloakConfig) : null; + +export default keycloakInstance; diff --git a/tsconfig.json b/tsconfig.json index 8c84553..dedc84e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -28,6 +28,6 @@ "src/components/Link.tsx", "src/components/theme/theme.ts", "src/components/theme/theme.ts" -, "src/pages/tenant.jsx" ], +, "src/pages/tenant.jsx", "src/utils/keycloak.ts", "src/context/AuthContextt.js" ], "exclude": ["node_modules"] } From bed6413354416f0253a94e3961ee17c51742562e Mon Sep 17 00:00:00 2001 From: vidya khandekar Date: Thu, 23 Jan 2025 12:02:00 +0530 Subject: [PATCH 3/8] Task #233633: Implement Authentication Through Keycloak by Redirecting User to Keycloak Login Page with Google Authentication --- tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index dedc84e..5fd2ed9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -28,6 +28,6 @@ "src/components/Link.tsx", "src/components/theme/theme.ts", "src/components/theme/theme.ts" -, "src/pages/tenant.jsx", "src/utils/keycloak.ts", "src/context/AuthContextt.js" ], +, "src/pages/tenant.jsx", "src/utils/keycloak.ts", "src/context/AuthContext.js" ], "exclude": ["node_modules"] } From 321abcad3cf95d5ae2ac0479fe2ab12eb16cdde0 Mon Sep 17 00:00:00 2001 From: vidya khandekar Date: Thu, 23 Jan 2025 12:40:46 +0530 Subject: [PATCH 4/8] Remove changes --- src/components/KeyCloakLogin.tsx | 13 ------------- src/pages/login.tsx | 2 -- 2 files changed, 15 deletions(-) delete mode 100644 src/components/KeyCloakLogin.tsx diff --git a/src/components/KeyCloakLogin.tsx b/src/components/KeyCloakLogin.tsx deleted file mode 100644 index 25354cd..0000000 --- a/src/components/KeyCloakLogin.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { Button } from "@mui/material"; -import React from "react"; - -const KeyCloakLogin = () => { - const handleGoogleLogin = () => { - window.location.href = - "https://all-saas-keycloak.tekdinext.com/auth/realms/ALL-SaaS/protocol/openid-connect/auth?client_id=ALL-SaaS&response_type=code"; - }; - - return ; -}; - -export default KeyCloakLogin; diff --git a/src/pages/login.tsx b/src/pages/login.tsx index 3c8a4cb..8786a7f 100644 --- a/src/pages/login.tsx +++ b/src/pages/login.tsx @@ -39,7 +39,6 @@ import PersonIcon from "@mui/icons-material/Person"; import KeyIcon from "@mui/icons-material/VpnKey"; import GoogleSignInButton from "@/components/GoogleSignInButton"; import { GoogleOAuthProvider } from "@react-oauth/google"; -import KeyCloakLogin from "@/components/KeyCloakLogin"; const LoginPage = () => { const { t } = useTranslation(); @@ -437,7 +436,6 @@ const LoginPage = () => { - From 22d028bd996898df6410cb4ffc40925608b60e8e Mon Sep 17 00:00:00 2001 From: vidya khandekar Date: Thu, 23 Jan 2025 14:27:26 +0530 Subject: [PATCH 5/8] Keycloak logout functionality --- src/utils/keycloak.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/utils/keycloak.ts b/src/utils/keycloak.ts index 9f2c44d..325b3ae 100644 --- a/src/utils/keycloak.ts +++ b/src/utils/keycloak.ts @@ -1,15 +1,11 @@ import Keycloak from "keycloak-js"; - -export const logout = async (router) => { - +export const logout = async (router: any) => { try { if (keycloakInstance) { console.log("calling logout"); - - await keycloakInstance.logout({redirectUri: window.location.origin + '/login' }); - + await keycloakInstance.logout(); // Clear local storage localStorage.removeItem("token"); localStorage.removeItem("userProfile"); From d19410989d6ff1647f2ddd3a1f72af1a40316b4a Mon Sep 17 00:00:00 2001 From: vidya khandekar Date: Thu, 23 Jan 2025 14:52:59 +0530 Subject: [PATCH 6/8] Added env variables --- src/utils/keycloak.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/utils/keycloak.ts b/src/utils/keycloak.ts index 325b3ae..434a19e 100644 --- a/src/utils/keycloak.ts +++ b/src/utils/keycloak.ts @@ -17,9 +17,9 @@ export const logout = async (router: any) => { }; const keycloakConfig = { - url: "https://all-saas-keycloak.tekdinext.com/auth", - realm: "ALL-SaaS", - clientId: "ALL-SaaS", + url: process.env.NEXT_PUBLIC_KEYCLOAK_URL, + realm: process.env.NEXT_PUBLIC_KEYCLOAK_REALM, + clientId: process.env.NEXT_PUBLIC_KEYCLOAK_CLIENT_ID, }; // Initialize Keycloak instance From 0ecb741fc03ab167f28eba30d15b82a31a0b16c1 Mon Sep 17 00:00:00 2001 From: vidya khandekar Date: Fri, 24 Jan 2025 14:31:53 +0530 Subject: [PATCH 7/8] Logout issue resolved --- src/components/layouts/header/Profile.tsx | 3 +- src/pages/_app.tsx | 28 +-- src/pages/login.tsx | 229 +--------------------- src/pages/logout.tsx | 3 +- src/utils/keycloak.ts | 20 +- 5 files changed, 24 insertions(+), 259 deletions(-) diff --git a/src/components/layouts/header/Profile.tsx b/src/components/layouts/header/Profile.tsx index 8d8b6a4..75221e2 100644 --- a/src/components/layouts/header/Profile.tsx +++ b/src/components/layouts/header/Profile.tsx @@ -48,8 +48,7 @@ const Profile = () => { const handleLogout = async () => { if (typeof window !== "undefined" && window.localStorage) { - // localStorage.removeItem("token"); - await logout(router); + router.replace("/logout"); } }; diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 73ead1f..aef0967 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -15,17 +15,9 @@ import "./../styles/style.css"; import keycloak from "../utils/keycloak"; import { QueryClientProvider, QueryClient } from "@tanstack/react-query"; import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; - import "react-circular-progressbar/dist/styles.css"; -import { log } from "console"; -import { useRouter } from "next/router"; function App({ Component, pageProps }: AppProps) { - const [isLogin, setLogin] = useState(false); - const [userInfo, setUserInfo] = useState(null); - const [accessToken, setAccessToken] = useState(null); - const router = useRouter(); - // Analytics initialization useEffect(() => { telemetryFactory.init(); @@ -42,24 +34,18 @@ function App({ Component, pageProps }: AppProps) { useEffect(() => { const initializeKeycloak = async () => { try { - if (!keycloak.authenticated) { + if (keycloak != null && !keycloak.authenticated) { const authenticated = await keycloak.init({ onLoad: "login-required", + redirectUri: window.location.origin + "/tenant", }); - setLogin(authenticated); - if (authenticated) { - setAccessToken(keycloak.token); - localStorage.setItem("token", keycloak.token); - localStorage.setItem("refreshToken", keycloak.refreshToken); - - try { - const profile = await keycloak.loadUserProfile(); - setUserInfo(profile); - // router.push("/tenant"); - } catch (err) { - console.error("Failed to load user profile:", err); + if (keycloak.token) { + localStorage.setItem("token", keycloak.token); + } + if (keycloak.refreshToken) { + localStorage.setItem("refreshToken", keycloak.refreshToken); } } } diff --git a/src/pages/login.tsx b/src/pages/login.tsx index 8786a7f..744cb20 100644 --- a/src/pages/login.tsx +++ b/src/pages/login.tsx @@ -1,24 +1,11 @@ import { Box, - Button, - FormControl, - IconButton, - InputAdornment, - TextField, - Grid, - Typography, useMediaQuery, // Import useMediaQuery hook } from "@mui/material"; import React, { useEffect, useRef, useState } from "react"; -import Select, { SelectChangeEvent } from "@mui/material/Select"; -import { Visibility, VisibilityOff } from "@mui/icons-material"; +import { SelectChangeEvent } from "@mui/material/Select"; import ReactGA from "react-ga4"; -import Checkbox from "@mui/material/Checkbox"; -import Image from "next/image"; import Loader from "../components/Loader"; -import MenuItem from "@mui/material/MenuItem"; -import appLogo from "../../public/logo.png"; -import config from "../../config.json"; import { getUserId, login } from "../services/LoginService"; import { serverSideTranslations } from "next-i18next/serverSideTranslations"; import { useRouter } from "next/router"; @@ -27,18 +14,11 @@ import { useTranslation } from "next-i18next"; import { telemetryFactory } from "@/utils/telemetry"; import { logEvent } from "@/utils/googleAnalytics"; import { showToastMessage } from "@/components/Toastify"; -import Link from "@mui/material/Link"; -// import loginImage from "../../public/loginImage.jpg"; -import loginImage from "../../public/all-saas-login.png"; import { useUserIdStore } from "@/store/useUserIdStore"; import { getUserDetailsInfo } from "@/services/UserList"; import { Storage } from "@/utils/app.constant"; import useSubmittedButtonStore from "@/utils/useSharedState"; import { Role } from "@/utils/app.constant"; -import PersonIcon from "@mui/icons-material/Person"; -import KeyIcon from "@mui/icons-material/VpnKey"; -import GoogleSignInButton from "@/components/GoogleSignInButton"; -import { GoogleOAuthProvider } from "@react-oauth/google"; const LoginPage = () => { const { t } = useTranslation(); @@ -237,210 +217,11 @@ const LoginPage = () => { label: "Forgot Password Link Clicked", }); }; - const GOOGLE_CLIENT_ID = process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID || ""; - return ( - - - {!(isMobile || isMedium) && ( // Render only on desktop view - - )} - - -
- - {loading && ( - - )} - App Logo - - {/* - {t("LOGIN_PAGE.LOGIN")} - */} - {/* - - */} - - - - ), - }} - sx={{ - "& .MuiOutlinedInput-root": { - borderRadius: "20px", // Adjust the value as needed for more or less rounding - }, - }} - /> - {/* */} - - - - - ), - endAdornment: ( - - - {showPassword ? : } - - - ), - }} - // label={t("LOGIN_PAGE.PASSWORD")} - placeholder={t("LOGIN_PAGE.PASSWORD_PLACEHOLDER")} - value={password} - onChange={handlePasswordChange} - error={passwordError} - margin="normal" - inputRef={passwordRef} - sx={{ - "& .MuiOutlinedInput-root": { - borderRadius: "20px", // Adjust the value as needed for more or less rounding - }, - }} - /> - {/* - setRememberMe(e.target.checked)} - checked={rememberMe} - /> - { - setRememberMe(!rememberMe); - logEvent({ - action: "remember-me-button-clicked", - category: "Login Page", - label: `Remember Me ${ - rememberMe ? "Checked" : "Unchecked" - }`, - }); - }} - sx={{ - cursor: "pointer", - marginTop: "15px", - color: theme.palette.warning[300], - }} - > - {t("LOGIN_PAGE.REMEMBER_ME")} - - */} - - - - - - - -
-
-
-
+ return ( + + {true && } + ); }; diff --git a/src/pages/logout.tsx b/src/pages/logout.tsx index 1788929..f124953 100644 --- a/src/pages/logout.tsx +++ b/src/pages/logout.tsx @@ -11,7 +11,7 @@ function Logout() { useEffect(() => { const userLogout = async () => { try { - // await logout(router); + await logout(); } catch (error) { console.log(error); } @@ -43,7 +43,6 @@ function Logout() { } }); } - router.replace("/login"); }, []); return ; diff --git a/src/utils/keycloak.ts b/src/utils/keycloak.ts index 434a19e..bb70d4b 100644 --- a/src/utils/keycloak.ts +++ b/src/utils/keycloak.ts @@ -1,15 +1,14 @@ import Keycloak from "keycloak-js"; -export const logout = async (router: any) => { +export const logout = async () => { try { if (keycloakInstance) { - console.log("calling logout"); + await keycloakInstance.logout({ + redirectUri: window.location.origin + "/login", + }); + console.log(keycloakInstance); - await keycloakInstance.logout(); - // Clear local storage - localStorage.removeItem("token"); - localStorage.removeItem("userProfile"); - router.replace("/login"); + localStorage.clear(); } } catch (error) { console.error("Logout failed:", error); @@ -17,12 +16,13 @@ export const logout = async (router: any) => { }; const keycloakConfig = { - url: process.env.NEXT_PUBLIC_KEYCLOAK_URL, - realm: process.env.NEXT_PUBLIC_KEYCLOAK_REALM, - clientId: process.env.NEXT_PUBLIC_KEYCLOAK_CLIENT_ID, + url: process.env.NEXT_PUBLIC_KEYCLOAK_URL || " ", + realm: process.env.NEXT_PUBLIC_KEYCLOAK_REALM || " ", + clientId: process.env.NEXT_PUBLIC_KEYCLOAK_CLIENT_ID || "", }; // Initialize Keycloak instance + const keycloakInstance = typeof window !== "undefined" ? new Keycloak(keycloakConfig) : null; From 479c511006017a099841e153feea1e956f9ea2a5 Mon Sep 17 00:00:00 2001 From: vidya khandekar Date: Fri, 24 Jan 2025 14:39:24 +0530 Subject: [PATCH 8/8] Fix-Sonar issue --- src/components/layouts/header/Profile.tsx | 2 +- src/pages/login.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/layouts/header/Profile.tsx b/src/components/layouts/header/Profile.tsx index 75221e2..8b59ec0 100644 --- a/src/components/layouts/header/Profile.tsx +++ b/src/components/layouts/header/Profile.tsx @@ -15,7 +15,7 @@ import MailIcon from "@mui/icons-material/Mail"; import PhoneIcon from "@mui/icons-material/Phone"; import { Box, Button, Divider, Menu, Typography } from "@mui/material"; import { useRouter } from "next/router"; -import { logout } from "@/utils/keycloak"; + const Profile = () => { const [anchorEl4, setAnchorEl4] = React.useState(null); const [profileClick, setProfileClick] = React.useState(false); diff --git a/src/pages/login.tsx b/src/pages/login.tsx index 744cb20..f5ce876 100644 --- a/src/pages/login.tsx +++ b/src/pages/login.tsx @@ -220,7 +220,7 @@ const LoginPage = () => { return ( - {true && } + ); };