mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-24 02:02:36 -04:00
Add a register page
This commit is contained in:
parent
b62b272492
commit
2b87aacc58
23
front/apps/mobile/app/register/index.tsx
Normal file
23
front/apps/mobile/app/register/index.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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 { RegisterPage } from "@kyoo/ui";
|
||||
|
||||
export default RegisterPage;
|
24
front/apps/web/src/pages/register/index.tsx
Normal file
24
front/apps/web/src/pages/register/index.tsx
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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 { RegisterPage } from "@kyoo/ui";
|
||||
import { withRoute } from "~/router";
|
||||
|
||||
export default withRoute(RegisterPage);
|
@ -18,7 +18,8 @@
|
||||
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { px, Stylable, Theme, useYoshiki } from "yoshiki/native";
|
||||
import { ComponentProps } from "react";
|
||||
import { Theme, useYoshiki } from "yoshiki/native";
|
||||
import { PressableFeedback } from "./links";
|
||||
import { P } from "./text";
|
||||
import { ts } from "./utils";
|
||||
@ -27,16 +28,15 @@ export const Button = ({
|
||||
text,
|
||||
onPress,
|
||||
...props
|
||||
}: { text: string; onPress?: () => void } & Stylable) => {
|
||||
}: { text: string } & ComponentProps<typeof PressableFeedback>) => {
|
||||
const { css } = useYoshiki();
|
||||
|
||||
return (
|
||||
<PressableFeedback
|
||||
onPress={onPress}
|
||||
{...css(
|
||||
{
|
||||
flexGrow: 0,
|
||||
p: ts(.5),
|
||||
p: ts(0.5),
|
||||
borderRadius: ts(5),
|
||||
borderColor: (theme) => theme.accent,
|
||||
borderWidth: ts(0.5),
|
||||
@ -45,6 +45,7 @@ export const Button = ({
|
||||
text: { color: (theme: Theme) => theme.colors.white },
|
||||
},
|
||||
},
|
||||
// @ts-ignore ??
|
||||
props,
|
||||
)}
|
||||
>
|
||||
|
@ -23,4 +23,4 @@ export { BrowsePage } from "./browse";
|
||||
export { MovieDetails, ShowDetails } from "./details";
|
||||
export { Player } from "./player";
|
||||
export { SearchPage } from "./search";
|
||||
export { LoginPage } from "./login";
|
||||
export { LoginPage, RegisterPage } from "./login";
|
||||
|
86
front/packages/ui/src/login/form.tsx
Normal file
86
front/packages/ui/src/login/form.tsx
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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 { ts } from "@kyoo/primitives";
|
||||
import { ReactNode } from "react";
|
||||
import { ImageBackground, ImageProps, Platform, View } from "react-native";
|
||||
import Svg, { SvgProps, Path } from "react-native-svg";
|
||||
import { min, percent, px, Stylable, useYoshiki, vh, vw } from "yoshiki/native";
|
||||
|
||||
const SvgBlob = (props: SvgProps) => {
|
||||
const { css, theme } = useYoshiki();
|
||||
|
||||
return (
|
||||
<View {...css({ width: percent(100), aspectRatio: 5 / 6 }, props)}>
|
||||
<Svg width="100%" height="100%" viewBox="0 0 500 600">
|
||||
<Path
|
||||
d="M459.7 0c-20.2 43.3-40.3 86.6-51.7 132.6-11.3 45.9-13.9 94.6-36.1 137.6-22.2 43-64.1 80.3-111.5 88.2s-100.2-13.7-144.5-1.8C71.6 368.6 35.8 414.2 0 459.7V0h459.7z"
|
||||
fill={theme.background}
|
||||
/>
|
||||
</Svg>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export const FormPage = ({ children, ...props }: { children: ReactNode } & Stylable) => {
|
||||
const { css } = useYoshiki();
|
||||
|
||||
// TODO: Replace the hardcoded 1 to a random show/movie thumbnail.
|
||||
const src = `${Platform.OS === "web" ? "/api/" : process.env.PUBLIC_BACK_URL}/shows/1/thumbnail`;
|
||||
const nativeProps = Platform.select<ImageProps>({
|
||||
web: {
|
||||
defaultSource: typeof src === "string" ? { uri: src! } : Array.isArray(src) ? src[0] : src!,
|
||||
},
|
||||
default: {},
|
||||
});
|
||||
|
||||
return (
|
||||
<ImageBackground
|
||||
source={{ uri: src }}
|
||||
{...nativeProps}
|
||||
{...css({
|
||||
flexDirection: "row",
|
||||
flexGrow: 1,
|
||||
backgroundColor: (theme) => theme.dark.background,
|
||||
})}
|
||||
>
|
||||
<View
|
||||
{...css({
|
||||
width: min(vh(90), px(1200)),
|
||||
height: min(vh(90), px(1200)),
|
||||
})}
|
||||
>
|
||||
<SvgBlob {...css({ position: "absolute", top: 0, left: 0 })} />
|
||||
<View
|
||||
{...css(
|
||||
{
|
||||
width: percent(75),
|
||||
paddingHorizontal: ts(3),
|
||||
maxWidth: vw(100),
|
||||
},
|
||||
props,
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</View>
|
||||
</View>
|
||||
</ImageBackground>
|
||||
);
|
||||
};
|
22
front/packages/ui/src/login/index.ts
Normal file
22
front/packages/ui/src/login/index.ts
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
export { LoginPage } from "./login";
|
||||
export { RegisterPage } from "./register";
|
@ -1,181 +0,0 @@
|
||||
/*
|
||||
* 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, kyooUrl, QueryPage } from "@kyoo/models";
|
||||
import { Button, P, Input, ts, H1, A, IconButton } from "@kyoo/primitives";
|
||||
import { ComponentProps, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { ImageBackground, ImageProps, Platform, View } from "react-native";
|
||||
import { Trans } from "react-i18next";
|
||||
import { min, percent, px, useYoshiki, vh, vw } from "yoshiki/native";
|
||||
import Visibility from "@material-symbols/svg-400/rounded/visibility-fill.svg";
|
||||
import VisibilityOff from "@material-symbols/svg-400/rounded/visibility_off-fill.svg";
|
||||
import { DefaultLayout } from "../layout";
|
||||
import Svg, { SvgProps, Path } from "react-native-svg";
|
||||
|
||||
const SvgBlob = (props: SvgProps) => {
|
||||
const { css, theme } = useYoshiki();
|
||||
|
||||
return (
|
||||
<View {...css({ width: percent(100), aspectRatio: 5 / 6 }, props)}>
|
||||
<Svg width="100%" height="100%" viewBox="0 0 500 600">
|
||||
<Path
|
||||
d="M459.7 0c-20.2 43.3-40.3 86.6-51.7 132.6-11.3 45.9-13.9 94.6-36.1 137.6-22.2 43-64.1 80.3-111.5 88.2s-100.2-13.7-144.5-1.8C71.6 368.6 35.8 414.2 0 459.7V0h459.7z"
|
||||
fill={theme.background}
|
||||
/>
|
||||
</Svg>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const PasswordInput = (props: ComponentProps<typeof Input>) => {
|
||||
const { css } = useYoshiki();
|
||||
const [show, setVisibility] = useState(false);
|
||||
|
||||
return (
|
||||
<Input
|
||||
secureTextEntry={!show}
|
||||
right={
|
||||
<IconButton
|
||||
icon={show ? VisibilityOff : Visibility}
|
||||
size={19}
|
||||
onPress={() => setVisibility(!show)}
|
||||
{...css({ width: px(19), height: px(19), m: 0, p: 0 })}
|
||||
/>
|
||||
}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
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 = () => {
|
||||
const { t } = useTranslation();
|
||||
const { css } = useYoshiki();
|
||||
|
||||
// TODO: Replace the hardcoded 1 to a random show/movie thumbnail.
|
||||
const src = `${Platform.OS === "web" ? "/api/" : process.env.PUBLIC_BACK_URL}/shows/1/thumbnail`;
|
||||
const nativeProps = Platform.select<ImageProps>({
|
||||
web: {
|
||||
defaultSource: typeof src === "string" ? { uri: src! } : Array.isArray(src) ? src[0] : src!,
|
||||
},
|
||||
default: {},
|
||||
});
|
||||
|
||||
const [username, setUsername] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
return (
|
||||
<ImageBackground
|
||||
source={{ uri: src }}
|
||||
{...nativeProps}
|
||||
{...css({
|
||||
flexDirection: "row",
|
||||
flexGrow: 1,
|
||||
backgroundColor: (theme) => theme.dark.background,
|
||||
})}
|
||||
>
|
||||
<View
|
||||
{...css({
|
||||
width: min(vh(90), px(1200)),
|
||||
height: min(vh(90), px(1200)),
|
||||
})}
|
||||
>
|
||||
<SvgBlob {...css({ position: "absolute", top: 0, left: 0 })} />
|
||||
<View
|
||||
{...css({
|
||||
width: percent(75),
|
||||
maxWidth: vw(100),
|
||||
paddingHorizontal: ts(3),
|
||||
marginTop: Platform.OS === "web" ? ts(6) : 0,
|
||||
})}
|
||||
>
|
||||
<H1>{t("login.login")}</H1>
|
||||
{Platform.OS !== "web" && (
|
||||
<>
|
||||
<P {...css({ paddingLeft: ts(1) })}>{t("login.server")}</P>
|
||||
<Input variant="big" />
|
||||
</>
|
||||
)}
|
||||
<P {...css({ paddingLeft: ts(1) })}>{t("login.username")}</P>
|
||||
<Input
|
||||
autoComplete="username"
|
||||
variant="big"
|
||||
onChangeText={(value) => setUsername(value)}
|
||||
/>
|
||||
<P {...css({ paddingLeft: ts(1) })}>{t("login.password")}</P>
|
||||
<PasswordInput
|
||||
autoComplete="password"
|
||||
variant="big"
|
||||
onChangeText={(value) => setPassword(value)}
|
||||
/>
|
||||
{error && <P {...css({ color: (theme) => theme.colors.red })}>{error}</P>}
|
||||
<Button
|
||||
text={t("login.login")}
|
||||
onPress={async () => {
|
||||
const { error } = await login(username, password);
|
||||
setError(error);
|
||||
}}
|
||||
{...css({
|
||||
m: ts(1),
|
||||
width: px(250),
|
||||
maxWidth: percent(100),
|
||||
alignSelf: "center",
|
||||
mY: ts(3),
|
||||
})}
|
||||
/>
|
||||
<P>
|
||||
<Trans i18nKey="login.or-register">
|
||||
Don’t have an account? <A href="/register">Register</A>.
|
||||
</Trans>
|
||||
</P>
|
||||
</View>
|
||||
</View>
|
||||
</ImageBackground>
|
||||
);
|
||||
};
|
||||
|
||||
LoginPage.getLayout = DefaultLayout;
|
111
front/packages/ui/src/login/login.tsx
Normal file
111
front/packages/ui/src/login/login.tsx
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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, kyooUrl, QueryPage } from "@kyoo/models";
|
||||
import { Button, P, Input, ts, H1, A } from "@kyoo/primitives";
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Platform } from "react-native";
|
||||
import { Trans } from "react-i18next";
|
||||
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 };
|
||||
};
|
||||
|
||||
export const LoginPage: QueryPage = () => {
|
||||
const [username, setUsername] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const { t } = useTranslation();
|
||||
const { css } = useYoshiki();
|
||||
|
||||
return (
|
||||
<FormPage
|
||||
{...css({
|
||||
marginTop: Platform.OS === "web" ? ts(6) : 0,
|
||||
})}
|
||||
>
|
||||
<H1>{t("login.login")}</H1>
|
||||
{Platform.OS !== "web" && (
|
||||
<>
|
||||
<P {...css({ paddingLeft: ts(1) })}>{t("login.server")}</P>
|
||||
<Input variant="big" />
|
||||
</>
|
||||
)}
|
||||
<P {...css({ paddingLeft: ts(1) })}>{t("login.username")}</P>
|
||||
<Input autoComplete="username" variant="big" onChangeText={(value) => setUsername(value)} />
|
||||
<P {...css({ paddingLeft: ts(1) })}>{t("login.password")}</P>
|
||||
<PasswordInput
|
||||
autoComplete="password"
|
||||
variant="big"
|
||||
onChangeText={(value) => setPassword(value)}
|
||||
/>
|
||||
{error && <P {...css({ color: (theme) => theme.colors.red })}>{error}</P>}
|
||||
<Button
|
||||
text={t("login.login")}
|
||||
onPress={async () => {
|
||||
const { error } = await login(username, password);
|
||||
setError(error);
|
||||
}}
|
||||
{...css({
|
||||
m: ts(1),
|
||||
width: px(250),
|
||||
maxWidth: percent(100),
|
||||
alignSelf: "center",
|
||||
mY: ts(3),
|
||||
})}
|
||||
/>
|
||||
<P>
|
||||
<Trans i18nKey="login.or-register">
|
||||
Don’t have an account? <A href="/register">Register</A>.
|
||||
</Trans>
|
||||
</P>
|
||||
</FormPage>
|
||||
);
|
||||
};
|
||||
|
||||
LoginPage.getLayout = DefaultLayout;
|
45
front/packages/ui/src/login/password-input.tsx
Normal file
45
front/packages/ui/src/login/password-input.tsx
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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 { IconButton, Input } from "@kyoo/primitives";
|
||||
import { ComponentProps, useState } from "react";
|
||||
import { px, useYoshiki } from "yoshiki/native";
|
||||
import Visibility from "@material-symbols/svg-400/rounded/visibility-fill.svg";
|
||||
import VisibilityOff from "@material-symbols/svg-400/rounded/visibility_off-fill.svg";
|
||||
|
||||
export const PasswordInput = (props: ComponentProps<typeof Input>) => {
|
||||
const { css } = useYoshiki();
|
||||
const [show, setVisibility] = useState(false);
|
||||
|
||||
return (
|
||||
<Input
|
||||
secureTextEntry={!show}
|
||||
right={
|
||||
<IconButton
|
||||
icon={show ? VisibilityOff : Visibility}
|
||||
size={19}
|
||||
onPress={() => setVisibility(!show)}
|
||||
{...css({ width: px(19), height: px(19), m: 0, p: 0 })}
|
||||
/>
|
||||
}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
100
front/packages/ui/src/login/register.tsx
Normal file
100
front/packages/ui/src/login/register.tsx
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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, kyooUrl, QueryPage } from "@kyoo/models";
|
||||
import { Button, P, Input, ts, H1, A } from "@kyoo/primitives";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Platform } from "react-native";
|
||||
import { Trans } from "react-i18next";
|
||||
import { percent, px, useYoshiki } from "yoshiki/native";
|
||||
import { DefaultLayout } from "../layout";
|
||||
import { FormPage } from "./form";
|
||||
import { PasswordInput } from "./password-input";
|
||||
|
||||
export const RegisterPage: QueryPage = () => {
|
||||
const [email, setEmail] = useState("");
|
||||
const [username, setUsername] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [confirm, setConfirm] = useState("");
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const { t } = useTranslation();
|
||||
const { css } = useYoshiki();
|
||||
|
||||
return (
|
||||
<FormPage>
|
||||
<H1>{t("login.register")}</H1>
|
||||
{Platform.OS !== "web" && (
|
||||
<>
|
||||
<P {...css({ paddingLeft: ts(1) })}>{t("login.server")}</P>
|
||||
<Input variant="big" />
|
||||
</>
|
||||
)}
|
||||
|
||||
<P {...css({ paddingLeft: ts(1) })}>{t("login.username")}</P>
|
||||
<Input autoComplete="username" variant="big" onChangeText={(value) => setUsername(value)} />
|
||||
|
||||
<P {...css({ paddingLeft: ts(1) })}>{t("login.email")}</P>
|
||||
<Input autoComplete="email" variant="big" onChangeText={(value) => setEmail(value)} />
|
||||
|
||||
<P {...css({ paddingLeft: ts(1) })}>{t("login.password")}</P>
|
||||
<PasswordInput
|
||||
autoComplete="password-new"
|
||||
variant="big"
|
||||
onChangeText={(value) => setPassword(value)}
|
||||
/>
|
||||
|
||||
<P {...css({ paddingLeft: ts(1) })}>{t("login.confirm")}</P>
|
||||
<PasswordInput
|
||||
autoComplete="password-new"
|
||||
variant="big"
|
||||
onChangeText={(value) => setConfirm(value)}
|
||||
/>
|
||||
|
||||
{password !== confirm && (
|
||||
<P {...css({ color: (theme) => theme.colors.red })}>{t("login.password-no-match")}</P>
|
||||
)}
|
||||
{error && <P {...css({ color: (theme) => theme.colors.red })}>{error}</P>}
|
||||
<Button
|
||||
text={t("login.login")}
|
||||
disabled={error != null || password !== confirm}
|
||||
onPress={async () => {
|
||||
const { error } = await register(email, username, password);
|
||||
setError(error);
|
||||
}}
|
||||
{...css({
|
||||
m: ts(1),
|
||||
width: px(250),
|
||||
maxWidth: percent(100),
|
||||
alignSelf: "center",
|
||||
mY: ts(3),
|
||||
})}
|
||||
/>
|
||||
<P>
|
||||
<Trans i18nKey="login.or-login">
|
||||
Have an account already? <A href="/login">Log in</A>.
|
||||
</Trans>
|
||||
</P>
|
||||
</FormPage>
|
||||
);
|
||||
};
|
||||
|
||||
RegisterPage.getLayout = DefaultLayout;
|
@ -57,6 +57,9 @@
|
||||
"email": "Email",
|
||||
"username": "Username",
|
||||
"password": "Password",
|
||||
"or-register": "Don’t have an account? <1>Register</1>."
|
||||
"confirm": "Confirm Password",
|
||||
"or-register": "Don’t have an account? <1>Register</1>.",
|
||||
"or-login": "Have an account already? <1>Log in</1>.",
|
||||
"password-no-match": "Passwords do not match."
|
||||
}
|
||||
}
|
||||
|
@ -57,6 +57,9 @@
|
||||
"email": "Email",
|
||||
"username": "Username",
|
||||
"password": "Mot de passe",
|
||||
"or-register": "Vous n'avez pas de compte ? <1>Inscrivez-vous</1>."
|
||||
"confirm": "Confirm Password",
|
||||
"or-register": "Vous n'avez pas de compte ? <1>Inscrivez-vous</1>.",
|
||||
"or-login": "Vous avez déjà un compte ? <1>Connectez-vous.<1/>",
|
||||
"password-no-match": "Mots de passe differents"
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user