98 lines
2.7 KiB
TypeScript
98 lines
2.7 KiB
TypeScript
import { Schema as S } from "@effect/schema";
|
|
import { Login as LoginApi } from "common/api";
|
|
import { Effect, Fiber, Option as O, pipe } from "effect";
|
|
import { useLocation } from "preact-iso";
|
|
import { useId, useMemo, useRef } from "preact/hooks";
|
|
import { useStore } from "../store";
|
|
import * as style from "./Login.css";
|
|
|
|
export const Login = () => {
|
|
|
|
const { route } = useLocation();
|
|
|
|
const loginUsername = useStore(state => state.loginUsername);
|
|
const loginPassword = useStore(state => state.loginPassword);
|
|
|
|
const setLoginUsername = useStore(state => state.setLoginUsername);
|
|
const setLoginPassword = useStore(state => state.setLoginPassword);
|
|
|
|
const setUser = useStore(state => state.setUser);
|
|
|
|
const usernameId = useId();
|
|
const passwordId = useId();
|
|
|
|
const requestFiber = useRef<Fiber.RuntimeFiber<void> | null>(null);
|
|
const requestEffect = useMemo(() => Effect.gen(function* () {
|
|
const requestData = LoginApi.props.request.schema.make({ username: loginUsername, password: loginPassword });
|
|
|
|
const requestJson = yield* pipe(
|
|
requestData,
|
|
S.encode(LoginApi.props.request.schema),
|
|
Effect.map(JSON.stringify),
|
|
Effect.orDie,
|
|
);
|
|
|
|
const res = yield* Effect.promise((signal) => fetch("http://localhost:3000/login", {
|
|
method: "POST",
|
|
body: requestJson,
|
|
headers: { "Content-Type": "application/json" },
|
|
signal,
|
|
credentials: "include",
|
|
}));
|
|
|
|
if (!res.ok) {
|
|
yield* Effect.die(new Error("Response was not ok"));
|
|
}
|
|
|
|
const responseData = yield* pipe(
|
|
Effect.promise(() => res.json()),
|
|
Effect.flatMap(S.decodeUnknown(LoginApi.props.response[200].schema)),
|
|
Effect.orDie,
|
|
);
|
|
|
|
setLoginUsername("");
|
|
setLoginPassword("");
|
|
setUser(O.some(responseData));
|
|
|
|
route("/");
|
|
}), [loginUsername, loginPassword]);
|
|
|
|
const onSubmit = (e: SubmitEvent) => {
|
|
e.preventDefault();
|
|
|
|
if (requestFiber.current !== null) {
|
|
Effect.runFork(Fiber.interrupt(requestFiber.current), { immediate: true });
|
|
}
|
|
|
|
requestFiber.current = Effect.runFork(requestEffect);
|
|
};
|
|
|
|
return (
|
|
<div class={style.container}>
|
|
<form class={style.box} onSubmit={onSubmit}>
|
|
<header class={style.header}>Repozytorium muzyczne</header>
|
|
<label for={usernameId}>Nazwa użytkownika</label>
|
|
<input
|
|
id={usernameId}
|
|
class={style.input}
|
|
type="text"
|
|
value={loginUsername}
|
|
autofocus
|
|
required
|
|
onInput={(e) => setLoginUsername(e.currentTarget.value)}
|
|
/>
|
|
<label for={passwordId}>Hasło</label>
|
|
<input
|
|
id={passwordId}
|
|
class={style.input}
|
|
type="password"
|
|
value={loginPassword}
|
|
required
|
|
onInput={(e) => setLoginPassword(e.currentTarget.value)}
|
|
/>
|
|
<button class={style.submit} type="submit">Zaloguj się</button>
|
|
</form>
|
|
</div>
|
|
);
|
|
};
|