diff options
| author | MohamedBassem <me@mbassem.com> | 2024-03-13 21:43:44 +0000 |
|---|---|---|
| committer | Mohamed Bassem <me@mbassem.com> | 2024-03-14 16:40:45 +0000 |
| commit | 04572a8e5081b1e4871e273cde9dbaaa44c52fe0 (patch) | |
| tree | 8e993acb732a50d1306d4d6953df96c165c57f57 /apps/mobile/lib | |
| parent | 2df08ed08c065e8b91bc8df0266bd4bcbb062be4 (diff) | |
| download | karakeep-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.ts | 15 | ||||
| -rw-r--r-- | apps/mobile/lib/providers.tsx | 54 | ||||
| -rw-r--r-- | apps/mobile/lib/session.ts | 20 | ||||
| -rw-r--r-- | apps/mobile/lib/settings.ts | 29 | ||||
| -rw-r--r-- | apps/mobile/lib/storage-state.ts | 51 | ||||
| -rw-r--r-- | apps/mobile/lib/trpc.ts | 4 | ||||
| -rw-r--r-- | apps/mobile/lib/utils.ts | 6 |
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)); +} |
