From 04572a8e5081b1e4871e273cde9dbaaa44c52fe0 Mon Sep 17 00:00:00 2001 From: MohamedBassem Date: Wed, 13 Mar 2024 21:43:44 +0000 Subject: structure: Create apps dir and copy tooling dir from t3-turbo repo --- apps/mobile/lib/last-shared-intent.ts | 15 ++++++++++ apps/mobile/lib/providers.tsx | 54 +++++++++++++++++++++++++++++++++++ apps/mobile/lib/session.ts | 20 +++++++++++++ apps/mobile/lib/settings.ts | 29 +++++++++++++++++++ apps/mobile/lib/storage-state.ts | 51 +++++++++++++++++++++++++++++++++ apps/mobile/lib/trpc.ts | 4 +++ apps/mobile/lib/utils.ts | 6 ++++ 7 files changed, 179 insertions(+) create mode 100644 apps/mobile/lib/last-shared-intent.ts create mode 100644 apps/mobile/lib/providers.tsx create mode 100644 apps/mobile/lib/session.ts create mode 100644 apps/mobile/lib/settings.ts create mode 100644 apps/mobile/lib/storage-state.ts create mode 100644 apps/mobile/lib/trpc.ts create mode 100644 apps/mobile/lib/utils.ts (limited to 'apps/mobile/lib') 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((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 + >(getTRPCClient(settings.address)); + + useEffect(() => { + setTrpcClient(getTRPCClient(settings.address)); + }, [settings.address]); + + return ( + + + {children} + + + ); +} 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(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 = [[boolean, T | null], (value: T | null) => void]; + +function useAsyncState( + initialValue: [boolean, T | null] = [true, null], +): UseStateHook { + return React.useReducer( + ( + state: [boolean, T | null], + action: T | null = null, + ): [boolean, T | null] => [false, action], + initialValue, + ) as UseStateHook; +} + +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(key: string): UseStateHook { + // Public + const [state, setState] = useAsyncState(); + + // 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(); 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)); +} -- cgit v1.2.3-70-g09d2