mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-31 20:24:27 -04:00
Adding login errors
This commit is contained in:
parent
e5027cf00d
commit
b62b272492
@ -26,14 +26,14 @@ import { QueryClientProvider } from "@tanstack/react-query";
|
|||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import { Stack } from "expo-router";
|
import { Stack } from "expo-router";
|
||||||
import { getLocales } from "expo-localization";
|
import { getLocales } from "expo-localization";
|
||||||
import * as SplashScreen from "expo-splash-screen";
|
import { SplashScreen } from "expo-router";
|
||||||
import {
|
import {
|
||||||
useFonts,
|
useFonts,
|
||||||
Poppins_300Light,
|
Poppins_300Light,
|
||||||
Poppins_400Regular,
|
Poppins_400Regular,
|
||||||
Poppins_900Black,
|
Poppins_900Black,
|
||||||
} from "@expo-google-fonts/poppins";
|
} from "@expo-google-fonts/poppins";
|
||||||
import { useCallback, useLayoutEffect, useState } from "react";
|
import { useState } from "react";
|
||||||
import { useColorScheme } from "react-native";
|
import { useColorScheme } from "react-native";
|
||||||
import { initReactI18next } from "react-i18next";
|
import { initReactI18next } from "react-i18next";
|
||||||
import { useTheme } from "yoshiki/native";
|
import { useTheme } from "yoshiki/native";
|
||||||
@ -75,25 +75,12 @@ const ThemedStack = ({ onLayout }: { onLayout?: () => void }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
SplashScreen.preventAutoHideAsync();
|
|
||||||
|
|
||||||
export default function Root() {
|
export default function Root() {
|
||||||
const [queryClient] = useState(() => createQueryClient());
|
const [queryClient] = useState(() => createQueryClient());
|
||||||
const theme = useColorScheme();
|
const theme = useColorScheme();
|
||||||
const [fontsLoaded] = useFonts({ Poppins_300Light, Poppins_400Regular, Poppins_900Black });
|
const [fontsLoaded] = useFonts({ Poppins_300Light, Poppins_400Regular, Poppins_900Black });
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
if (!fontsLoaded) return <SplashScreen />;
|
||||||
// This does not seems to work on the global scope so why not.
|
|
||||||
SplashScreen.preventAutoHideAsync();
|
|
||||||
})
|
|
||||||
|
|
||||||
const onLayout = useCallback(async () => {
|
|
||||||
if (fontsLoaded) {
|
|
||||||
await SplashScreen.hideAsync();
|
|
||||||
}
|
|
||||||
}, [fontsLoaded]);
|
|
||||||
|
|
||||||
if (!fontsLoaded) return null;
|
|
||||||
return (
|
return (
|
||||||
<QueryClientProvider client={queryClient}>
|
<QueryClientProvider client={queryClient}>
|
||||||
<ThemeSelector
|
<ThemeSelector
|
||||||
@ -106,7 +93,7 @@ export default function Root() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<PortalProvider>
|
<PortalProvider>
|
||||||
<ThemedStack onLayout={onLayout} />
|
<ThemedStack />
|
||||||
</PortalProvider>
|
</PortalProvider>
|
||||||
</ThemeSelector>
|
</ThemeSelector>
|
||||||
</QueryClientProvider>
|
</QueryClientProvider>
|
||||||
|
@ -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 { QueryPage } from "@kyoo/models";
|
import { KyooErrors, kyooUrl, QueryPage } from "@kyoo/models";
|
||||||
import { Button, P, Input, ts, H1, A, IconButton } from "@kyoo/primitives";
|
import { Button, P, Input, ts, H1, A, IconButton } from "@kyoo/primitives";
|
||||||
import { ComponentProps, useState } from "react";
|
import { ComponentProps, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@ -65,6 +65,32 @@ const PasswordInput = (props: ComponentProps<typeof 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 = () => {
|
export const LoginPage: QueryPage = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { css } = useYoshiki();
|
const { css } = useYoshiki();
|
||||||
@ -78,6 +104,10 @@ export const LoginPage: QueryPage = () => {
|
|||||||
default: {},
|
default: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const [username, setUsername] = useState("");
|
||||||
|
const [password, setPassword] = useState("");
|
||||||
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ImageBackground
|
<ImageBackground
|
||||||
source={{ uri: src }}
|
source={{ uri: src }}
|
||||||
@ -110,12 +140,25 @@ export const LoginPage: QueryPage = () => {
|
|||||||
<Input variant="big" />
|
<Input variant="big" />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<P {...css({ paddingLeft: ts(1) })}>{t("login.email")}</P>
|
<P {...css({ paddingLeft: ts(1) })}>{t("login.username")}</P>
|
||||||
<Input autoComplete="email" variant="big" />
|
<Input
|
||||||
|
autoComplete="username"
|
||||||
|
variant="big"
|
||||||
|
onChangeText={(value) => setUsername(value)}
|
||||||
|
/>
|
||||||
<P {...css({ paddingLeft: ts(1) })}>{t("login.password")}</P>
|
<P {...css({ paddingLeft: ts(1) })}>{t("login.password")}</P>
|
||||||
<PasswordInput autoComplete="password" variant="big" />
|
<PasswordInput
|
||||||
|
autoComplete="password"
|
||||||
|
variant="big"
|
||||||
|
onChangeText={(value) => setPassword(value)}
|
||||||
|
/>
|
||||||
|
{error && <P {...css({ color: (theme) => theme.colors.red })}>{error}</P>}
|
||||||
<Button
|
<Button
|
||||||
text={t("login.login")}
|
text={t("login.login")}
|
||||||
|
onPress={async () => {
|
||||||
|
const { error } = await login(username, password);
|
||||||
|
setError(error);
|
||||||
|
}}
|
||||||
{...css({
|
{...css({
|
||||||
m: ts(1),
|
m: ts(1),
|
||||||
width: px(250),
|
width: px(250),
|
||||||
|
@ -55,6 +55,7 @@
|
|||||||
"register": "Register",
|
"register": "Register",
|
||||||
"server": "Server Address",
|
"server": "Server Address",
|
||||||
"email": "Email",
|
"email": "Email",
|
||||||
|
"username": "Username",
|
||||||
"password": "Password",
|
"password": "Password",
|
||||||
"or-register": "Don’t have an account? <1>Register</1>."
|
"or-register": "Don’t have an account? <1>Register</1>."
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,7 @@
|
|||||||
"register": "Créer un compte",
|
"register": "Créer un compte",
|
||||||
"server": "Addresse du serveur",
|
"server": "Addresse du serveur",
|
||||||
"email": "Email",
|
"email": "Email",
|
||||||
|
"username": "Username",
|
||||||
"password": "Mot de passe",
|
"password": "Mot de passe",
|
||||||
"or-register": "Vous n'avez pas de compte ? <1>Inscrivez-vous</1>."
|
"or-register": "Vous n'avez pas de compte ? <1>Inscrivez-vous</1>."
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user