Extract admin dashboard from ghabilee-frontend2 into a dedicated Next.js app for backoffice.ghabilee.ir (no SEO indexing / Clarity).
102 lines
2.8 KiB
TypeScript
102 lines
2.8 KiB
TypeScript
import type { PersistQueryClientProviderProps } from '@tanstack/react-query-persist-client'
|
|
|
|
import { QueryClient } from '@tanstack/react-query'
|
|
import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister'
|
|
|
|
const DEFAULT_STALE_TIME_MS = 30_000
|
|
const DEFAULT_GC_TIME_MS = 5 * 60_000
|
|
|
|
export const makeQueryClient = () =>
|
|
new QueryClient({
|
|
defaultOptions: {
|
|
queries: {
|
|
staleTime: DEFAULT_STALE_TIME_MS,
|
|
gcTime: DEFAULT_GC_TIME_MS,
|
|
refetchOnWindowFocus: true,
|
|
refetchOnReconnect: true,
|
|
retry: 1,
|
|
},
|
|
},
|
|
})
|
|
|
|
let browserQueryClient: QueryClient | undefined
|
|
|
|
/** Browser singleton so layout remounts share one cache. */
|
|
export const getQueryClient = () => {
|
|
if (typeof window === 'undefined') {
|
|
return makeQueryClient()
|
|
}
|
|
|
|
browserQueryClient ??= makeQueryClient()
|
|
|
|
return browserQueryClient
|
|
}
|
|
|
|
const PERSIST_STORAGE_KEY = 'ghabilee-admin-query-cache-v1'
|
|
const LEGACY_PERSIST_STORAGE_KEY = 'ghabilee-query-cache-v2'
|
|
const PERSIST_MAX_AGE_MS = 24 * 60 * 60_000
|
|
|
|
/** Inert stand-in for `window.localStorage` during SSR. */
|
|
const noopStorage: Storage = {
|
|
length: 0,
|
|
clear() {
|
|
/* SSR inert storage */
|
|
},
|
|
getItem: () => null,
|
|
key: () => null,
|
|
removeItem() {
|
|
/* SSR inert storage */
|
|
},
|
|
setItem() {
|
|
/* SSR inert storage */
|
|
},
|
|
}
|
|
|
|
const removeStorageKey = (key: string) => {
|
|
if (typeof window === 'undefined') return
|
|
|
|
try {
|
|
window.localStorage.removeItem(key)
|
|
} catch {
|
|
// Persistence is optional; blocked storage must not break the app.
|
|
}
|
|
}
|
|
|
|
let didRemoveLegacyPersistedCache = false
|
|
|
|
const removeLegacyPersistedCache = () => {
|
|
if (didRemoveLegacyPersistedCache || typeof window === 'undefined') return
|
|
|
|
removeStorageKey(LEGACY_PERSIST_STORAGE_KEY)
|
|
removeStorageKey('ghabilee-query-cache')
|
|
didRemoveLegacyPersistedCache = true
|
|
}
|
|
|
|
/** Remove persisted query state synchronously before ending a user session. */
|
|
export const clearPersistedQueryCache = () => {
|
|
removeStorageKey(PERSIST_STORAGE_KEY)
|
|
removeStorageKey(LEGACY_PERSIST_STORAGE_KEY)
|
|
removeStorageKey('ghabilee-query-cache')
|
|
}
|
|
|
|
/**
|
|
* Admin does not persist discovery/home-feed caches. Provider shape stays
|
|
* stable for hydration; dehydrate always returns false.
|
|
*/
|
|
export const getQueryPersistOptions = (): PersistQueryClientProviderProps['persistOptions'] => {
|
|
removeLegacyPersistedCache()
|
|
|
|
return {
|
|
// eslint-disable-next-line @typescript-eslint/no-deprecated -- sync persister intentional for localStorage
|
|
persister: createSyncStoragePersister({
|
|
storage: typeof window === 'undefined' ? noopStorage : window.localStorage,
|
|
key: PERSIST_STORAGE_KEY,
|
|
}),
|
|
maxAge: PERSIST_MAX_AGE_MS,
|
|
buster: process.env.NEXT_PUBLIC_APP_VERSION ?? '',
|
|
dehydrateOptions: {
|
|
shouldDehydrateQuery: () => false,
|
|
},
|
|
}
|
|
}
|