feat: minimal UI for login

This commit is contained in:
2025-04-11 11:08:33 +01:00
parent 36d60d7985
commit 4dbe1508c2
5 changed files with 86 additions and 0 deletions

View File

@ -62,6 +62,10 @@ func main() {
}) })
}) })
r.Options("/*", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
r.Get("/image", func(w http.ResponseWriter, r *http.Request) { r.Get("/image", func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Authorization")[7:] token := r.Header.Get("Authorization")[7:]

View File

@ -7,6 +7,7 @@ import { SearchCardLocation } from "./components/search-card/SearchCardLocation"
import { UserImage, getUserImages } from "./network"; import { UserImage, getUserImages } from "./network";
import { getCardSize } from "./utils/getCardSize"; import { getCardSize } from "./utils/getCardSize";
import { SearchCardNote } from "./components/search-card/SearchCardNote"; import { SearchCardNote } from "./components/search-card/SearchCardNote";
import { A } from "@solidjs/router";
const getCardComponent = (item: UserImage) => { const getCardComponent = (item: UserImage) => {
switch (item.type) { switch (item.type) {
@ -99,6 +100,7 @@ function App() {
return ( return (
<> <>
<main class="container pt-2"> <main class="container pt-2">
<A href="login">login</A>
<div class="px-4"> <div class="px-4">
<div class="inline-flex justify-between w-full rounded-xl text-base leading-none outline-none bg-white border border-neutral-200 text-neutral-900"> <div class="inline-flex justify-between w-full rounded-xl text-base leading-none outline-none bg-white border border-neutral-200 text-neutral-900">
<div class="appearance-none inline-flex justify-center items-center w-auto outline-none rounded-l-md px-2.5 text-gray-900"> <div class="appearance-none inline-flex justify-center items-center w-auto outline-none rounded-l-md px-2.5 text-gray-900">

48
frontend/src/Login.tsx Normal file
View File

@ -0,0 +1,48 @@
import { Button } from "@kobalte/core/button";
import { TextField } from "@kobalte/core/text-field";
import { createSignal, Show, type Component } from "solid-js";
import { postCode, postLogin } from "./network";
export const Login: Component = () => {
let form: HTMLFormElement | undefined;
const [submitted, setSubmitted] = createSignal(false);
const onSubmit: HTMLFormElement["onsubmit"] = async (e) => {
e.preventDefault();
const formData = new FormData(form);
const email = formData.get("email");
if (email == null) {
throw new Error("bruh, no email");
}
if (!submitted()) {
await postLogin(email.toString());
setSubmitted(true);
} else {
const code = formData.get("code");
if (code == null) {
throw new Error("bruh, no code");
}
const res = await postCode(email.toString(), code.toString());
console.log(res);
}
};
return (
<form ref={form} onSubmit={onSubmit}>
<TextField name="email">
<TextField.Label>Email</TextField.Label>
<TextField.Input />
</TextField>
<Show when={submitted()}>
<TextField name="code">
<TextField.Label>Code</TextField.Label>
<TextField.Input />
</TextField>
</Show>
<Button type="submit">Submit</Button>
</form>
);
};

View File

@ -4,11 +4,13 @@ import App from "./App";
import "./index.css"; import "./index.css";
import { Route, Router } from "@solidjs/router"; import { Route, Router } from "@solidjs/router";
import { ImagePage } from "./ImagePage"; import { ImagePage } from "./ImagePage";
import { Login } from "./Login";
render( render(
() => ( () => (
<Router> <Router>
<Route path="/" component={App} /> <Route path="/" component={App} />
<Route path="/login" component={Login} />
<Route path="/image/:imageId" component={ImagePage} /> <Route path="/image/:imageId" component={ImagePage} />
</Router> </Router>
), ),

View File

@ -113,3 +113,33 @@ export const getUserImages = async (): Promise<UserImage[]> => {
return parse(getUserImagesResponseValidator, res); return parse(getUserImagesResponseValidator, res);
}; };
export const postLogin = async (email: string): Promise<void> => {
const request = getBaseRequest({
path: "login",
body: JSON.stringify({ email }),
method: "POST",
});
await fetch(request);
};
const codeValidator = strictObject({
access: string(),
refresh: string(),
});
export const postCode = async (
email: string,
code: string,
): Promise<InferOutput<typeof codeValidator>> => {
const request = getBaseRequest({
path: "code",
body: JSON.stringify({ email, code }),
method: "POST",
});
const res = await fetch(request).then((res) => res.json());
return parse(codeValidator, res);
};