Create login and register function

This commit is contained in:
Zoe Roux 2023-02-01 02:50:11 +09:00 committed by Zoe Roux
parent 2b87aacc58
commit ffbf4be19e
5 changed files with 66 additions and 43 deletions

View File

@ -39,9 +39,9 @@ export const kyooUrl =
? process.env.KYOO_URL ?? "http://localhost:5000"
: "/api";
const queryFn = async <Data,>(
type: z.ZodType<Data>,
context: QueryFunctionContext,
export const queryFn = async <Data,>(
context: QueryFunctionContext | { path: string[]; body?: object; method: "GET" | "POST" },
type?: z.ZodType<Data>,
): Promise<Data> => {
if (!kyooUrl) console.error("Kyoo's url is not defined.");
@ -50,10 +50,21 @@ const queryFn = async <Data,>(
resp = await fetch(
[kyooUrl]
.concat(
context.pageParam ? [context.pageParam] : (context.queryKey.filter((x) => x) as string[]),
"path" in context
? context.path
: context.pageParam
? [context.pageParam]
: (context.queryKey.filter((x) => x) as string[]),
)
.join("/")
.replace("/?", "?"),
{
// @ts-ignore
method: context.method,
// @ts-ignore
body: context.body ? JSON.stringify(context.body) : undefined,
headers: "body" in context ? { "Content-Type": "application/json" } : undefined,
},
);
} catch (e) {
console.log("Fetch error", e);
@ -81,6 +92,7 @@ const queryFn = async <Data,>(
console.error("Invald json from kyoo", e);
throw { errors: ["Invalid repsonse from kyoo"] };
}
if (!type) return data;
const parsed = await type.safeParseAsync(data);
if (!parsed.success) {
console.log("Parse error: ", parsed.error);
@ -137,7 +149,7 @@ const toQueryKey = <Data,>(query: QueryIdentifier<Data>) => {
export const useFetch = <Data,>(query: QueryIdentifier<Data>) => {
return useQuery<Data, KyooErrors>({
queryKey: toQueryKey(query),
queryFn: (ctx) => queryFn(query.parser, ctx),
queryFn: (ctx) => queryFn(ctx, query.parser),
});
};
@ -149,7 +161,7 @@ export const useInfiniteFetch = <Data,>(
// eslint-disable-next-line react-hooks/rules-of-hooks
const ret = useInfiniteQuery<Data[], KyooErrors>({
queryKey: toQueryKey(query),
queryFn: (ctx) => queryFn(z.array(query.parser), ctx),
queryFn: (ctx) => queryFn(ctx, z.array(query.parser)),
getNextPageParam: query.getNext,
...options,
});
@ -158,7 +170,7 @@ export const useInfiniteFetch = <Data,>(
// eslint-disable-next-line react-hooks/rules-of-hooks
const ret = useInfiniteQuery<Page<Data>, KyooErrors>({
queryKey: toQueryKey(query),
queryFn: (ctx) => queryFn(Paged(query.parser), ctx),
queryFn: (ctx) => queryFn(ctx, Paged(query.parser)),
getNextPageParam: (page: Page<Data>) => page?.next || undefined,
});
return { ...ret, items: ret.data?.pages.flatMap((x) => x.items) };
@ -175,12 +187,12 @@ export const fetchQuery = async (queries: QueryIdentifier[]) => {
if (query.infinite) {
return client.prefetchInfiniteQuery({
queryKey: toQueryKey(query),
queryFn: (ctx) => queryFn(Paged(query.parser), ctx),
queryFn: (ctx) => queryFn(ctx, Paged(query.parser)),
});
} else {
return client.prefetchQuery({
queryKey: toQueryKey(query),
queryFn: (ctx) => queryFn(query.parser, ctx),
queryFn: (ctx) => queryFn(ctx, query.parser),
});
}
}),

View File

@ -26,7 +26,6 @@ import { ts } from "./utils";
export const Button = ({
text,
onPress,
...props
}: { text: string } & ComponentProps<typeof PressableFeedback>) => {
const { css } = useYoshiki();

View File

@ -0,0 +1,35 @@
/*
* Kyoo - A portable and vast media library solution.
* Copyright (c) Kyoo.
*
* See AUTHORS.md and LICENSE file in the project root for full license information.
*
* Kyoo is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* Kyoo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
*/
import { KyooErrors, queryFn } from "@kyoo/models";
export const loginFunc = async (action: "register" | "login", body: object) => {
try {
const token = await queryFn({
path: ["auth", action],
method: "POST",
body: body,
});
return null;
} catch (e) {
return (e as KyooErrors).errors[0];
}
};

View File

@ -18,7 +18,7 @@
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
*/
import { KyooErrors, kyooUrl, QueryPage } from "@kyoo/models";
import { QueryPage } from "@kyoo/models";
import { Button, P, Input, ts, H1, A } from "@kyoo/primitives";
import { useState } from "react";
import { useTranslation } from "react-i18next";
@ -28,32 +28,7 @@ import { percent, px, useYoshiki } from "yoshiki/native";
import { DefaultLayout } from "../layout";
import { FormPage } from "./form";
import { PasswordInput } from "./password-input";
const login = async (username: string, password: string) => {
let resp;
try {
resp = await fetch(`${kyooUrl}/auth/login`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
username,
password,
}),
});
} catch (e) {
console.error("Login error", e);
throw { errors: ["Could not reach Kyoo's server."] } as KyooErrors;
}
if (!resp.ok) {
const err = (await resp.json()) as KyooErrors;
return { type: "error", value: null, error: err.errors[0] };
}
const token = await resp.json();
// TODO: Save the token in the secure storage.
return { type: "value", value: token, error: null };
};
import { loginFunc } from "./api";
export const LoginPage: QueryPage = () => {
const [username, setUsername] = useState("");
@ -88,7 +63,7 @@ export const LoginPage: QueryPage = () => {
<Button
text={t("login.login")}
onPress={async () => {
const { error } = await login(username, password);
const error = await loginFunc("login", {username, password});
setError(error);
}}
{...css({

View File

@ -18,9 +18,9 @@
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
*/
import { KyooErrors, kyooUrl, QueryPage } from "@kyoo/models";
import { QueryPage } from "@kyoo/models";
import { Button, P, Input, ts, H1, A } from "@kyoo/primitives";
import { useEffect, useState } from "react";
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { Platform } from "react-native";
import { Trans } from "react-i18next";
@ -28,6 +28,7 @@ import { percent, px, useYoshiki } from "yoshiki/native";
import { DefaultLayout } from "../layout";
import { FormPage } from "./form";
import { PasswordInput } from "./password-input";
import { loginFunc } from "./api";
export const RegisterPage: QueryPage = () => {
const [email, setEmail] = useState("");
@ -74,10 +75,11 @@ export const RegisterPage: QueryPage = () => {
)}
{error && <P {...css({ color: (theme) => theme.colors.red })}>{error}</P>}
<Button
text={t("login.login")}
disabled={error != null || password !== confirm}
text={t("login.register")}
disabled={password !== confirm}
onPress={async () => {
const { error } = await register(email, username, password);
console.log("toto")
const error = await loginFunc("register", { email, username, password });
setError(error);
}}
{...css({