import { useRef, useState } from "react"; import { Keyboard, KeyboardAvoidingView, Pressable, TouchableWithoutFeedback, View, } from "react-native"; import { Redirect, useRouter } from "expo-router"; import * as WebBrowser from "expo-web-browser"; import Logo from "@/components/Logo"; import { TailwindResolver } from "@/components/TailwindResolver"; import { Button } from "@/components/ui/Button"; import { Input } from "@/components/ui/Input"; import { Text } from "@/components/ui/Text"; import useAppSettings from "@/lib/settings"; import { useMutation } from "@tanstack/react-query"; import { Bug, Edit3 } from "lucide-react-native"; import { useTRPC } from "@karakeep/shared-react/trpc"; enum LoginType { Password, ApiKey, } export default function Signin() { const { settings, setSettings } = useAppSettings(); const router = useRouter(); const api = useTRPC(); const [error, setError] = useState(); const [loginType, setLoginType] = useState(LoginType.Password); const emailRef = useRef(""); const passwordRef = useRef(""); const apiKeyRef = useRef(""); const toggleLoginType = () => { setLoginType((prev) => { if (prev === LoginType.Password) { return LoginType.ApiKey; } else { return LoginType.Password; } }); }; const { mutate: login, isPending: userNamePasswordRequestIsPending } = useMutation( api.apiKeys.exchange.mutationOptions({ onSuccess: (resp) => { setSettings({ ...settings, apiKey: resp.key, apiKeyId: resp.id }); }, onError: (e) => { if (e.data?.code === "UNAUTHORIZED") { setError("Wrong username or password"); } else { setError(`${e.message}`); } }, }), ); const { mutate: validateApiKey, isPending: apiKeyValueRequestIsPending } = useMutation( api.apiKeys.validate.mutationOptions({ onSuccess: () => { const apiKey = apiKeyRef.current; setSettings({ ...settings, apiKey: apiKey }); }, onError: (e) => { if (e.data?.code === "UNAUTHORIZED") { setError("Invalid API key"); } else { setError(`${e.message}`); } }, }), ); if (settings.apiKey) { return ; } const onSignUp = async () => { const serverAddress = settings.address ?? "https://cloud.karakeep.app"; const signupUrl = `${serverAddress}/signup?redirectUrl=${encodeURIComponent("karakeep://signin")}`; await WebBrowser.openAuthSessionAsync(signupUrl, "karakeep://signin"); }; const onSignin = () => { if (!settings.address) { setError("Server address is required"); return; } if ( !settings.address.startsWith("http://") && !settings.address.startsWith("https://") ) { setError("Server address must start with http:// or https://"); return; } if (loginType === LoginType.Password) { const email = emailRef.current; const password = passwordRef.current; const randStr = (Math.random() + 1).toString(36).substring(5); login({ email: email.trim(), password: password, keyName: `Mobile App: (${randStr})`, }); } else if (loginType === LoginType.ApiKey) { const apiKey = apiKeyRef.current; validateApiKey({ apiKey: apiKey }); } }; return ( ( )} /> {error && ( {error} )} Server Address {settings.address ?? "https://cloud.karakeep.app"} {loginType === LoginType.Password && ( <> Email (emailRef.current = text)} /> Password (passwordRef.current = text)} /> )} {loginType === LoginType.ApiKey && ( API Key (apiKeyRef.current = text)} /> )} {loginType === LoginType.Password ? "Use API key instead?" : "Use password instead?"} Don't have an account?{" "} Sign Up ); }