From 61f4848f20f571908657babeb08b3102e6486000 Mon Sep 17 00:00:00 2001 From: Stavros Date: Thu, 6 Mar 2025 17:30:35 +0200 Subject: [PATCH] refactor: split login screen and forms --- site/src/components/auth/login-forn.tsx | 46 +++++++ site/src/components/auth/oauth-buttons.tsx | 72 +++++++++++ site/src/pages/login-page.tsx | 142 +++------------------ site/src/schemas/login-schema.ts | 8 ++ 4 files changed, 144 insertions(+), 124 deletions(-) create mode 100644 site/src/components/auth/login-forn.tsx create mode 100644 site/src/components/auth/oauth-buttons.tsx create mode 100644 site/src/schemas/login-schema.ts diff --git a/site/src/components/auth/login-forn.tsx b/site/src/components/auth/login-forn.tsx new file mode 100644 index 0000000..8b76e2d --- /dev/null +++ b/site/src/components/auth/login-forn.tsx @@ -0,0 +1,46 @@ +import { TextInput, PasswordInput, Button } from "@mantine/core"; +import { useForm, zodResolver } from "@mantine/form"; +import { LoginFormValues, loginSchema } from "../../schemas/login-schema"; + +interface LoginFormProps { + isLoading: boolean; + onSubmit: (values: LoginFormValues) => void; +} + +export const LoginForm = (props: LoginFormProps) => { + const { isLoading, onSubmit } = props; + + const form = useForm({ + mode: "uncontrolled", + initialValues: { + username: "", + password: "", + }, + validate: zodResolver(loginSchema), + }); + + return ( +
+ + + + + ); +}; diff --git a/site/src/components/auth/oauth-buttons.tsx b/site/src/components/auth/oauth-buttons.tsx new file mode 100644 index 0000000..eb8b239 --- /dev/null +++ b/site/src/components/auth/oauth-buttons.tsx @@ -0,0 +1,72 @@ +import { Grid, Button } from "@mantine/core"; +import { GithubIcon } from "../../icons/github"; +import { GoogleIcon } from "../../icons/google"; +import { OAuthIcon } from "../../icons/oauth"; +import { TailscaleIcon } from "../../icons/tailscale"; + +interface OAuthButtonsProps { + oauthProviders: string[]; + isLoading: boolean; + mutate: (provider: string) => void; + genericName: string; +} + +export const OAuthButtons = (props: OAuthButtonsProps) => { + const { oauthProviders, isLoading, genericName, mutate } = props; + return ( + + {oauthProviders.includes("google") && ( + + + + )} + {oauthProviders.includes("github") && ( + + + + )} + {oauthProviders.includes("tailscale") && ( + + + + )} + {oauthProviders.includes("generic") && ( + + + + )} + + ); +}; diff --git a/site/src/pages/login-page.tsx b/site/src/pages/login-page.tsx index b11210d..948c735 100644 --- a/site/src/pages/login-page.tsx +++ b/site/src/pages/login-page.tsx @@ -1,33 +1,22 @@ -import { - Button, - Paper, - PasswordInput, - TextInput, - Title, - Text, - Divider, - Grid, -} from "@mantine/core"; -import { useForm, zodResolver } from "@mantine/form"; +import { Paper, Title, Text, Divider } from "@mantine/core"; import { notifications } from "@mantine/notifications"; import { useMutation } from "@tanstack/react-query"; import axios from "axios"; -import { z } from "zod"; import { useUserContext } from "../context/user-context"; import { Navigate } from "react-router"; import { Layout } from "../components/layouts/layout"; -import { GoogleIcon } from "../icons/google"; -import { GithubIcon } from "../icons/github"; -import { OAuthIcon } from "../icons/oauth"; -import { TailscaleIcon } from "../icons/tailscale"; import { isQueryValid } from "../utils/utils"; +import { OAuthButtons } from "../components/auth/oauth-buttons"; +import { LoginFormValues } from "../schemas/login-schema"; +import { LoginForm } from "../components/auth/login-forn"; export const LoginPage = () => { const queryString = window.location.search; const params = new URLSearchParams(queryString); const redirectUri = params.get("redirect_uri") ?? ""; - const { isLoggedIn, configuredProviders, title, genericName } = useUserContext(); + const { isLoggedIn, configuredProviders, title, genericName } = + useUserContext(); const oauthProviders = configuredProviders.filter( (value) => value !== "username", @@ -37,24 +26,8 @@ export const LoginPage = () => { return ; } - const schema = z.object({ - username: z.string(), - password: z.string(), - }); - - type FormValues = z.infer; - - const form = useForm({ - mode: "uncontrolled", - initialValues: { - username: "", - password: "", - }, - validate: zodResolver(schema), - }); - const loginMutation = useMutation({ - mutationFn: (login: FormValues) => { + mutationFn: (login: LoginFormValues) => { return axios.post("/api/login", login); }, onError: () => { @@ -105,7 +78,7 @@ export const LoginPage = () => { }, }); - const handleSubmit = (values: FormValues) => { + const handleSubmit = (values: LoginFormValues) => { loginMutation.mutate(values); }; @@ -118,68 +91,12 @@ export const LoginPage = () => { Welcome back, login with - - {oauthProviders.includes("google") && ( - - - - )} - {oauthProviders.includes("github") && ( - - - - )} - {oauthProviders.includes("tailscale") && ( - - - - )} - {oauthProviders.includes("generic") && ( - - - - )} - + {configuredProviders.includes("username") && ( { )} {configuredProviders.includes("username") && ( -
- - - - + )} diff --git a/site/src/schemas/login-schema.ts b/site/src/schemas/login-schema.ts new file mode 100644 index 0000000..c08f70f --- /dev/null +++ b/site/src/schemas/login-schema.ts @@ -0,0 +1,8 @@ +import { z } from "zod"; + +export const loginSchema = z.object({ + username: z.string(), + password: z.string(), +}); + +export type LoginFormValues = z.infer; \ No newline at end of file