mirror of
https://github.com/linkwarden/linkwarden.git
synced 2026-03-03 03:47:02 +00:00
198 lines
6.8 KiB
TypeScript
198 lines
6.8 KiB
TypeScript
import { Button } from "@/components/ui/Button";
|
|
import Input from "@/components/ui/Input";
|
|
import { rawTheme, ThemeName } from "@/lib/colors";
|
|
import useAuthStore from "@/store/auth";
|
|
import { Redirect } from "expo-router";
|
|
import { useColorScheme } from "nativewind";
|
|
import { useEffect, useState } from "react";
|
|
import { View, Text, Dimensions, TouchableOpacity, Image } from "react-native";
|
|
import { SheetManager } from "react-native-actions-sheet";
|
|
import Svg, { Path } from "react-native-svg";
|
|
import {
|
|
KeyboardStickyView,
|
|
KeyboardToolbar,
|
|
} from "react-native-keyboard-controller";
|
|
import { SafeAreaView } from "react-native-safe-area-context";
|
|
|
|
export default function HomeScreen() {
|
|
const { auth, signIn } = useAuthStore();
|
|
const { colorScheme } = useColorScheme();
|
|
const [method, setMethod] = useState<"password" | "token">("password");
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
|
|
const [form, setForm] = useState({
|
|
user: "",
|
|
password: "",
|
|
token: "",
|
|
instance: auth.instance || "https://cloud.linkwarden.app",
|
|
});
|
|
|
|
const [showInstanceField, setShowInstanceField] = useState(
|
|
form.instance !== "https://cloud.linkwarden.app"
|
|
);
|
|
|
|
useEffect(() => {
|
|
setForm((prev) => ({
|
|
...prev,
|
|
instance: auth.instance || "https://cloud.linkwarden.app",
|
|
}));
|
|
}, [auth.instance]);
|
|
|
|
useEffect(() => {
|
|
setShowInstanceField(form.instance !== "https://cloud.linkwarden.app");
|
|
}, [form.instance]);
|
|
|
|
useEffect(() => {
|
|
setForm((prev) => ({
|
|
...prev,
|
|
token: "",
|
|
user: "",
|
|
password: "",
|
|
}));
|
|
}, [method]);
|
|
|
|
if (auth.status === "authenticated") {
|
|
return <Redirect href="/dashboard" />;
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<KeyboardStickyView className="flex-col justify-end h-full bg-base-100 relative">
|
|
<View className="flex-col justify-end h-full bg-primary relative">
|
|
<View className="my-auto">
|
|
<Image
|
|
source={require("@/assets/images/linkwarden.png")}
|
|
className="w-[120px] h-[120px] mx-auto"
|
|
/>
|
|
</View>
|
|
<Text className="text-base-100 text-7xl font-bold ml-8">Login</Text>
|
|
<View>
|
|
<Text
|
|
className="text-base-100 text-2xl mx-8 mt-3"
|
|
numberOfLines={1}
|
|
>
|
|
Login to{" "}
|
|
{form.instance === "https://cloud.linkwarden.app"
|
|
? "cloud.linkwarden.app"
|
|
: form.instance}
|
|
</Text>
|
|
<TouchableOpacity
|
|
onPress={() => {
|
|
if (showInstanceField) {
|
|
setForm({
|
|
...form,
|
|
instance: "https://cloud.linkwarden.app",
|
|
});
|
|
}
|
|
setShowInstanceField(!showInstanceField);
|
|
}}
|
|
className="mx-8 mt-1 self-start"
|
|
>
|
|
<Text className="text-neutral-content text-sm">
|
|
{!showInstanceField ? "Change server" : "Use official server"}
|
|
</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
<Svg
|
|
viewBox="0 0 1440 320"
|
|
width={Dimensions.get("screen").width}
|
|
height={Dimensions.get("screen").width * (320 / 1440) + 2}
|
|
>
|
|
<Path
|
|
fill={rawTheme[colorScheme as ThemeName]["base-100"]}
|
|
fill-opacity="1"
|
|
d="M0,256L48,234.7C96,213,192,171,288,176C384,181,480,235,576,266.7C672,299,768,309,864,277.3C960,245,1056,171,1152,122.7C1248,75,1344,53,1392,42.7L1440,32L1440,320L1392,320C1344,320,1248,320,1152,320C1056,320,960,320,864,320C768,320,672,320,576,320C480,320,384,320,288,320C192,320,96,320,48,320L0,320Z"
|
|
/>
|
|
</Svg>
|
|
<SafeAreaView
|
|
edges={["bottom"]}
|
|
className="flex-col justify-end h-auto duration-100 pt-10 bg-base-100 -mt-2 pb-10 gap-4 w-full px-4"
|
|
>
|
|
{showInstanceField && (
|
|
<Input
|
|
className="w-full text-xl p-3 leading-tight h-12"
|
|
textAlignVertical="center"
|
|
placeholder="Instance URL"
|
|
selectTextOnFocus={false}
|
|
value={form.instance}
|
|
onChangeText={(text) => setForm({ ...form, instance: text })}
|
|
/>
|
|
)}
|
|
{method === "password" ? (
|
|
<>
|
|
<Input
|
|
className="w-full text-xl p-3 leading-tight h-12"
|
|
textAlignVertical="center"
|
|
placeholder="Email or Username"
|
|
value={form.user}
|
|
onChangeText={(text) => setForm({ ...form, user: text })}
|
|
/>
|
|
<Input
|
|
className="w-full text-xl p-3 leading-tight h-12"
|
|
textAlignVertical="center"
|
|
placeholder="Password"
|
|
secureTextEntry
|
|
value={form.password}
|
|
onChangeText={(text) => setForm({ ...form, password: text })}
|
|
/>
|
|
</>
|
|
) : (
|
|
<Input
|
|
className="w-full text-xl p-3 leading-tight h-12"
|
|
textAlignVertical="center"
|
|
placeholder="Access Token"
|
|
secureTextEntry
|
|
value={form.token}
|
|
onChangeText={(text) => setForm({ ...form, token: text })}
|
|
/>
|
|
)}
|
|
|
|
<TouchableOpacity
|
|
onPress={() =>
|
|
setMethod(method === "password" ? "token" : "password")
|
|
}
|
|
className="w-fit mx-auto"
|
|
>
|
|
<Text className="text-primary w-fit text-center">
|
|
{method === "password"
|
|
? "Login with Access Token"
|
|
: "Login with Username/Password"}
|
|
</Text>
|
|
</TouchableOpacity>
|
|
|
|
<Button
|
|
variant="accent"
|
|
size="lg"
|
|
isLoading={isLoading}
|
|
onPress={async () => {
|
|
if (
|
|
((form.user && form.password) || form.token) &&
|
|
form.instance
|
|
) {
|
|
setIsLoading(true);
|
|
await signIn(
|
|
form.user,
|
|
form.password,
|
|
form.instance,
|
|
form.token
|
|
);
|
|
setIsLoading(false);
|
|
}
|
|
}}
|
|
>
|
|
<Text className="text-white text-xl">Login</Text>
|
|
</Button>
|
|
<TouchableOpacity
|
|
className="w-fit mx-auto"
|
|
onPress={() => SheetManager.show("support-sheet")}
|
|
>
|
|
<Text className="text-neutral text-center w-fit">Need help?</Text>
|
|
</TouchableOpacity>
|
|
</SafeAreaView>
|
|
</View>
|
|
</KeyboardStickyView>
|
|
<KeyboardToolbar />
|
|
</>
|
|
);
|
|
}
|