Skip to content

Commit

Permalink
WIP local storage alternative
Browse files Browse the repository at this point in the history
  • Loading branch information
aaronleopold committed Feb 12, 2024
1 parent b8338b9 commit 4b2d422
Show file tree
Hide file tree
Showing 9 changed files with 110 additions and 19 deletions.
1 change: 1 addition & 0 deletions apps/expo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"web": "expo start --web"
},
"dependencies": {
"@react-native-async-storage/async-storage": "1.21.0",
"@react-navigation/native": "^6.1.10",
"@react-navigation/native-stack": "^6.9.18",
"@stump/api": "*",
Expand Down
25 changes: 15 additions & 10 deletions apps/expo/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
import { NavigationContainer } from '@react-navigation/native'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
import { checkUrl, initializeApi, isAxiosError, isUrl } from '@stump/api'
import { useAppStore, useAuthQuery, useUserStore } from '@stump/client'
import { StumpClientContextProvider, useAppStore, useAuthQuery, useUserStore } from '@stump/client'
import * as SplashScreen from 'expo-splash-screen'
import { useEffect, useState } from 'react'
import { SafeAreaProvider } from 'react-native-safe-area-context'

import { AuthenticatedNavigator } from './screens/authenticated'
import LoginOrClaim from './screens/LoginOrClaim'
import ServerNotAccessible from './screens/ServerNotAccessible'

// TODO: Setup React Navigation: https://reactnavigation.org/docs/getting-started/
// 3 main route groups:
// - Cannot connect to server
// - Unathenticated
// - Authenticated

const Stack = createNativeStackNavigator()

export default function AppWrapper() {
return (
<StumpClientContextProvider>
<App />
</StumpClientContextProvider>
)
}

function App() {
const { baseUrl, setBaseUrl, setPlatform } = useAppStore((store) => ({
baseUrl: store.baseUrl,
setBaseUrl: store.setBaseUrl,
Expand Down Expand Up @@ -105,8 +108,10 @@ export default function AppWrapper() {
if (!isReady) return null

return (
<NavigationContainer>
<Stack.Navigator>{renderApp()}</Stack.Navigator>
</NavigationContainer>
<SafeAreaProvider>
<NavigationContainer>
<Stack.Navigator>{renderApp()}</Stack.Navigator>
</NavigationContainer>
</SafeAreaProvider>
)
}
21 changes: 15 additions & 6 deletions apps/expo/src/AppEntry.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
import { StumpClientContextProvider } from '@stump/client'
import { useFonts } from 'expo-font'
import * as SplashScreen from 'expo-splash-screen'
import { useEffect } from 'react'
import { lazy, Suspense, useEffect } from 'react'

import App from './App'
import { LocalStorage } from './localStorage'

// Prevent the splash screen from auto-hiding before asset loading is complete.
SplashScreen.preventAutoHideAsync()

// FIXME: this doesn't seem to be working still... Investigate
// Set global persist storage to AsyncStorage
// setGlobalPersistStorage(() => AsyncStorage)
globalThis.localStorage = new LocalStorage()

// Lazy load the app to prevent zustand from being initialized before the globalThis.localStorage is set
const LazyApp = lazy(async () => {
return await import('./App')
})

export function AppEntry() {
const [loaded, error] = useFonts({
SpaceMono: require('../assets/fonts/SpaceMono-Regular.ttf'),
Expand All @@ -24,8 +33,8 @@ export function AppEntry() {

// NOTE: react navigate advises against manual redirect? so for now we don't supply onRedirect...
return (
<StumpClientContextProvider>
<App />
</StumpClientContextProvider>
<Suspense fallback={null}>
<LazyApp />
</Suspense>
)
}
42 changes: 42 additions & 0 deletions apps/expo/src/localStorage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import AsyncStorage from '@react-native-async-storage/async-storage'

export class LocalStorage {
localStore: Record<string, string> = {}
length = 0

getItem(key: string) {
return this.localStore[key] ?? null
}

setItem(key: string, value: string) {
this.localStore[key] = value
this.length = Object.keys(this.localStore).length
AsyncStorage.setItem(key, value)
}

removeItem(key: string) {
delete this.localStore[key]
this.length = Object.keys(this.localStore).length
AsyncStorage.removeItem(key)
}

clear() {
this.localStore = {}
this.length = 0
AsyncStorage.clear()
}

async load() {
const keys = await AsyncStorage.getAllKeys()
const items = await AsyncStorage.multiGet(keys)
this.localStore = Object.fromEntries(items)
}

async sync() {
await AsyncStorage.multiSet(Object.entries(this.localStore))
}

key(index: number) {
return Object.keys(this.localStore)[index]
}
}
4 changes: 2 additions & 2 deletions apps/expo/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"compilerOptions": {
"skipLibCheck": true,
"jsx": "preserve",
"module": "esnext",
"paths": {
"@stump/api": ["../../packages/api/src/index.ts"],
"@stump/api/*": ["../../packages/api/src/*"],
Expand All @@ -11,6 +12,5 @@
"@stump/types": ["../../packages/types/index.ts"],
"@stump/types/*": ["../../packages/types/*"]
}
},
"module": "NodeNext"
}
}
2 changes: 2 additions & 0 deletions packages/client/src/stores/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { create } from 'zustand'
import { devtools, persist } from 'zustand/middleware'

import { Platform } from '../context'
import { globalPersistStorage } from '.'

type AppStore = {
platform: Platform
Expand Down Expand Up @@ -45,6 +46,7 @@ export const useAppStore = create<AppStore>()(
partialize(state) {
return { baseUrl: state.baseUrl, platform: state.platform }
},
storage: globalPersistStorage,
},
),
),
Expand Down
12 changes: 12 additions & 0 deletions packages/client/src/stores/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { createJSONStorage, StateStorage } from 'zustand/middleware'

export { useAppStore } from './app'
export { type EpubReaderPreferences, type EpubReaderStore, useEpubReader } from './epub'
export { useJobStore } from './job'
Expand All @@ -7,3 +9,13 @@ export interface StoreBase<T extends StoreBase<T>> {
reset(): void
set(changes: Partial<T>): void
}

export let globalPersistStorage = createJSONStorage(() => globalThis.localStorage)
// FIXME: this doesn't work :sob: but I like the idea... Try and get this to work instead of the hacky localStorage file I did
export const setGlobalPersistStorage = (
getStorage: () => StateStorage,
options?: JsonStorageOptions | undefined,
) => {
globalPersistStorage = createJSONStorage(getStorage, options)
}
type JsonStorageOptions = Parameters<typeof createJSONStorage>[1]
3 changes: 2 additions & 1 deletion packages/client/src/stores/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { produce } from 'immer'
import { create } from 'zustand'
import { devtools, persist } from 'zustand/middleware'

import { StoreBase } from '.'
import { globalPersistStorage, StoreBase } from '.'

// TODO: fix this store to use the new `createWithEqualityFn` method and optimize

Expand Down Expand Up @@ -68,6 +68,7 @@ export const useUserStore = create<UserStore>()(
userPreferences: store.userPreferences,
}
},
storage: globalPersistStorage,
},
),
),
Expand Down
19 changes: 19 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2944,6 +2944,13 @@
dependencies:
"@babel/runtime" "^7.13.10"

"@react-native-async-storage/async-storage@1.21.0":
version "1.21.0"
resolved "https://registry.yarnpkg.com/@react-native-async-storage/async-storage/-/async-storage-1.21.0.tgz#d7e370028e228ab84637016ceeb495878b7a44c8"
integrity sha512-JL0w36KuFHFCvnbOXRekqVAUplmOyT/OuCQkogo6X98MtpSaJOKEAeZnYO8JB0U/RIEixZaGI5px73YbRm/oag==
dependencies:
merge-options "^3.0.4"

"@react-native-community/cli-clean@12.3.2":
version "12.3.2"
resolved "https://registry.yarnpkg.com/@react-native-community/cli-clean/-/cli-clean-12.3.2.tgz#d4f1730c3d22d816b4d513d330d5f3896a3f5921"
Expand Down Expand Up @@ -9699,6 +9706,11 @@ is-plain-obj@^1.1.0:
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
integrity sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==

is-plain-obj@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287"
integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==

is-plain-obj@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-4.1.0.tgz#d65025edec3657ce032fd7db63c97883eaed71f0"
Expand Down Expand Up @@ -10981,6 +10993,13 @@ merge-descriptors@1.0.1:
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==

merge-options@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/merge-options/-/merge-options-3.0.4.tgz#84709c2aa2a4b24c1981f66c179fe5565cc6dbb7"
integrity sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==
dependencies:
is-plain-obj "^2.1.0"

merge-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
Expand Down

0 comments on commit 4b2d422

Please sign in to comment.