mirror of
https://github.com/Ategon/Jamjar.git
synced 2025-02-12 06:16:21 +00:00
Add login functionality
This commit is contained in:
parent
e61dd263c5
commit
51d92b2fc4
5 changed files with 222 additions and 10 deletions
83
src/app/login/page.tsx
Normal file
83
src/app/login/page.tsx
Normal file
|
@ -0,0 +1,83 @@
|
|||
"use client";
|
||||
|
||||
import { Button, Form, Input } from "@nextui-org/react";
|
||||
import { redirect } from "next/navigation";
|
||||
import { useState } from "react";
|
||||
|
||||
export default function UserPage() {
|
||||
const [username, setUsername] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [error, setError] = useState("");
|
||||
|
||||
return (
|
||||
<div className="absolute flex items-center justify-center top-0 left-0 w-screen h-screen">
|
||||
<Form
|
||||
className="w-full max-w-xs flex flex-col gap-4"
|
||||
validationBehavior="native"
|
||||
onReset={() => {
|
||||
setUsername("");
|
||||
setPassword("");
|
||||
}}
|
||||
onSubmit={async (e) => {
|
||||
e.preventDefault();
|
||||
const response = await fetch(
|
||||
process.env.MODE === "PROD"
|
||||
? "https://d2jam.com/api/v1/login"
|
||||
: "http://localhost:3005/api/v1/login",
|
||||
{
|
||||
body: JSON.stringify({ username: username, password: password }),
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}
|
||||
);
|
||||
|
||||
if (response.status == 401) {
|
||||
setError("Invalid username or password");
|
||||
setPassword("");
|
||||
return;
|
||||
}
|
||||
|
||||
const token = await response.json();
|
||||
document.cookie = `token=${token}`;
|
||||
|
||||
redirect("/");
|
||||
}}
|
||||
>
|
||||
<Input
|
||||
isRequired
|
||||
errorMessage="Please enter a valid username"
|
||||
label="Username"
|
||||
labelPlacement="outside"
|
||||
name="username"
|
||||
placeholder="Enter your username"
|
||||
type="text"
|
||||
value={username}
|
||||
onValueChange={setUsername}
|
||||
/>
|
||||
|
||||
<Input
|
||||
isRequired
|
||||
errorMessage="Please enter a valid password"
|
||||
label="Password"
|
||||
labelPlacement="outside"
|
||||
name="password"
|
||||
placeholder="Enter your password"
|
||||
type="password"
|
||||
value={password}
|
||||
onValueChange={setPassword}
|
||||
/>
|
||||
<div className="flex gap-2">
|
||||
<Button color="primary" type="submit">
|
||||
Submit
|
||||
</Button>
|
||||
<Button type="reset" variant="flat">
|
||||
Reset
|
||||
</Button>
|
||||
</div>
|
||||
<p>Sign up is being worked on currently</p>
|
||||
{error && <p className="text-red-500">{error}</p>}
|
||||
{}
|
||||
</Form>
|
||||
</div>
|
||||
);
|
||||
}
|
18
src/app/logout/page.tsx
Normal file
18
src/app/logout/page.tsx
Normal file
|
@ -0,0 +1,18 @@
|
|||
"use client";
|
||||
|
||||
import { redirect } from "next/navigation";
|
||||
import React, { useEffect } from "react";
|
||||
|
||||
export default function UserPage() {
|
||||
useEffect(() => {
|
||||
document.cookie = "token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
|
||||
|
||||
redirect("/");
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="absolute flex items-center justify-center top-0 left-0 w-screen h-screen">
|
||||
<p>Logging out...</p>
|
||||
</div>
|
||||
);
|
||||
}
|
0
src/app/signup/page.tsx
Normal file
0
src/app/signup/page.tsx
Normal file
|
@ -1,3 +1,5 @@
|
|||
"use client";
|
||||
|
||||
import {
|
||||
Navbar as NavbarBase,
|
||||
NavbarBrand,
|
||||
|
@ -6,10 +8,51 @@ import {
|
|||
} from "@nextui-org/navbar";
|
||||
import { Link } from "@nextui-org/link";
|
||||
import { Divider } from "@nextui-org/divider";
|
||||
import { Image, Tooltip } from "@nextui-org/react";
|
||||
import {
|
||||
Avatar,
|
||||
Button,
|
||||
Dropdown,
|
||||
DropdownItem,
|
||||
DropdownMenu,
|
||||
DropdownTrigger,
|
||||
Image,
|
||||
Tooltip,
|
||||
} from "@nextui-org/react";
|
||||
import { SiDiscord, SiForgejo, SiGithub } from "@icons-pack/react-simple-icons";
|
||||
import { LogInIcon } from "lucide-react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { hasCookie, getCookies } from "@/helpers/cookie";
|
||||
import { usePathname } from "next/navigation";
|
||||
|
||||
export default function Navbar() {
|
||||
const [user, setUser] = useState("");
|
||||
const pathname = usePathname();
|
||||
|
||||
useEffect(() => {
|
||||
loadUser();
|
||||
async function loadUser() {
|
||||
if (!hasCookie()) {
|
||||
setUser("");
|
||||
return;
|
||||
}
|
||||
|
||||
const response = await fetch(
|
||||
process.env.MODE === "PROD"
|
||||
? "https://d2jam.com/api/v1/self"
|
||||
: "http://localhost:3005/api/v1/self",
|
||||
{
|
||||
headers: { authorization: `Bearer ${getCookies().token}` },
|
||||
}
|
||||
);
|
||||
|
||||
if ((await response.text()) == "ok") {
|
||||
setUser("ok");
|
||||
} else {
|
||||
setUser("");
|
||||
}
|
||||
}
|
||||
}, [pathname]);
|
||||
|
||||
return (
|
||||
<NavbarBase
|
||||
shouldHideOnScroll
|
||||
|
@ -83,15 +126,63 @@ export default function Navbar() {
|
|||
</Link>
|
||||
</NavbarItem>
|
||||
<Divider orientation="vertical" className="h-1/2" />
|
||||
{/* <NavbarItem>
|
||||
<Button
|
||||
endContent={<LogInIcon />}
|
||||
className="text-white border-white/50 hover:border-green-100/50 hover:text-green-100 hover:scale-110 transition-all transform duration-500 ease-in-out"
|
||||
variant="bordered"
|
||||
>
|
||||
Log In
|
||||
</Button>
|
||||
</NavbarItem> */}
|
||||
{!user ? (
|
||||
<div className="flex gap-3 items-center">
|
||||
<NavbarItem>
|
||||
<Link href="/login">
|
||||
<Button
|
||||
endContent={<LogInIcon />}
|
||||
className="text-white border-white/50 hover:border-green-100/50 hover:text-green-100 hover:scale-110 transition-all transform duration-500 ease-in-out"
|
||||
variant="bordered"
|
||||
>
|
||||
Log In
|
||||
</Button>
|
||||
</Link>
|
||||
</NavbarItem>
|
||||
{/* <NavbarItem>
|
||||
<Link href="/signup">
|
||||
<Button
|
||||
endContent={<NotebookPen />}
|
||||
className="text-white border-white/50 hover:border-green-100/50 hover:text-green-100 hover:scale-110 transition-all transform duration-500 ease-in-out"
|
||||
variant="bordered"
|
||||
>
|
||||
Sign up
|
||||
</Button>
|
||||
</Link>
|
||||
</NavbarItem> */}
|
||||
</div>
|
||||
) : (
|
||||
<Dropdown>
|
||||
<DropdownTrigger>
|
||||
<Avatar />
|
||||
</DropdownTrigger>
|
||||
<DropdownMenu>
|
||||
{/* <DropdownItem
|
||||
key="profile"
|
||||
className="text-black"
|
||||
href="/profile"
|
||||
>
|
||||
Profile
|
||||
</DropdownItem>
|
||||
<DropdownItem
|
||||
showDivider
|
||||
key="settings"
|
||||
className="text-black"
|
||||
href="/settings"
|
||||
>
|
||||
Settings
|
||||
</DropdownItem> */}
|
||||
<DropdownItem
|
||||
key="logout"
|
||||
color="danger"
|
||||
className="text-danger"
|
||||
href="/logout"
|
||||
>
|
||||
Logout
|
||||
</DropdownItem>
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
)}
|
||||
</NavbarContent>
|
||||
</NavbarBase>
|
||||
);
|
||||
|
|
20
src/helpers/cookie.ts
Normal file
20
src/helpers/cookie.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
export function getCookies() {
|
||||
const pairs = document.cookie.split(";");
|
||||
const cookies: Record<string, string> = {};
|
||||
for (let i = 0; i < pairs.length; i++) {
|
||||
const pair = pairs[i].split("=");
|
||||
cookies[(pair[0] + "").trim()] = unescape(pair.slice(1).join("="));
|
||||
}
|
||||
return cookies;
|
||||
}
|
||||
|
||||
export function hasCookie() {
|
||||
const pairs = document.cookie.split(";");
|
||||
for (let i = 0; i < pairs.length; i++) {
|
||||
const pair = pairs[i].split("=");
|
||||
if (pair[0] == "token") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
Loading…
Reference in a new issue