aboutsummaryrefslogtreecommitdiffstats
path: root/apps/mobile/lib
diff options
context:
space:
mode:
authorMohamedBassem <me@mbassem.com>2024-03-13 21:43:44 +0000
committerMohamed Bassem <me@mbassem.com>2024-03-14 16:40:45 +0000
commit04572a8e5081b1e4871e273cde9dbaaa44c52fe0 (patch)
tree8e993acb732a50d1306d4d6953df96c165c57f57 /apps/mobile/lib
parent2df08ed08c065e8b91bc8df0266bd4bcbb062be4 (diff)
downloadkarakeep-04572a8e5081b1e4871e273cde9dbaaa44c52fe0.tar.zst
structure: Create apps dir and copy tooling dir from t3-turbo repo
Diffstat (limited to 'apps/mobile/lib')
-rw-r--r--apps/mobile/lib/last-shared-intent.ts15
-rw-r--r--apps/mobile/lib/providers.tsx54
-rw-r--r--apps/mobile/lib/session.ts20
-rw-r--r--apps/mobile/lib/settings.ts29
-rw-r--r--apps/mobile/lib/storage-state.ts51
-rw-r--r--apps/mobile/lib/trpc.ts4
-rw-r--r--apps/mobile/lib/utils.ts6
7 files changed, 179 insertions, 0 deletions
diff --git a/apps/mobile/lib/last-shared-intent.ts b/apps/mobile/lib/last-shared-intent.ts
new file mode 100644
index 00000000..951bcf74
--- /dev/null
+++ b/apps/mobile/lib/last-shared-intent.ts
@@ -0,0 +1,15 @@
+import { create } from "zustand";
+
+interface LastSharedIntent {
+ lastIntent: string;
+ setIntent: (intent: string) => void;
+ isPreviouslyShared: (intent: string) => boolean;
+}
+
+export const useLastSharedIntent = create<LastSharedIntent>((set, get) => ({
+ lastIntent: "",
+ setIntent: (intent: string) => set({ lastIntent: intent }),
+ isPreviouslyShared: (intent: string) => {
+ return get().lastIntent === intent;
+ },
+}));
diff --git a/apps/mobile/lib/providers.tsx b/apps/mobile/lib/providers.tsx
new file mode 100644
index 00000000..1717afb2
--- /dev/null
+++ b/apps/mobile/lib/providers.tsx
@@ -0,0 +1,54 @@
+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";
+
+import { ToastProvider } from "@/components/ui/Toast";
+
+function getTRPCClient(address: string) {
+ return api.createClient({
+ links: [
+ httpBatchLink({
+ url: `${address}/api/trpc`,
+ async headers() {
+ const settings = await getAppSettings();
+ return {
+ Authorization:
+ settings && settings.apiKey
+ ? `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}>
+ <ToastProvider>{children}</ToastProvider>
+ </QueryClientProvider>
+ </api.Provider>
+ );
+}
diff --git a/apps/mobile/lib/session.ts b/apps/mobile/lib/session.ts
new file mode 100644
index 00000000..e2ab245b
--- /dev/null
+++ b/apps/mobile/lib/session.ts
@@ -0,0 +1,20 @@
+import { useCallback, useMemo } from "react";
+
+import useAppSettings from "./settings";
+
+export function useSession() {
+ const { settings, isLoading, setSettings } = useAppSettings();
+ const isLoggedIn = useMemo(() => {
+ return isLoading ? undefined : !!settings.apiKey;
+ }, [isLoading, settings]);
+
+ const logout = useCallback(() => {
+ setSettings({ ...settings, apiKey: undefined });
+ }, [settings]);
+
+ return {
+ isLoggedIn,
+ isLoading,
+ logout,
+ };
+}
diff --git a/apps/mobile/lib/settings.ts b/apps/mobile/lib/settings.ts
new file mode 100644
index 00000000..21f40528
--- /dev/null
+++ b/apps/mobile/lib/settings.ts
@@ -0,0 +1,29 @@
+import * as SecureStore from "expo-secure-store";
+
+import { useStorageState } from "./storage-state";
+
+const SETTING_NAME = "settings";
+
+export type Settings = {
+ apiKey?: string;
+ address: string;
+};
+
+export default function useAppSettings() {
+ let [[isLoading, settings], setSettings] =
+ useStorageState<Settings>(SETTING_NAME);
+
+ settings ||= {
+ address: "https://demo.hoarder.app",
+ };
+
+ return { settings, setSettings, isLoading };
+}
+
+export async function getAppSettings() {
+ const val = await SecureStore.getItemAsync(SETTING_NAME);
+ if (!val) {
+ return null;
+ }
+ return JSON.parse(val) as Settings;
+}
diff --git a/apps/mobile/lib/storage-state.ts b/apps/mobile/lib/storage-state.ts
new file mode 100644
index 00000000..4988f0e0
--- /dev/null
+++ b/apps/mobile/lib/storage-state.ts
@@ -0,0 +1,51 @@
+import * as SecureStore from "expo-secure-store";
+import * as React from "react";
+
+type UseStateHook<T> = [[boolean, T | null], (value: T | null) => void];
+
+function useAsyncState<T>(
+ initialValue: [boolean, T | null] = [true, null],
+): UseStateHook<T> {
+ return React.useReducer(
+ (
+ state: [boolean, T | null],
+ action: T | null = null,
+ ): [boolean, T | null] => [false, action],
+ initialValue,
+ ) as UseStateHook<T>;
+}
+
+export async function setStorageItemAsync(key: string, value: string | null) {
+ if (value == null) {
+ await SecureStore.deleteItemAsync(key);
+ } else {
+ await SecureStore.setItemAsync(key, value);
+ }
+}
+
+export function useStorageState<T>(key: string): UseStateHook<T> {
+ // Public
+ const [state, setState] = useAsyncState<T>();
+
+ // Get
+ React.useEffect(() => {
+ SecureStore.getItemAsync(key).then((value) => {
+ if (!value) {
+ setState(null);
+ return null;
+ }
+ setState(JSON.parse(value));
+ });
+ }, [key]);
+
+ // Set
+ const setValue = React.useCallback(
+ (value: T | null) => {
+ setState(value);
+ setStorageItemAsync(key, JSON.stringify(value));
+ },
+ [key],
+ );
+
+ return [state, setValue];
+}
diff --git a/apps/mobile/lib/trpc.ts b/apps/mobile/lib/trpc.ts
new file mode 100644
index 00000000..6b428bd9
--- /dev/null
+++ b/apps/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/apps/mobile/lib/utils.ts b/apps/mobile/lib/utils.ts
new file mode 100644
index 00000000..365058ce
--- /dev/null
+++ b/apps/mobile/lib/utils.ts
@@ -0,0 +1,6 @@
+import { type ClassValue, clsx } from "clsx";
+import { twMerge } from "tailwind-merge";
+
+export function cn(...inputs: ClassValue[]) {
+ return twMerge(clsx(inputs));
+}