This commit is contained in:
shafi54 2026-08-13 00:16:27 +05:30
parent 1139bf0f46
commit 360289d3c6
2 changed files with 43 additions and 93 deletions

View file

@ -12,7 +12,7 @@ export default function HomeLayout() {
}} }}
> >
<Stack.Screen <Stack.Screen
name="product-detail/[id]" name="product-detail"
options={{ options={{
headerShown: false, headerShown: false,
title: "Product Details", title: "Product Details",

View file

@ -6,82 +6,52 @@ import { AllProductsApiType, StoresApiType, SlotsApiType, EssentialConstsApiType
import { CACHE_FILENAMES } from "@packages/shared"; import { CACHE_FILENAMES } from "@packages/shared";
import { StorageServiceCasual } from 'common-ui'; import { StorageServiceCasual } from 'common-ui';
// Local useGetEssentialConsts hook // The only persisted payload: the small essential-consts config object
// (assetsDomain, cache versions, etc.). The big data payloads (products,
// stores, slots, availability, banners) are fetched fresh each session and
// kept in memory by react-query — they are NOT written to storage.
const ESSENTIAL_CONSTS_KEY = 'essential_consts'
export const useGetEssentialConsts = () => { export const useGetEssentialConsts = () => {
const query = trpc.common.essentialConsts.useQuery(undefined, { const [initialData, setInitialData] = useState<EssentialConstsApiType | undefined>(undefined)
refetchInterval: 60000,
})
return { ...query, refetch: query.refetch }
}
// ---------------------------------------------------------------------------
// Persisted cache helpers — store fetched JSON keyed by its versioned URL.
// Only refetch + repersist when the version (URL) changes.
// ---------------------------------------------------------------------------
interface PersistedCache<T> {
version: string
data: T
}
const CACHE_STORAGE_KEYS = {
products: 'cache_products',
stores: 'cache_stores',
slots: 'cache_slots',
banners: 'cache_banners',
availability: 'cache_availability',
storeProducts: (storeId: number) => `cache_store_${storeId}`,
} as const
async function readPersistedCache<T>(key: string): Promise<PersistedCache<T> | null> {
const raw = await StorageServiceCasual.getItem(key)
if (!raw) return null
try {
return JSON.parse(raw) as PersistedCache<T>
} catch {
return null
}
}
async function writePersistedCache<T>(key: string, version: string, data: T): Promise<void> {
await StorageServiceCasual.setItem(key, JSON.stringify({ version, data }))
}
/**
* Loads the persisted cache for `storageKey` and reports whether its version
* matches the current `version`. Returns { initialData, isReady }.
* - version matches serve persisted data, no network refetch needed.
* - version differs signal to refetch (caller's query fetches + repersists).
*/
function usePersistedCache<T>(storageKey: string, version: string | null) {
const [initialData, setInitialData] = useState<T | undefined>(undefined)
const [isReady, setIsReady] = useState(false) const [isReady, setIsReady] = useState(false)
// Load the last persisted response so config is available immediately.
useEffect(() => { useEffect(() => {
let cancelled = false let cancelled = false
setIsReady(false) StorageServiceCasual.getItem(ESSENTIAL_CONSTS_KEY).then((raw) => {
setInitialData(undefined)
if (!version) {
setIsReady(true)
return
}
readPersistedCache<T>(storageKey).then((persisted) => {
if (cancelled) return if (cancelled) return
if (persisted && persisted.version === version) { if (raw) {
setInitialData(persisted.data) try {
setInitialData(JSON.parse(raw))
} catch {
// ignore corrupt cache
}
} }
setIsReady(true) setIsReady(true)
}) })
return () => { cancelled = true } return () => { cancelled = true }
}, [storageKey, version]) }, [])
return { initialData, isReady } const query = trpc.common.essentialConsts.useQuery(undefined, {
refetchInterval: 60000,
enabled: isReady,
placeholderData: initialData,
})
// Persist the latest response.
useEffect(() => {
if (query.data) {
StorageServiceCasual.setItem(ESSENTIAL_CONSTS_KEY, JSON.stringify(query.data))
}
}, [query.data])
return { ...query, refetch: query.refetch }
} }
type ProductsResponse = AllProductsApiType; type ProductsResponse = AllProductsApiType;
type StoresResponse = StoresApiType; type StoresResponse = StoresApiType;
type SlotsResponse = SlotsApiType; type SlotsResponse = SlotsApiType;
type EssentialConstsResponse = EssentialConstsApiType;
type BannersResponse = BannersApiType; type BannersResponse = BannersApiType;
type StoreWithProductsResponse = StoreWithProductsApiType; type StoreWithProductsResponse = StoreWithProductsApiType;
type AvailabilityResponse = AvailabilityApiType; type AvailabilityResponse = AvailabilityApiType;
@ -142,7 +112,6 @@ export function useAllProducts() {
const cacheUrl = useCacheUrl(CACHE_FILENAMES.products) const cacheUrl = useCacheUrl(CACHE_FILENAMES.products)
const { data: availabilityData } = useAvailability() const { data: availabilityData } = useAvailability()
const version = cacheUrl ?? '' const version = cacheUrl ?? ''
const { initialData, isReady } = usePersistedCache<ProductsResponse>(CACHE_STORAGE_KEYS.products, version)
const productsQuery = useQuery<ProductsResponse>({ const productsQuery = useQuery<ProductsResponse>({
queryKey: ['all-products', version], queryKey: ['all-products', version],
@ -151,12 +120,10 @@ export function useAllProducts() {
throw new Error('Cache URL not available') throw new Error('Cache URL not available')
} }
const response = await axios.get<ProductsResponse>(cacheUrl) const response = await axios.get<ProductsResponse>(cacheUrl)
await writePersistedCache(CACHE_STORAGE_KEYS.products, version, response.data)
return response.data return response.data
}, },
staleTime: 60000, // 1 minute staleTime: 60000, // 1 minute
enabled: !!cacheUrl && isReady, enabled: !!cacheUrl,
placeholderData: initialData,
}) })
const mergedProducts = React.useMemo(() => { const mergedProducts = React.useMemo(() => {
@ -197,7 +164,6 @@ export function useAllProducts() {
export function useAvailability() { export function useAvailability() {
const cacheUrl = useAvailabilityCacheUrl() const cacheUrl = useAvailabilityCacheUrl()
const version = cacheUrl ?? '' const version = cacheUrl ?? ''
const { initialData, isReady } = usePersistedCache<AvailabilityResponse>(CACHE_STORAGE_KEYS.availability, version)
return useQuery<AvailabilityResponse>({ return useQuery<AvailabilityResponse>({
queryKey: ['availability', version], queryKey: ['availability', version],
@ -206,19 +172,16 @@ export function useAvailability() {
throw new Error('Cache URL not available') throw new Error('Cache URL not available')
} }
const response = await axios.get<AvailabilityResponse>(cacheUrl) const response = await axios.get<AvailabilityResponse>(cacheUrl)
await writePersistedCache(CACHE_STORAGE_KEYS.availability, version, response.data)
return response.data return response.data
}, },
staleTime: 60000, // 1 minute staleTime: 60000, // 1 minute
enabled: !!cacheUrl && isReady, enabled: !!cacheUrl,
placeholderData: initialData,
}) })
} }
export function useStores() { export function useStores() {
const cacheUrl = useCacheUrl(CACHE_FILENAMES.stores) const cacheUrl = useCacheUrl(CACHE_FILENAMES.stores)
const version = cacheUrl ?? '' const version = cacheUrl ?? ''
const { initialData, isReady } = usePersistedCache<StoresResponse>(CACHE_STORAGE_KEYS.stores, version)
return useQuery<StoresResponse>({ return useQuery<StoresResponse>({
queryKey: ['stores', version], queryKey: ['stores', version],
@ -227,19 +190,16 @@ export function useStores() {
throw new Error('Cache URL not available') throw new Error('Cache URL not available')
} }
const response = await axios.get<StoresResponse>(cacheUrl) const response = await axios.get<StoresResponse>(cacheUrl)
await writePersistedCache(CACHE_STORAGE_KEYS.stores, version, response.data)
return response.data return response.data
}, },
staleTime: 60000, // 1 minute staleTime: 60000, // 1 minute
enabled: !!cacheUrl && isReady, enabled: !!cacheUrl,
placeholderData: initialData,
}) })
} }
export function useSlots() { export function useSlots() {
const cacheUrl = useSlotsCacheUrl() const cacheUrl = useSlotsCacheUrl()
const version = cacheUrl ?? '' const version = cacheUrl ?? ''
const { initialData, isReady } = usePersistedCache<SlotsResponse>(CACHE_STORAGE_KEYS.slots, version)
return useQuery<SlotsResponse>({ return useQuery<SlotsResponse>({
queryKey: ['slots', version], queryKey: ['slots', version],
@ -247,36 +207,29 @@ export function useSlots() {
if (!cacheUrl) { if (!cacheUrl) {
throw new Error('Cache URL not available') throw new Error('Cache URL not available')
} }
const response = await axios.get<SlotsResponse>(cacheUrl+'?v=123') const response = await axios.get<SlotsResponse>(cacheUrl + '?v=123')
await writePersistedCache(CACHE_STORAGE_KEYS.slots, version, response.data)
return response.data return response.data
}, },
staleTime: 60000, // 1 minute staleTime: 60000, // 1 minute
enabled: !!cacheUrl && isReady, enabled: !!cacheUrl,
placeholderData: initialData,
}) })
} }
export function useBanners() { export function useBanners() {
const cacheUrl = useCacheUrl(CACHE_FILENAMES.banners) const cacheUrl = useCacheUrl(CACHE_FILENAMES.banners)
const version = cacheUrl ?? '' const version = cacheUrl ?? ''
const { initialData, isReady } = usePersistedCache<BannersResponse>(CACHE_STORAGE_KEYS.banners, version)
return useQuery<BannersResponse>({ return useQuery<BannersResponse>({
queryKey: ['banners', version], queryKey: ['banners', version],
queryFn: async () => { queryFn: async () => {
if (!cacheUrl) {
if (!cacheUrl) { throw new Error('Cache URL not available')
throw new Error('Cache URL not available') }
} const response = await axios.get<BannersResponse>(cacheUrl)
const response = await axios.get<BannersResponse>(cacheUrl) return response.data
await writePersistedCache(CACHE_STORAGE_KEYS.banners, version, response.data)
return response.data
}, },
staleTime: 60000, // 1 minute staleTime: 60000, // 1 minute
enabled: !!cacheUrl && isReady, enabled: !!cacheUrl,
placeholderData: initialData,
}) })
} }
@ -291,7 +244,6 @@ export function useStoreWithProducts(storeId: number) {
? `${assetsDomain}${apiCacheKey}/v-${cacheVersion}/stores/${storeId}.json` ? `${assetsDomain}${apiCacheKey}/v-${cacheVersion}/stores/${storeId}.json`
: null : null
const version = cacheUrl ?? '' const version = cacheUrl ?? ''
const { initialData, isReady } = usePersistedCache<StoreWithProductsResponse>(CACHE_STORAGE_KEYS.storeProducts(storeId), version)
return useQuery<StoreWithProductsResponse>({ return useQuery<StoreWithProductsResponse>({
queryKey: ['store-with-products', storeId, version], queryKey: ['store-with-products', storeId, version],
@ -300,11 +252,9 @@ export function useStoreWithProducts(storeId: number) {
throw new Error('Cache URL not available') throw new Error('Cache URL not available')
} }
const response = await axios.get<StoreWithProductsResponse>(cacheUrl) const response = await axios.get<StoreWithProductsResponse>(cacheUrl)
await writePersistedCache(CACHE_STORAGE_KEYS.storeProducts(storeId), version, response.data)
return response.data return response.data
}, },
staleTime: 60000, // 1 minute staleTime: 60000, // 1 minute
enabled: !!cacheUrl && isReady, enabled: !!cacheUrl,
placeholderData: initialData,
}) })
} }