diff --git a/apps/mobile/app/(app)/(tabs)/index.tsx b/apps/mobile/app/(app)/(tabs)/index.tsx index c2893286..ea6b6cc3 100644 --- a/apps/mobile/app/(app)/(tabs)/index.tsx +++ b/apps/mobile/app/(app)/(tabs)/index.tsx @@ -11,12 +11,10 @@ import { Text } from '@/components/ui/text' import { useColorScheme } from '@/hooks/useColorScheme' import { formatDateShort } from '@/lib/date' import { theme } from '@/lib/theme' -import { walletQueries } from '@/queries/wallet' import { useTransactionList } from '@/stores/transaction/hooks' import { dayjsExtended } from '@6pm/utilities' import { t } from '@lingui/macro' import { useLingui } from '@lingui/react' -import { useQueryClient } from '@tanstack/react-query' import { format } from 'date-fns/format' import { LinearGradient } from 'expo-linear-gradient' import { groupBy, mapValues, orderBy, sumBy } from 'lodash-es' @@ -29,7 +27,6 @@ export default function HomeScreen() { const { top, bottom } = useSafeAreaInsets() const { colorScheme } = useColorScheme() const [walletAccountId, setWalletAccountId] = useState() - const queryClient = useQueryClient() const [filter, setFilter] = useState(HomeFilter.All) const [view, setView] = useState(HomeView.SpentThisWeek) const [customTimeRange, setCustomTimeRange] = useState<{ @@ -51,18 +48,11 @@ export default function HomeScreen() { } }, [customTimeRange, filter]) - const { transactions, isLoading, isRefetching, refetch } = useTransactionList( - { - walletAccountId, - categoryId, - ...timeRange, - }, - ) - - const handleRefresh = () => { - refetch() - queryClient.invalidateQueries({ queryKey: walletQueries.list._def }) - } + const { transactions, isLoading } = useTransactionList({ + walletAccountId, + categoryId, + ...timeRange, + }) const handleSetFilter = (filter: HomeFilter) => { if (filter === HomeFilter.ByDay) { @@ -134,8 +124,8 @@ export default function HomeScreen() { } className="flex-1 bg-card" contentContainerStyle={{ paddingBottom: bottom + 32 }} - refreshing={isRefetching} - onRefresh={handleRefresh} + // refreshing={isRefetching} + // onRefresh={handleRefresh} sections={transactionsGroupByDate} keyExtractor={(item) => item.id} renderItem={({ item: transaction }) => ( diff --git a/apps/mobile/app/_layout.tsx b/apps/mobile/app/_layout.tsx index 3f9af1d6..c7a040ef 100644 --- a/apps/mobile/app/_layout.tsx +++ b/apps/mobile/app/_layout.tsx @@ -33,7 +33,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 { StoreProvider } from '@/stores/core/store-provider' import { BottomSheetModalProvider } from '@gorhom/bottom-sheet' import AsyncStorage from '@react-native-async-storage/async-storage' import NetInfo from '@react-native-community/netinfo' diff --git a/apps/mobile/stores/category/hooks.tsx b/apps/mobile/stores/category/hooks.tsx index dabe279d..6fccf557 100644 --- a/apps/mobile/stores/category/hooks.tsx +++ b/apps/mobile/stores/category/hooks.tsx @@ -10,17 +10,27 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import { keyBy, omit } from 'lodash-es' import { useMemo } from 'react' import { z } from 'zod' +import type { StoreHookQueryOptions } from '../core/stores' import { categoryQueries } from './queries' import { useCategoryStore } from './store' -export const useCategoryList = () => { +export const useCategoryListQueryOptions = ( + queryOptions?: StoreHookQueryOptions, +) => { const categories = useCategoryStore().categories const setCategoriesState = useCategoryStore((state) => state.setCategories) - - const query = useQuery({ + return { ...categoryQueries.all({ setCategoriesState }), initialData: categories?.length > 0 ? categories : undefined, - }) + ...queryOptions, + } +} + +export const useCategoryList = (queryOptions?: StoreHookQueryOptions) => { + const categories = useCategoryStore().categories + const queryOpts = useCategoryListQueryOptions(queryOptions) + + const query = useQuery(queryOpts) const { categoriesDict, incomeCategories, expenseCategories } = useMemo(() => { diff --git a/apps/mobile/stores/core/store-interval-update.tsx b/apps/mobile/stores/core/store-interval-update.tsx new file mode 100644 index 00000000..361a7d76 --- /dev/null +++ b/apps/mobile/stores/core/store-interval-update.tsx @@ -0,0 +1,30 @@ +import { useSuspenseQueries } from '@tanstack/react-query' +import type { FC } from 'react' +import { useCategoryListQueryOptions } from '../category/hooks' +import { useTransactionListQueryOptions } from '../transaction/hooks' +import type { StoreHookQueryOptions } from './stores' +import { STORE_SYNC_INTERVAL } from './stores.const' + +export type StoreIntervalUpdateProps = { + interval?: number +} + +export const StoreIntervalUpdate: FC = ({ + interval = STORE_SYNC_INTERVAL, +}) => { + const queryOptions: StoreHookQueryOptions = { + refetchInterval: interval, + refetchIntervalInBackground: true, + } + const categoryListQueryOptions = useCategoryListQueryOptions(queryOptions) + const transactionListQueryOptions = useTransactionListQueryOptions( + undefined, + queryOptions, + ) + + useSuspenseQueries({ + queries: [{ ...categoryListQueryOptions }, transactionListQueryOptions], + }) + + return null +} diff --git a/apps/mobile/stores/store-provider.tsx b/apps/mobile/stores/core/store-provider.tsx similarity index 92% rename from apps/mobile/stores/store-provider.tsx rename to apps/mobile/stores/core/store-provider.tsx index c21764ed..0a8e7737 100644 --- a/apps/mobile/stores/store-provider.tsx +++ b/apps/mobile/stores/core/store-provider.tsx @@ -9,6 +9,7 @@ import { useEffect, useState, } from 'react' +import { StoreIntervalUpdate } from './store-interval-update' import { useResetAllStores } from './use-reset-all-stores' export type StoreProviderProps = { @@ -60,5 +61,10 @@ export const StoreProvider: FC = ({ children }) => { return null } - return children + return ( + <> + + {children} + + ) } diff --git a/apps/mobile/stores/core/stores.const.ts b/apps/mobile/stores/core/stores.const.ts new file mode 100644 index 00000000..93d18096 --- /dev/null +++ b/apps/mobile/stores/core/stores.const.ts @@ -0,0 +1 @@ +export const STORE_SYNC_INTERVAL = 1000 * 5 // 5 seconds diff --git a/apps/mobile/stores/core/stores.d.ts b/apps/mobile/stores/core/stores.d.ts new file mode 100644 index 00000000..cb499abd --- /dev/null +++ b/apps/mobile/stores/core/stores.d.ts @@ -0,0 +1,4 @@ +export type StoreHookQueryOptions = { + refetchInterval?: number + refetchIntervalInBackground?: boolean +} diff --git a/apps/mobile/stores/use-reset-all-stores.tsx b/apps/mobile/stores/core/use-reset-all-stores.tsx similarity index 76% rename from apps/mobile/stores/use-reset-all-stores.tsx rename to apps/mobile/stores/core/use-reset-all-stores.tsx index 00f10763..55d095bc 100644 --- a/apps/mobile/stores/use-reset-all-stores.tsx +++ b/apps/mobile/stores/core/use-reset-all-stores.tsx @@ -1,7 +1,7 @@ import { useCallback } from 'react' -import { useBudgetStore } from './budget/store' -import { useCategoryStore } from './category/store' -import { useTransactionStore } from './transaction/store' +import { useBudgetStore } from '../budget/store' +import { useCategoryStore } from '../category/store' +import { useTransactionStore } from '../transaction/store' export const useResetAllStores = () => { const resetBudgetStore = useBudgetStore((state) => state._reset) diff --git a/apps/mobile/stores/transaction/hooks.tsx b/apps/mobile/stores/transaction/hooks.tsx index 7a42fbe3..31eda494 100644 --- a/apps/mobile/stores/transaction/hooks.tsx +++ b/apps/mobile/stores/transaction/hooks.tsx @@ -1,6 +1,7 @@ import { UNCATEGORIZED_ID } from '@/components/home/category-chart' import { getHonoClient } from '@/lib/client' import { useMeQuery } from '@/queries/auth' +import { dayjsExtended } from '@6pm/utilities' import { type TransactionFormValues, type TransactionPopulated, @@ -12,22 +13,28 @@ import { keyBy } from 'lodash-es' import { useMemo } from 'react' import { z } from 'zod' import { useCategoryList } from '../category/hooks' +import type { StoreHookQueryOptions } from '../core/stores' import { transactionQueries } from './queries' import { useTransactionStore } from './store' -export function useTransactionList({ - from, - to, - walletAccountId, - budgetId, - categoryId, -}: { - from: Date - to: Date - walletAccountId?: string - budgetId?: string - categoryId?: string -}) { +// TODO: Update params here +const DEFAULT_FROM = dayjsExtended() + .subtract(10, 'year') + .startOf('year') + .toDate() +const DEFAULT_TO = dayjsExtended().add(10, 'year').endOf('year').toDate() + +export const useTransactionListQueryOptions = ( + { + // FIXME: This should be dynamic @bkdev98 + from = DEFAULT_FROM, + to = DEFAULT_TO, + }: { + from?: Date + to?: Date + } = {}, + queryOptions?: StoreHookQueryOptions, +) => { const transactionsInRangeFromStore = useTransactionStore().transactions.filter( (t) => @@ -36,7 +43,7 @@ export function useTransactionList({ const updateTransactionsByRange = useTransactionStore( (state) => state.updateTransactionsByRange, ) - const query = useQuery({ + return { ...transactionQueries.list({ filters: { from, to }, updateTransactionsByRangeInStore: updateTransactionsByRange, @@ -45,7 +52,39 @@ export function useTransactionList({ transactionsInRangeFromStore.length > 0 ? transactionsInRangeFromStore : undefined, - }) + ...queryOptions, + } +} + +export function useTransactionList( + { + // FIXME: This should be dynamic @bkdev98 + from = DEFAULT_FROM, + to = DEFAULT_TO, + walletAccountId, + budgetId, + categoryId, + }: { + from?: Date + to?: Date + walletAccountId?: string + budgetId?: string + categoryId?: string + } = {}, + queryOptions?: StoreHookQueryOptions, +) { + const transactionsInRangeFromStore = + useTransactionStore().transactions.filter( + (t) => new Date(t.date) >= from && new Date(t.date) <= to, + ) + const queryOpts = useTransactionListQueryOptions( + { + from, + to, + }, + queryOptions, + ) + const query = useQuery(queryOpts) const { transactions, transactionDict, totalExpense, totalIncome } = useMemo(() => {