mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-31 20:24:27 -04:00
Create login and register function
This commit is contained in:
parent
2b87aacc58
commit
ffbf4be19e
@ -39,9 +39,9 @@ export const kyooUrl =
|
|||||||
? process.env.KYOO_URL ?? "http://localhost:5000"
|
? process.env.KYOO_URL ?? "http://localhost:5000"
|
||||||
: "/api";
|
: "/api";
|
||||||
|
|
||||||
const queryFn = async <Data,>(
|
export const queryFn = async <Data,>(
|
||||||
type: z.ZodType<Data>,
|
context: QueryFunctionContext | { path: string[]; body?: object; method: "GET" | "POST" },
|
||||||
context: QueryFunctionContext,
|
type?: z.ZodType<Data>,
|
||||||
): Promise<Data> => {
|
): Promise<Data> => {
|
||||||
if (!kyooUrl) console.error("Kyoo's url is not defined.");
|
if (!kyooUrl) console.error("Kyoo's url is not defined.");
|
||||||
|
|
||||||
@ -50,10 +50,21 @@ const queryFn = async <Data,>(
|
|||||||
resp = await fetch(
|
resp = await fetch(
|
||||||
[kyooUrl]
|
[kyooUrl]
|
||||||
.concat(
|
.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("/")
|
.join("/")
|
||||||
.replace("/?", "?"),
|
.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) {
|
} catch (e) {
|
||||||
console.log("Fetch error", e);
|
console.log("Fetch error", e);
|
||||||
@ -81,6 +92,7 @@ const queryFn = async <Data,>(
|
|||||||
console.error("Invald json from kyoo", e);
|
console.error("Invald json from kyoo", e);
|
||||||
throw { errors: ["Invalid repsonse from kyoo"] };
|
throw { errors: ["Invalid repsonse from kyoo"] };
|
||||||
}
|
}
|
||||||
|
if (!type) return data;
|
||||||
const parsed = await type.safeParseAsync(data);
|
const parsed = await type.safeParseAsync(data);
|
||||||
if (!parsed.success) {
|
if (!parsed.success) {
|
||||||
console.log("Parse error: ", parsed.error);
|
console.log("Parse error: ", parsed.error);
|
||||||
@ -137,7 +149,7 @@ const toQueryKey = <Data,>(query: QueryIdentifier<Data>) => {
|
|||||||
export const useFetch = <Data,>(query: QueryIdentifier<Data>) => {
|
export const useFetch = <Data,>(query: QueryIdentifier<Data>) => {
|
||||||
return useQuery<Data, KyooErrors>({
|
return useQuery<Data, KyooErrors>({
|
||||||
queryKey: toQueryKey(query),
|
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
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||||
const ret = useInfiniteQuery<Data[], KyooErrors>({
|
const ret = useInfiniteQuery<Data[], KyooErrors>({
|
||||||
queryKey: toQueryKey(query),
|
queryKey: toQueryKey(query),
|
||||||
queryFn: (ctx) => queryFn(z.array(query.parser), ctx),
|
queryFn: (ctx) => queryFn(ctx, z.array(query.parser)),
|
||||||
getNextPageParam: query.getNext,
|
getNextPageParam: query.getNext,
|
||||||
...options,
|
...options,
|
||||||
});
|
});
|
||||||
@ -158,7 +170,7 @@ export const useInfiniteFetch = <Data,>(
|
|||||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||||
const ret = useInfiniteQuery<Page<Data>, KyooErrors>({
|
const ret = useInfiniteQuery<Page<Data>, KyooErrors>({
|
||||||
queryKey: toQueryKey(query),
|
queryKey: toQueryKey(query),
|
||||||
queryFn: (ctx) => queryFn(Paged(query.parser), ctx),
|
queryFn: (ctx) => queryFn(ctx, Paged(query.parser)),
|
||||||
getNextPageParam: (page: Page<Data>) => page?.next || undefined,
|
getNextPageParam: (page: Page<Data>) => page?.next || undefined,
|
||||||
});
|
});
|
||||||
return { ...ret, items: ret.data?.pages.flatMap((x) => x.items) };
|
return { ...ret, items: ret.data?.pages.flatMap((x) => x.items) };
|
||||||
@ -175,12 +187,12 @@ export const fetchQuery = async (queries: QueryIdentifier[]) => {
|
|||||||
if (query.infinite) {
|
if (query.infinite) {
|
||||||
return client.prefetchInfiniteQuery({
|
return client.prefetchInfiniteQuery({
|
||||||
queryKey: toQueryKey(query),
|
queryKey: toQueryKey(query),
|
||||||
queryFn: (ctx) => queryFn(Paged(query.parser), ctx),
|
queryFn: (ctx) => queryFn(ctx, Paged(query.parser)),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return client.prefetchQuery({
|
return client.prefetchQuery({
|
||||||
queryKey: toQueryKey(query),
|
queryKey: toQueryKey(query),
|
||||||
queryFn: (ctx) => queryFn(query.parser, ctx),
|
queryFn: (ctx) => queryFn(ctx, query.parser),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
@ -26,7 +26,6 @@ import { ts } from "./utils";
|
|||||||
|
|
||||||
export const Button = ({
|
export const Button = ({
|
||||||
text,
|
text,
|
||||||
onPress,
|
|
||||||
...props
|
...props
|
||||||
}: { text: string } & ComponentProps<typeof PressableFeedback>) => {
|
}: { text: string } & ComponentProps<typeof PressableFeedback>) => {
|
||||||
const { css } = useYoshiki();
|
const { css } = useYoshiki();
|
||||||
|
35
front/packages/ui/src/login/api.ts
Normal file
35
front/packages/ui/src/login/api.ts
Normal 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];
|
||||||
|
}
|
||||||
|
};
|
@ -18,7 +18,7 @@
|
|||||||
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
* 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 { Button, P, Input, ts, H1, A } from "@kyoo/primitives";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@ -28,32 +28,7 @@ import { percent, px, useYoshiki } from "yoshiki/native";
|
|||||||
import { DefaultLayout } from "../layout";
|
import { DefaultLayout } from "../layout";
|
||||||
import { FormPage } from "./form";
|
import { FormPage } from "./form";
|
||||||
import { PasswordInput } from "./password-input";
|
import { PasswordInput } from "./password-input";
|
||||||
|
import { loginFunc } from "./api";
|
||||||
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 };
|
|
||||||
};
|
|
||||||
|
|
||||||
export const LoginPage: QueryPage = () => {
|
export const LoginPage: QueryPage = () => {
|
||||||
const [username, setUsername] = useState("");
|
const [username, setUsername] = useState("");
|
||||||
@ -88,7 +63,7 @@ export const LoginPage: QueryPage = () => {
|
|||||||
<Button
|
<Button
|
||||||
text={t("login.login")}
|
text={t("login.login")}
|
||||||
onPress={async () => {
|
onPress={async () => {
|
||||||
const { error } = await login(username, password);
|
const error = await loginFunc("login", {username, password});
|
||||||
setError(error);
|
setError(error);
|
||||||
}}
|
}}
|
||||||
{...css({
|
{...css({
|
||||||
|
@ -18,9 +18,9 @@
|
|||||||
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
* 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 { Button, P, Input, ts, H1, A } from "@kyoo/primitives";
|
||||||
import { useEffect, useState } from "react";
|
import { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Platform } from "react-native";
|
import { Platform } from "react-native";
|
||||||
import { Trans } from "react-i18next";
|
import { Trans } from "react-i18next";
|
||||||
@ -28,6 +28,7 @@ import { percent, px, useYoshiki } from "yoshiki/native";
|
|||||||
import { DefaultLayout } from "../layout";
|
import { DefaultLayout } from "../layout";
|
||||||
import { FormPage } from "./form";
|
import { FormPage } from "./form";
|
||||||
import { PasswordInput } from "./password-input";
|
import { PasswordInput } from "./password-input";
|
||||||
|
import { loginFunc } from "./api";
|
||||||
|
|
||||||
export const RegisterPage: QueryPage = () => {
|
export const RegisterPage: QueryPage = () => {
|
||||||
const [email, setEmail] = useState("");
|
const [email, setEmail] = useState("");
|
||||||
@ -74,10 +75,11 @@ export const RegisterPage: QueryPage = () => {
|
|||||||
)}
|
)}
|
||||||
{error && <P {...css({ color: (theme) => theme.colors.red })}>{error}</P>}
|
{error && <P {...css({ color: (theme) => theme.colors.red })}>{error}</P>}
|
||||||
<Button
|
<Button
|
||||||
text={t("login.login")}
|
text={t("login.register")}
|
||||||
disabled={error != null || password !== confirm}
|
disabled={password !== confirm}
|
||||||
onPress={async () => {
|
onPress={async () => {
|
||||||
const { error } = await register(email, username, password);
|
console.log("toto")
|
||||||
|
const error = await loginFunc("register", { email, username, password });
|
||||||
setError(error);
|
setError(error);
|
||||||
}}
|
}}
|
||||||
{...css({
|
{...css({
|
||||||
|
Loading…
x
Reference in New Issue
Block a user