aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMohamedBassem <me@mbassem.com>2024-03-11 11:05:36 +0000
committerMohamedBassem <me@mbassem.com>2024-03-11 11:05:36 +0000
commit999ed977a588b2c3b2055f18db4218d77882a1a1 (patch)
treebe926d82bcd495878956483ee7b21a172666566a
parente774f1ad01d4755651a82ed100c26587774c8ee0 (diff)
downloadkarakeep-999ed977a588b2c3b2055f18db4218d77882a1a1.tar.zst
mobile: Add support for app settings
-rw-r--r--packages/mobile/app.json3
-rw-r--r--packages/mobile/app/_layout.tsx12
-rw-r--r--packages/mobile/lib/providers.tsx47
-rw-r--r--packages/mobile/lib/settings.ts39
-rw-r--r--packages/mobile/lib/trpc.ts4
-rw-r--r--packages/mobile/package.json6
-rw-r--r--pnpm-lock.yaml14
7 files changed, 118 insertions, 7 deletions
diff --git a/packages/mobile/app.json b/packages/mobile/app.json
index 11455267..cfc42f72 100644
--- a/packages/mobile/app.json
+++ b/packages/mobile/app.json
@@ -38,7 +38,8 @@
"NSExtensionActivationSupportsImageWithMaxCount": 1,
"NSExtensionActivationSupportsMovieWithMaxCount": 1
}
- }]
+ }],
+ "expo-secure-store"
]
}
}
diff --git a/packages/mobile/app/_layout.tsx b/packages/mobile/app/_layout.tsx
index c578d07f..b37585e2 100644
--- a/packages/mobile/app/_layout.tsx
+++ b/packages/mobile/app/_layout.tsx
@@ -7,6 +7,8 @@ import { StatusBar } from "expo-status-bar";
import { useEffect } from "react";
import { View } from "react-native";
+import { Providers } from "@/lib/providers";
+
export default function RootLayout() {
const router = useRouter();
const { hasShareIntent, shareIntent, resetShareIntent } = useShareIntent({
@@ -23,9 +25,11 @@ export default function RootLayout() {
}
}, [hasShareIntent]);
return (
- <View className="h-full w-full bg-white">
- <Slot />
- <StatusBar style="auto" />
- </View>
+ <Providers>
+ <View className="h-full w-full bg-white">
+ <Slot />
+ <StatusBar style="auto" />
+ </View>
+ </Providers>
);
}
diff --git a/packages/mobile/lib/providers.tsx b/packages/mobile/lib/providers.tsx
new file mode 100644
index 00000000..d5638da8
--- /dev/null
+++ b/packages/mobile/lib/providers.tsx
@@ -0,0 +1,47 @@
+import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
+import { httpBatchLink } from "@trpc/client";
+import { useEffect, useState } from "react";
+import superjson from "superjson";
+
+import useAppSettings, { getAppSettings } from "./settings";
+import { api } from "./trpc";
+
+function getTRPCClient(address: string) {
+ return api.createClient({
+ links: [
+ httpBatchLink({
+ url: `${address}/api/trpc`,
+ async headers() {
+ const settings = await getAppSettings();
+ return {
+ Authorization: settings ? `Bearer ${settings.apiKey}` : undefined,
+ };
+ },
+ transformer: superjson,
+ }),
+ ],
+ });
+}
+
+export function Providers({ children }: { children: React.ReactNode }) {
+ const { settings } = useAppSettings();
+ const [queryClient] = useState(() => new QueryClient());
+
+ const [trpcClient, setTrpcClient] = useState<
+ ReturnType<typeof getTRPCClient>
+ >(getTRPCClient(settings.address));
+
+ useEffect(() => {
+ setTrpcClient(getTRPCClient(settings.address));
+ }, [settings.address]);
+
+ return (
+ <api.Provider
+ key={settings.address}
+ client={trpcClient}
+ queryClient={queryClient}
+ >
+ <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
+ </api.Provider>
+ );
+}
diff --git a/packages/mobile/lib/settings.ts b/packages/mobile/lib/settings.ts
new file mode 100644
index 00000000..85296cfa
--- /dev/null
+++ b/packages/mobile/lib/settings.ts
@@ -0,0 +1,39 @@
+import * as SecureStore from "expo-secure-store";
+import { useEffect, useState } from "react";
+
+const SETTING_NAME = "settings";
+
+export type Settings = {
+ apiKey: string;
+ address: string;
+};
+
+export default function useAppSettings() {
+ const [settings, setSettings] = useState<Settings>({
+ apiKey: "",
+ address: "",
+ });
+
+ useEffect(() => {
+ SecureStore.setItemAsync(SETTING_NAME, JSON.stringify(settings));
+ }, [settings]);
+
+ useEffect(() => {
+ SecureStore.getItemAsync(SETTING_NAME).then((val) => {
+ if (!val) {
+ return;
+ }
+ setSettings(JSON.parse(val));
+ });
+ }, []);
+
+ return { settings, setSettings };
+}
+
+export async function getAppSettings() {
+ const val = await SecureStore.getItemAsync(SETTING_NAME);
+ if (!val) {
+ return null;
+ }
+ return JSON.parse(val) as Settings;
+}
diff --git a/packages/mobile/lib/trpc.ts b/packages/mobile/lib/trpc.ts
new file mode 100644
index 00000000..6b428bd9
--- /dev/null
+++ b/packages/mobile/lib/trpc.ts
@@ -0,0 +1,4 @@
+import type { AppRouter } from "@hoarder/trpc/routers/_app";
+import { createTRPCReact } from "@trpc/react-query";
+
+export const api = createTRPCReact<AppRouter>();
diff --git a/packages/mobile/package.json b/packages/mobile/package.json
index 70054835..bbc0127c 100644
--- a/packages/mobile/package.json
+++ b/packages/mobile/package.json
@@ -4,12 +4,13 @@
"main": "expo-router/entry",
"scripts": {
"start": "expo start",
- "android": "expo start --android",
- "ios": "expo start --ios",
+ "android": "expo run:android",
+ "ios": "expo run:ios",
"web": "expo start --web",
"lint": "eslint ."
},
"dependencies": {
+ "@tanstack/react-query": "^5.24.8",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.0",
"expo": "~50.0.11",
@@ -18,6 +19,7 @@
"expo-dev-client": "^3.3.9",
"expo-linking": "~6.2.2",
"expo-router": "~3.4.8",
+ "expo-secure-store": "^12.8.1",
"expo-share-intent": "^1.0.1",
"expo-status-bar": "~1.11.1",
"lucide-react-native": "^0.354.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c275d6ae..670c936f 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -193,6 +193,9 @@ importers:
packages/mobile:
dependencies:
+ '@tanstack/react-query':
+ specifier: ^5.24.8
+ version: 5.24.8(react@18.2.0)
class-variance-authority:
specifier: ^0.7.0
version: 0.7.0
@@ -217,6 +220,9 @@ importers:
expo-router:
specifier: ~3.4.8
version: 3.4.8(expo-constants@15.4.5)(expo-linking@6.2.2)(expo-modules-autolinking@1.10.3)(expo-status-bar@1.11.1)(expo@50.0.11)(react-dom@18.2.0)(react-native-reanimated@3.8.0)(react-native-safe-area-context@4.8.2)(react-native-screens@3.29.0)(react-native@0.73.4)(react@18.2.0)
+ expo-secure-store:
+ specifier: ^12.8.1
+ version: 12.8.1(expo@50.0.11)
expo-share-intent:
specifier: ^1.0.1
version: 1.0.1(expo-constants@15.4.5)(expo-linking@6.2.2)(expo@50.0.11)(react-native@0.73.4)(react@18.2.0)
@@ -9313,6 +9319,14 @@ packages:
- supports-color
dev: false
+ /expo-secure-store@12.8.1(expo@50.0.11):
+ resolution: {integrity: sha512-Ju3jmkHby4w7rIzdYAt9kQyQ7HhHJ0qRaiQOInknhOLIltftHjEgF4I1UmzKc7P5RCfGNmVbEH729Pncp/sHXQ==}
+ peerDependencies:
+ expo: '*'
+ dependencies:
+ expo: 50.0.11(@babel/core@7.23.9)(@react-native/babel-preset@0.73.21)
+ dev: false
+
/expo-share-intent@1.0.1(expo-constants@15.4.5)(expo-linking@6.2.2)(expo@50.0.11)(react-native@0.73.4)(react@18.2.0):
resolution: {integrity: sha512-dMPoyEZlqKTS5FdQEytmnPHBXqHiXzzzzxuZ1p5S0AXJgZKeQ4mQspd6aLu7t+pt9T2l8yomtyUGBWagG3QNbw==}
peerDependencies: