Skip to content

Commit

Permalink
login: authorization on frontend login + all routes
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelharlow committed Oct 25, 2024
1 parent e6681c9 commit 76cf1a9
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 17 deletions.
53 changes: 53 additions & 0 deletions src/main/frontend/src/components/Auth.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import {createContext, useContext, useState} from "react";
import {Navigate, Outlet} from "react-router-dom";


interface AuthContextType {
user: Login | undefined;
signIn: (data: any) => void;
signOut: () => void;
}

const AuthContext = createContext<AuthContextType | undefined>(undefined);

function AuthProvider({ children}: Props) {
const [user, setUser] = useState<any | undefined>(() => {
const user = sessionStorage.getItem("user");
return user ? JSON.parse(user) : undefined;
});

const signIn = (data: any) => {
setUser(data);
sessionStorage.setItem("user", JSON.stringify(data));
};

const signOut = () => {
setUser(undefined);
sessionStorage.removeItem("user");
};

return (
<AuthContext.Provider value={{user, signIn, signOut}}>
{children}
</AuthContext.Provider>
);
}

const useAuth = () => {
const context = useContext(AuthContext);
if (context === undefined) {
throw new Error("useAuth must be used within an AuthProvider");
}
return context;
}

function ProtectedRoute() {
const {user} = useAuth();
console.log(`User2: ${user}`);
if (user === undefined) {
return <Navigate to={"/login"} replace />;
}
return <Outlet />;
}

export { AuthProvider, useAuth, ProtectedRoute };
13 changes: 10 additions & 3 deletions src/main/frontend/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,28 @@ import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import App from './App.tsx'
import './index.css'
import {createBrowserRouter, createRoutesFromElements, Route, RouterProvider} from "react-router-dom";
import {createBrowserRouter, createRoutesFromElements, Navigate, Route, RouterProvider} from "react-router-dom";
import Layout from "@/components/Layout.tsx";
import Login from "@/routes/Login.tsx";
import {AuthProvider, ProtectedRoute} from "@/components/Auth.tsx";

const router = createBrowserRouter(
createRoutesFromElements(
<Route path={"/"} element={<Layout />}>
<Route index element={<App />} /> {/* element={<Navigate to={"login"} replace />} */}
<Route index element={<Navigate to={"login"} replace />} />
<Route path={"login"} element={<Login />} />
<Route path={"register"} element={<h1>HELLO OTHER ROUTE</h1>} />
<Route path={"/"} element={<ProtectedRoute />}>
<Route path={"app-demo"} element={<App />} />
</Route>
</Route>
)
)

createRoot(document.getElementById('root')!).render(
<StrictMode>
<RouterProvider router={router} />
<AuthProvider>
<RouterProvider router={router} />
</AuthProvider>
</StrictMode>,
)
104 changes: 90 additions & 14 deletions src/main/frontend/src/routes/Login.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,103 @@
import {Label} from "@/components/ui/label.tsx";
import {Input} from "@/components/ui/input.tsx";
import {Button} from "@/components/ui/button.tsx";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form"
import {zodResolver} from "@hookform/resolvers/zod";
import {useForm} from "react-hook-form";
import {z} from "zod"
import {useAuth} from "@/components/Auth.tsx";
import {useNavigate} from "react-router-dom";

const formSchema = z.object({
email: z.string().email({
message: "Invalid email address",
}),
password: z.string({
message: "Invalid password",
}),
})

function Login() {
const { signIn } = useAuth();
const navigate = useNavigate();

const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
email: "",
password: "",
},
})

const onSubmit = (data: z.infer<typeof formSchema>) => {
fetch("http://localhost:8080/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
}).then((response) => {
if (!response.ok) {
throw new Error("Password is incorrect")
}
}).then(() => {
console.log(data);
signIn(data);
navigate("/app-demo");
}).catch((error) => {
form.setError(
"password",
{
type: "value",
message: error.message,
}
)
})
}

return (
<div className={"flex rounded-3xl floating-shadow w-[900px] h-[600px] mb-16 overflow-hidden"}>
<div className={"bg-white w-1/2 px-6 py-12"}>
<h1>Welcome Back!</h1>
<h2 className={"font-light"}>Login to access loans and more.</h2>
<div className={"mt-8"}>
<Label>Email</Label>
<Input type={"email"} className={"mt-1"}/>
</div>
<div className={"mt-6"}>
<Label>Password</Label>
<Input type={"password"} className={"mt-1"}/>
</div>
<div className={"flex justify-between"}>
<Button variant={"link"} className={"mt-4 px-0 text-commerce-green font-semibold"}>Admin</Button>
<Button variant={"link"} className={"mt-4 px-0 text-commerce-green font-semibold"}>Forgot Password?</Button>
</div>
<Button className={"mt-8 w-full"}>Login</Button>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)}>
<FormField
control={form.control}
name="email"
render={({field}) => (
<FormItem className={"mt-8"}>
<FormLabel className={"text-black"}>Email</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage/>
</FormItem>
)}
/>
<FormField
control={form.control}
name="password"
render={({field}) => (
<FormItem className={"mt-6"}>
<FormLabel className={"text-black"}>Password</FormLabel>
<FormControl>
<Input type="password" {...field} />
</FormControl>
<FormMessage/>
</FormItem>
)}
/>
<Button type={"button"} variant={"link"} className={"px-0 text-commerce-green font-semibold"}>Forgot Password?</Button>
<Button type={"submit"} className={"mt-4 py-6 w-full"}>Login</Button>
</form>
</Form>
</div>
<div className={"bg-commerce-green w-1/2"}>
<img className={"m-auto mt-64"} src={"/commerce_globe_45x48.png"} alt={"Logo"}/>
Expand Down
9 changes: 9 additions & 0 deletions src/main/frontend/src/vite-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
/// <reference types="vite/client" />

interface Props {
children?: React.ReactNode;
}

interface Account {
id: number;
userType: number;
username: string;
password: string;
email: string;
phoneNumber: string;
}

interface Login {
email: string;
password: string;
}

0 comments on commit 76cf1a9

Please sign in to comment.