prepared for login

This commit is contained in:
z1glr
2025-01-08 00:42:06 +00:00
parent f0ad6a3b64
commit be8705286e
9 changed files with 133 additions and 61 deletions

View File

@@ -8,8 +8,7 @@ import (
) )
type UserLogin struct { type UserLogin struct {
UserID int `json:"userID"` UserName string `json:"userName"`
Name string `json:"name"`
LoggedIn bool `json:"loggedIn"` LoggedIn bool `json:"loggedIn"`
} }
@@ -48,8 +47,7 @@ func handleWelcome(c *fiber.Ctx) error {
user := users[0] user := users[0]
response.Data = UserLogin{ response.Data = UserLogin{
UserID: user.UserID, UserName: user.UserName,
Name: user.Name,
LoggedIn: true, LoggedIn: true,
} }
} }

View File

@@ -164,8 +164,7 @@ func extractJWT(c *fiber.Ctx) (int, string, error) {
// user-entry in the database // user-entry in the database
type UserDB struct { type UserDB struct {
UserID int `json:"userID"` UserName string `json:"userName"`
Name string `json:"name"`
Password []byte `json:"password"` Password []byte `json:"password"`
Admin bool `json:"admin"` Admin bool `json:"admin"`
TokenID string `json:"tokenID"` TokenID string `json:"tokenID"`
@@ -216,6 +215,6 @@ func checkAdmin(c *fiber.Ctx) (bool, error) {
if len(response) != 1 { if len(response) != 1 {
return false, fmt.Errorf("user doesn't exist") return false, fmt.Errorf("user doesn't exist")
} else { } else {
return response[0].Name == "admin" && response[0].TokenID == tokenID, err return response[0].UserName == "admin" && response[0].TokenID == tokenID, err
} }
} }

View File

@@ -21,6 +21,7 @@
"@nextui-org/modal": "^2.2.7", "@nextui-org/modal": "^2.2.7",
"@nextui-org/radio": "^2.3.8", "@nextui-org/radio": "^2.3.8",
"@nextui-org/select": "^2.4.9", "@nextui-org/select": "^2.4.9",
"@nextui-org/spinner": "^2.2.6",
"@nextui-org/switch": "^2.2.8", "@nextui-org/switch": "^2.2.8",
"@nextui-org/system": "^2.4.6", "@nextui-org/system": "^2.4.6",
"@nextui-org/table": "^2.2.8", "@nextui-org/table": "^2.2.8",

View File

@@ -22,6 +22,7 @@
"@nextui-org/modal": "^2.2.7", "@nextui-org/modal": "^2.2.7",
"@nextui-org/radio": "^2.3.8", "@nextui-org/radio": "^2.3.8",
"@nextui-org/select": "^2.4.9", "@nextui-org/select": "^2.4.9",
"@nextui-org/spinner": "^2.2.6",
"@nextui-org/switch": "^2.2.8", "@nextui-org/switch": "^2.2.8",
"@nextui-org/system": "^2.4.6", "@nextui-org/system": "^2.4.6",
"@nextui-org/table": "^2.2.8", "@nextui-org/table": "^2.2.8",

11
client/src/app/Header.tsx Normal file
View File

@@ -0,0 +1,11 @@
import { Link } from "@nextui-org/link";
export default function Header() {
return (
<div className="flex justify-center">
<Link href="/" className="text-center text-8xl">
<h1 className="font-display-headline">Volunteer Scheduler</h1>
</Link>
</div>
);
}

55
client/src/app/Main.tsx Normal file
View File

@@ -0,0 +1,55 @@
"use client";
import { apiCall } from "@/lib";
import { Spinner } from "@nextui-org/spinner";
import { usePathname, useRouter } from "next/navigation";
import React, { useEffect, useState } from "react";
enum AuthState {
Loading,
LoginScreen,
Unauthorized,
LoggedIn,
}
export default function Main({ children }: { children: React.ReactNode }) {
const [status, setStatus] = useState(AuthState.Loading);
const router = useRouter();
const pathname = usePathname();
useEffect(() => {
void (async () => {
if (pathname === "/login") {
setStatus(AuthState.LoginScreen);
} else {
const welcomeResult = await apiCall<{
userName: string;
loggedIn: boolean;
}>("GET", "welcome");
if (!welcomeResult.ok) {
router.push("/login");
} else {
const response = await welcomeResult.json();
if (response.loggedIn) {
setStatus(AuthState.LoggedIn);
} else {
setStatus(AuthState.Unauthorized);
}
}
}
})();
});
switch (status) {
case AuthState.Loading:
return <Spinner label="Loading..." />;
case AuthState.LoggedIn:
case AuthState.LoginScreen:
return children;
case AuthState.Unauthorized:
return "";
}
}

View File

@@ -3,6 +3,8 @@ import "./globals.css";
import { NextUIProvider } from "@nextui-org/system"; import { NextUIProvider } from "@nextui-org/system";
import React from "react"; import React from "react";
import Footer from "./Footer"; import Footer from "./Footer";
import Header from "./Header";
import Main from "./Main";
export const metadata: Metadata = { export const metadata: Metadata = {
title: "Create Next App", title: "Create Next App",
@@ -31,11 +33,11 @@ export default function RootLayout({
<NextUIProvider> <NextUIProvider>
<div className="flex min-h-screen flex-col p-4"> <div className="flex min-h-screen flex-col p-4">
<header> <header>
<h1 className="text-center font-display-headline text-8xl"> <Header />
Volunteer Scheduler
</h1>
</header> </header>
<main className="flex min-h-full flex-1 flex-col">{children}</main> <main className="flex min-h-full flex-1 flex-col">
<Main>{children}</Main>
</main>
<footer className="flex h-4 justify-center gap-4"> <footer className="flex h-4 justify-center gap-4">
<Footer sites={footerSites} /> <Footer sites={footerSites} />
</footer> </footer>

View File

@@ -0,0 +1,53 @@
"use client";
import { ViewFilled, ViewOffFilled } from "@carbon/icons-react";
import { Button } from "@nextui-org/button";
import { Form } from "@nextui-org/form";
import { Input } from "@nextui-org/input";
import { Switch } from "@nextui-org/switch";
import { useState } from "react";
export default function Login() {
const [visibility, setVisibility] = useState(false);
return (
<div>
<h2 className="mb-4 text-center text-4xl">Login</h2>
<Form
validationBehavior="native"
className="flex flex-col items-center gap-2"
onSubmit={(e) => e.preventDefault()}
>
<Input
isRequired
type="user"
label="Name"
name="username"
variant="bordered"
className="max-w-xs"
/>
<Input
isRequired
label="Password"
name="password"
autoComplete="current-password"
endContent={
<Switch
className="my-auto"
startContent={<ViewFilled />}
endContent={<ViewOffFilled />}
onValueChange={setVisibility}
isSelected={visibility}
/>
}
type={visibility ? "text" : "password"}
variant="bordered"
className="max-w-xs"
/>
<Button className="w-full max-w-xs" color="primary" type="submit">
Login
</Button>
</Form>
</div>
);
}

View File

@@ -1,54 +1,6 @@
"use client"; import OverviewPersonal from "./me/page";
import { Input } from "@nextui-org/input";
import { useState } from "react";
import { ViewFilled, ViewOffFilled } from "@carbon/icons-react";
import { Switch } from "@nextui-org/switch";
import { Button } from "@nextui-org/button";
import { Form } from "@nextui-org/form";
export default function Home() { export default function Home() {
const [visibility, setVisibility] = useState(false);
// return <EventVolunteer />; // return <EventVolunteer />;
return ( return <OverviewPersonal />;
<div>
<h2 className="mb-4 text-center text-4xl">Login</h2>
<Form
validationBehavior="native"
className="flex flex-col items-center gap-2"
onSubmit={(e) => e.preventDefault()}
>
<Input
isRequired
type="user"
label="Name"
name="username"
variant="bordered"
className="max-w-xs"
/>
<Input
isRequired
label="Password"
name="password"
autoComplete="current-password"
endContent={
<Switch
className="my-auto"
startContent={<ViewFilled />}
endContent={<ViewOffFilled />}
onValueChange={setVisibility}
isSelected={visibility}
/>
}
type={visibility ? "text" : "password"}
variant="bordered"
className="max-w-xs"
/>
<Button className="w-full max-w-xs" color="primary" type="submit">
Login
</Button>
</Form>
</div>
);
} }