aboutsummaryrefslogtreecommitdiffstats
path: root/apps/mobile/app/signin.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'apps/mobile/app/signin.tsx')
-rw-r--r--apps/mobile/app/signin.tsx173
1 files changed, 64 insertions, 109 deletions
diff --git a/apps/mobile/app/signin.tsx b/apps/mobile/app/signin.tsx
index 6a554f89..94a57822 100644
--- a/apps/mobile/app/signin.tsx
+++ b/apps/mobile/app/signin.tsx
@@ -7,15 +7,17 @@ import {
View,
} from "react-native";
import { Redirect, useRouter } from "expo-router";
-import { CustomHeadersModal } from "@/components/CustomHeadersModal";
+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 { api } from "@/lib/trpc";
-import { Bug, Check, Edit3 } from "lucide-react-native";
+import { useMutation } from "@tanstack/react-query";
+import { Bug, Edit3 } from "lucide-react-native";
+
+import { useTRPC } from "@karakeep/shared-react/trpc";
enum LoginType {
Password,
@@ -25,15 +27,9 @@ enum LoginType {
export default function Signin() {
const { settings, setSettings } = useAppSettings();
const router = useRouter();
-
+ const api = useTRPC();
const [error, setError] = useState<string | undefined>();
const [loginType, setLoginType] = useState<LoginType>(LoginType.Password);
- const [isEditingServerAddress, setIsEditingServerAddress] = useState(false);
- const [tempServerAddress, setTempServerAddress] = useState(
- settings.address ?? "https://cloud.karakeep.app",
- );
- const [isCustomHeadersModalVisible, setIsCustomHeadersModalVisible] =
- useState(false);
const emailRef = useRef<string>("");
const passwordRef = useRef<string>("");
@@ -50,51 +46,58 @@ export default function Signin() {
};
const { mutate: login, isPending: userNamePasswordRequestIsPending } =
- api.apiKeys.exchange.useMutation({
- 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}`);
- }
- },
- });
+ 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 } =
- api.apiKeys.validate.useMutation({
- onSuccess: () => {
- const apiKey = apiKeyRef.current;
- setSettings({ ...settings, apiKey: apiKey });
- },
- onError: (e) => {
- if (e.data?.code === "UNAUTHORIZED") {
- setError("Invalid API key");
- } else {
- setError(`${e.message}`);
- }
- },
- });
+ 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 <Redirect href="dashboard" />;
}
- const handleSaveCustomHeaders = (headers: Record<string, string>) => {
- setSettings({ ...settings, customHeaders: headers });
+ 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 (!tempServerAddress) {
+ if (!settings.address) {
setError("Server address is required");
return;
}
if (
- !tempServerAddress.startsWith("http://") &&
- !tempServerAddress.startsWith("https://")
+ !settings.address.startsWith("http://") &&
+ !settings.address.startsWith("https://")
) {
setError("Server address must start with http:// or https://");
return;
@@ -137,71 +140,23 @@ export default function Signin() {
)}
<View className="gap-2">
<Text className="font-bold">Server Address</Text>
- {!isEditingServerAddress ? (
- <View className="flex-row items-center gap-2">
- <View className="flex-1 rounded-md border border-border bg-card px-3 py-2">
- <Text>{tempServerAddress}</Text>
- </View>
- <Button
- size="icon"
- variant="secondary"
- onPress={() => {
- setIsEditingServerAddress(true);
- }}
- >
- <TailwindResolver
- comp={(styles) => (
- <Edit3 size={16} color={styles?.color?.toString()} />
- )}
- className="color-foreground"
- />
- </Button>
+ <View className="flex-row items-center gap-2">
+ <View className="flex-1 rounded-md border border-border bg-card px-3 py-2">
+ <Text>{settings.address ?? "https://cloud.karakeep.app"}</Text>
</View>
- ) : (
- <View className="flex-row items-center gap-2">
- <Input
- className="flex-1"
- inputClasses="bg-card"
- placeholder="Server Address"
- value={tempServerAddress}
- autoCapitalize="none"
- keyboardType="url"
- onChangeText={setTempServerAddress}
- autoFocus
+ <Button
+ size="icon"
+ variant="secondary"
+ onPress={() => router.push("/server-address")}
+ >
+ <TailwindResolver
+ comp={(styles) => (
+ <Edit3 size={16} color={styles?.color?.toString()} />
+ )}
+ className="color-foreground"
/>
- <Button
- size="icon"
- variant="primary"
- onPress={() => {
- if (tempServerAddress.trim()) {
- setSettings({
- ...settings,
- address: tempServerAddress.trim().replace(/\/$/, ""),
- });
- }
- setIsEditingServerAddress(false);
- }}
- >
- <TailwindResolver
- comp={(styles) => (
- <Check size={16} color={styles?.color?.toString()} />
- )}
- className="text-white"
- />
- </Button>
- </View>
- )}
- <Pressable
- onPress={() => setIsCustomHeadersModalVisible(true)}
- className="mt-1"
- >
- <Text className="text-xs text-gray-500 underline">
- Configure Custom Headers{" "}
- {settings.customHeaders &&
- Object.keys(settings.customHeaders).length > 0 &&
- `(${Object.keys(settings.customHeaders).length})`}
- </Text>
- </Pressable>
+ </Button>
+ </View>
</View>
{loginType === LoginType.Password && (
<>
@@ -280,14 +235,14 @@ export default function Signin() {
: "Use password instead?"}
</Text>
</Pressable>
+ <Pressable onPress={onSignUp}>
+ <Text className="mt-4 text-center text-gray-500">
+ Don&apos;t have an account?{" "}
+ <Text className="text-foreground underline">Sign Up</Text>
+ </Text>
+ </Pressable>
</View>
</TouchableWithoutFeedback>
- <CustomHeadersModal
- visible={isCustomHeadersModalVisible}
- customHeaders={settings.customHeaders || {}}
- onClose={() => setIsCustomHeadersModalVisible(false)}
- onSave={handleSaveCustomHeaders}
- />
</KeyboardAvoidingView>
);
}