Compare commits

...
Author SHA1 Message Date
Hannah dagemark
f5466faa70 Add user login, signup, and session. 2026-09-02 21:39:39 +02:00
Hannah dagemark
3be05a9752 Update packages, make frontend url public env var 2026-09-02 21:37:51 +02:00
9 changed files with 939 additions and 618 deletions

View file

@ -1,2 +1,2 @@
FRONTEND_URL= NEXT_PUBLIC_FRONTEND_URL=
BACKEND_URL= BACKEND_URL=

View file

@ -1,7 +1,24 @@
import UnderConstruction from "@/components/static_pages/UnderConstruction"; import { useState } from "react";
import { login, signup } from "@/lib/server_functions/userAuth";
export default function Login() { export default function Login() {
const [createAccount, setCreateAccount] = useState(false);
return ( return (
<UnderConstruction /> <div>
) <form action={createAccount ? login : signup}>
} <input type="text" name="username" placeholder="Username" required />
<input
type="password"
name="password"
placeholder="Password"
required
/>
<button type="submit">{createAccount ? "Login" : "Signup"}</button>
</form>
<button onClick={() => setCreateAccount(!createAccount)}>
{createAccount ? "Don't have an account?" : "Already have an account?"}
</button>
</div>
);
}

View file

@ -0,0 +1,11 @@
const BACKEND_URL = process.env.BACKEND_URL;
export async function POST(request: Request) {
const response = await fetch(`${BACKEND_URL}/users/token`, request);
const data = await response.json();
return Response.json(data, {
status: response.status,
});
}

View file

@ -1,32 +1,25 @@
const BACKEND_URL = process.env.BACKEND_URL; const BACKEND_URL = process.env.BACKEND_URL;
export async function GET() { export async function GET() {
const response = await fetch(`${BACKEND_URL}/users`); const response = await fetch(`${BACKEND_URL}/users`);
if (!response.ok) { if (!response.ok) {
return new Response("Request failed in backend", { status: response.status, }); return new Response("Request failed in backend", {
} status: response.status,
});
}
const data = await response.json(); const data = await response.json();
return Response.json(data); return Response.json(data);
} }
export async function POST(request: Request) { export async function POST(request: Request) {
const response = await fetch(`${BACKEND_URL}/users`, request);
const body = await request.json(); const data = await response.json();
const response = await fetch(`${BACKEND_URL}/users`, { return Response.json(data, {
method: "POST", status: response.status,
headers: { });
"Content-Type": "application/json", }
},
body: JSON.stringify(body),
});
const data = await response.json();
return Response.json(data, {
status: response.status,
});
}

View file

@ -1,6 +1,6 @@
import { RequestInit } from "next/dist/server/web/spec-extension/request"; import { RequestInit } from "next/dist/server/web/spec-extension/request";
const FRONTEND_URL = process.env.FRONTEND_URL; const FRONTEND_URL = process.env.NEXT_PUBLIC_FRONTEND_URL;
export async function cmFetch<T>( export async function cmFetch<T>(
bffUrl: string | URL, bffUrl: string | URL,

View file

@ -1,18 +1,24 @@
export async function getUsers() { import { cmFetch } from "../cmFetch";
const response = await fetch("/api/users"); import { Token, User } from "../types";
if (!response.ok) {
throw new Error(`Response status: ${response.status}`);
}
return response.json(); export async function getUsers() {
return cmFetch<User[]>(`/api/users`);
} }
export async function getUser(id: number) { export async function getUser(id: number) {
const response = await fetch(`/api/users/${id}`); return cmFetch<User>(`/api/users/${id}`);
}
if (!response.ok) {
throw new Error(`Response status: ${response.status}`); export async function loginUser(user: FormData) {
} return cmFetch<Token>(`/api/users/login`, {
method: "POST",
return response.json(); body: user,
});
}
export async function createUser(user: FormData) {
return cmFetch<Token>(`/api/users`, {
method: "POST",
body: user,
});
} }

View file

@ -6,6 +6,12 @@ export interface User {
authority: number; authority: number;
} }
export interface Token {
access_token: string;
token_type: string;
}
export interface Service { export interface Service {
id: number | null; id: number | null;

View file

@ -0,0 +1,32 @@
import { cookies } from "next/headers";
import { redirect } from "next/navigation";
import { createUser, loginUser } from "../api/helpers/users";
import { Token } from "../api/types";
export async function login(formData: FormData) {
"use server";
const token = await loginUser(formData);
await createSession(token);
redirect("/admin/overview");
}
export async function signup(formData: FormData) {
// Technically same code as login for now but will do different stuff with it later so separating it early on
"use server";
const token = await createUser(formData);
await createSession(token);
redirect("/admin/overview");
}
export async function createSession(token: Token) {
const access_token = token.access_token;
const cookieStore = await cookies();
cookieStore.set("access_token", access_token, {
httpOnly: true,
secure: true,
sameSite: "lax",
path: "/",
});
}

1416
package-lock.json generated

File diff suppressed because it is too large Load diff