Skip to content

Commit

Permalink
feat(mobile): clear all cache when user change (#198)
Browse files Browse the repository at this point in the history
  • Loading branch information
duongdev committed Aug 3, 2024
1 parent 04c0b3f commit ef306bd
Show file tree
Hide file tree
Showing 11 changed files with 137 additions and 31 deletions.
5 changes: 0 additions & 5 deletions apps/mobile/app/(app)/(tabs)/settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ import { useLocale } from '@/locales/provider'
import { useAuth } from '@clerk/clerk-expo'
import { t } from '@lingui/macro'
import { useLingui } from '@lingui/react'
import AsyncStorage from '@react-native-async-storage/async-storage'
import { useQueryClient } from '@tanstack/react-query'
import { LinearGradient } from 'expo-linear-gradient'
import { Link } from 'expo-router'
import {
Expand All @@ -40,7 +38,6 @@ export default function SettingsScreen() {
const { i18n } = useLingui()
const { language } = useLocale()
const { colorScheme } = useColorScheme()
const queryClient = useQueryClient()

return (
<View className="bg-card">
Expand Down Expand Up @@ -189,8 +186,6 @@ export default function SettingsScreen() {
text: t(i18n)`Sign out`,
style: 'destructive',
onPress: async () => {
await AsyncStorage.clear()
queryClient.clear()
await signOut()
},
},
Expand Down
47 changes: 25 additions & 22 deletions apps/mobile/app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { useWarmUpBrowser } from '@/hooks/use-warm-up-browser'
import { useColorScheme } from '@/hooks/useColorScheme'
import { queryClient } from '@/lib/client'
import { LocaleProvider } from '@/locales/provider'
import { StoreProvider } from '@/stores/store-provider'
import { BottomSheetModalProvider } from '@gorhom/bottom-sheet'
import AsyncStorage from '@react-native-async-storage/async-storage'
import NetInfo from '@react-native-community/netinfo'
Expand Down Expand Up @@ -147,28 +148,30 @@ function RootLayout() {
client={queryClient}
persistOptions={{ persister: asyncStoragePersister }}
>
<LocaleProvider>
<ThemeProvider
value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}
>
<SafeAreaProvider>
<GestureHandlerRootView>
<BottomSheetModalProvider>
<Stack screenOptions={{ headerShown: false }}>
<Stack.Screen
name="(aux)"
options={{
presentation: 'modal',
}}
/>
</Stack>
<ToastRoot />
<PortalHost />
</BottomSheetModalProvider>
</GestureHandlerRootView>
</SafeAreaProvider>
</ThemeProvider>
</LocaleProvider>
<StoreProvider>
<LocaleProvider>
<ThemeProvider
value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}
>
<SafeAreaProvider>
<GestureHandlerRootView>
<BottomSheetModalProvider>
<Stack screenOptions={{ headerShown: false }}>
<Stack.Screen
name="(aux)"
options={{
presentation: 'modal',
}}
/>
</Stack>
<ToastRoot />
<PortalHost />
</BottomSheetModalProvider>
</GestureHandlerRootView>
</SafeAreaProvider>
</ThemeProvider>
</LocaleProvider>
</StoreProvider>
</PersistQueryClientProvider>
</ClerkLoaded>
</ClerkProvider>
Expand Down
14 changes: 14 additions & 0 deletions apps/mobile/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import AsyncStorage from '@react-native-async-storage/async-storage'
import { type ClassValue, clsx } from 'clsx'
import { Platform } from 'react-native'
import { twMerge } from 'tailwind-merge'

export function cn(...inputs: ClassValue[]) {
Expand All @@ -8,3 +10,15 @@ export function cn(...inputs: ClassValue[]) {
export async function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms))
}

export async function clearAsyncStorage() {
const asyncStorageKeys = await AsyncStorage.getAllKeys()
if (asyncStorageKeys.length > 0) {
if (Platform.OS === 'android') {
await AsyncStorage.clear()
}
if (Platform.OS === 'ios') {
await AsyncStorage.multiRemove(asyncStorageKeys)
}
}
}
2 changes: 1 addition & 1 deletion apps/mobile/stores/budget/hooks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export const useBudgetList = () => {

const query = useQuery({
...budgetQueries.all({ setBudgetsState }),
initialData: budgets,
initialData: budgets.length > 0 ? budgets : undefined,
})

const {
Expand Down
3 changes: 3 additions & 0 deletions apps/mobile/stores/budget/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export type BudgetItem = Budget & {

interface BudgetStore {
budgets: BudgetItem[]
_reset: () => void
setBudgets: (budgets: BudgetItem[]) => void
updateBudget: (budget: BudgetItem) => void
}
Expand All @@ -17,6 +18,8 @@ export const useBudgetStore = create<BudgetStore>()(
persist(
(set) => ({
budgets: [],
// biome-ignore lint/style/useNamingConvention: <explanation>
_reset: () => set({ budgets: [] }),
setBudgets: (budgets: BudgetItem[]) => set({ budgets }),
updateBudget: (budget: BudgetItem) =>
set((state) => {
Expand Down
2 changes: 1 addition & 1 deletion apps/mobile/stores/category/hooks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const useCategoryList = () => {

const query = useQuery({
...categoryQueries.all({ setCategoriesState }),
initialData: categories,
initialData: categories?.length > 0 ? categories : undefined,
})

const { categoriesDict, incomeCategories, expenseCategories } =
Expand Down
3 changes: 3 additions & 0 deletions apps/mobile/stores/category/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { createJSONStorage, persist } from 'zustand/middleware'

interface CategoryStore {
categories: Category[]
_reset: () => void
setCategories: (categories: Category[]) => void
updateCategory: (category: Category) => void
}
Expand All @@ -18,6 +19,8 @@ export const useCategoryStore = create<CategoryStore>()(
persist(
(set) => ({
categories: [],
// biome-ignore lint/style/useNamingConvention: <explanation>
_reset: () => set({ categories: [] }),
setCategories: (categories: Category[]) =>
set({ categories: normalizeCategories(categories) }),
updateCategory: (category: Category) =>
Expand Down
64 changes: 64 additions & 0 deletions apps/mobile/stores/store-provider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { clearAsyncStorage } from '@/lib/utils'
import { useAuth } from '@clerk/clerk-expo'
import { useAsyncStorage } from '@react-native-async-storage/async-storage'
import { useQueryClient } from '@tanstack/react-query'
import {
type FC,
type ReactNode,
useCallback,
useEffect,
useState,
} from 'react'
import { useResetAllStores } from './use-reset-all-stores'

export type StoreProviderProps = {
children: ReactNode
}

export const StoreProvider: FC<StoreProviderProps> = ({ children }) => {
const [isReady, setIsReady] = useState(false)
const { userId } = useAuth()
const queryClient = useQueryClient()
const { getItem, setItem, removeItem } = useAsyncStorage('user-id')
const resetAllStores = useResetAllStores()

const handleUserChange = useCallback(async () => {
const storedUserId = await getItem()

if (storedUserId === userId) {
return
}

// biome-ignore lint/suspicious/noConsoleLog: <explanation>
console.log('User changed, clearing storage', userId)

await clearAsyncStorage()
queryClient.clear()
queryClient.invalidateQueries()
resetAllStores()

// biome-ignore lint/suspicious/noConsoleLog: <explanation>
console.log('Storage cleared')

if (userId) {
await setItem(userId)
} else {
await removeItem()
}
}, [getItem, queryClient, userId, removeItem, setItem, resetAllStores])

// Clear the async storage & queryClient when the user changes
useEffect(() => {
handleUserChange().catch((error) => {
console.error('Failed to clear storage', error)
})

setIsReady(true)
}, [handleUserChange])

if (!isReady) {
return null
}

return children
}
7 changes: 5 additions & 2 deletions apps/mobile/stores/transaction/hooks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ export function useTransactionList({
filters: { from, to },
updateTransactionsByRangeInStore: updateTransactionsByRange,
}),
initialData: transactionsInRangeFromStore,
initialData:
transactionsInRangeFromStore.length > 0
? transactionsInRangeFromStore
: undefined,
})

const { transactions, transactionDict, totalExpense, totalIncome } =
Expand Down Expand Up @@ -98,7 +101,7 @@ export function useTransaction(transactionId: string) {
updateTransactionInStore: updateTransaction,
removeTransactionInStore: removeTransaction,
}),
initialData: transaction,
initialData: transaction || undefined,
})

return { ...query, transaction }
Expand Down
3 changes: 3 additions & 0 deletions apps/mobile/stores/transaction/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ type Transaction = TransactionPopulated

export interface TransactionStore {
transactions: Transaction[]
_reset: () => void
setTransactions: (transactions: Transaction[]) => void
addTransactions: (transactions: Transaction[]) => void
updateTransactionsByRange: (args: {
Expand All @@ -31,6 +32,8 @@ export const useTransactionStore = create<TransactionStore>()(
persist(
(set) => ({
transactions: [],
// biome-ignore lint/style/useNamingConvention: <explanation>
_reset: () => set({ transactions: [] }),
setTransactions: (transactions) => {
set({ transactions: normalizeTransactions(transactions) })
},
Expand Down
18 changes: 18 additions & 0 deletions apps/mobile/stores/use-reset-all-stores.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useCallback } from 'react'
import { useBudgetStore } from './budget/store'
import { useCategoryStore } from './category/store'
import { useTransactionStore } from './transaction/store'

export const useResetAllStores = () => {
const resetBudgetStore = useBudgetStore((state) => state._reset)
const resetCategoryStore = useCategoryStore((state) => state._reset)
const resetTransactionStore = useTransactionStore((state) => state._reset)

const resetAllStores = useCallback(() => {
resetBudgetStore()
resetCategoryStore()
resetTransactionStore()
}, [resetBudgetStore, resetCategoryStore, resetTransactionStore])

return resetAllStores
}

0 comments on commit ef306bd

Please sign in to comment.