c3ec91b2af
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
73 lines
3.5 KiB
TypeScript
73 lines
3.5 KiB
TypeScript
/**
|
||
* TanStack Query ayarları: sunucu verisinin önbelleği, yeniden deneme, yenileme.
|
||
*/
|
||
import { QueryCache, QueryClient } from '@tanstack/react-query'
|
||
import { ApiError } from './api'
|
||
|
||
/** Önbellek anahtarları tek yerde (yazım hatası olmasın) */
|
||
export const queryKeys = {
|
||
me: ['me'] as const,
|
||
registration: ['registration'] as const,
|
||
health: ['health'] as const,
|
||
household: ['household'] as const,
|
||
categories: (includeInactive = false) => ['categories', { includeInactive }] as const,
|
||
paymentMethods: (includeInactive = false) => ['payment-methods', { includeInactive }] as const,
|
||
/** Dönem listesi; `currentPeriod` da bu önekle başlar (birlikte yenilenir) */
|
||
periods: ['periods'] as const,
|
||
currentPeriod: ['periods', 'current'] as const,
|
||
/** Panel: son dönemler + toplam birikim (dönem listesiyle birlikte yenilenir) */
|
||
stats: ['periods', 'stats'] as const,
|
||
/** Bir döneme bağlı tüm veriler bu önekle başlar → `invalidateQueries({ queryKey: period(id) })` */
|
||
/** Birikimler: portföy ve varlık işlemleri bu önekle başlar (birlikte yenilenir) */
|
||
portfolio: ['portfolio'] as const,
|
||
assetTxs: (assetId: string) => ['portfolio', 'txs', assetId] as const,
|
||
pendingSavings: ['portfolio', 'pending'] as const,
|
||
/** Rapor kırılımı (`query` = sunucu sorgu metni); kayıt değişince `reports` öneki yenilenir */
|
||
reportBreakdown: (query: string) => ['reports', 'breakdown', query] as const,
|
||
reports: ['reports'] as const,
|
||
/** JSON yedeği: son yedek zamanı + geri dönüş noktaları */
|
||
backup: ['backup'] as const,
|
||
period: (id: string) => ['period', id] as const,
|
||
planItems: (id: string) => ['period', id, 'plan-items'] as const,
|
||
summary: (id: string) => ['period', id, 'summary'] as const,
|
||
review: (id: string) => ['period', id, 'review'] as const,
|
||
/** Panel grafiği: günlük harcama (kayıt değişince dönem önekiyle yenilenir) */
|
||
daily: (id: string) => ['period', id, 'daily'] as const,
|
||
/** Aylık değerlendirme raporu (Markdown); kayıt değişince dönem önekiyle yenilenir */
|
||
monthlyReport: (id: string) => ['period', id, 'report'] as const,
|
||
budget: (id: string) => ['period', id, 'budget'] as const,
|
||
suggestion: (id: string, method: string) => ['period', id, 'suggestion', method] as const,
|
||
notes: (id: string, context: string) => ['period', id, 'notes', context] as const,
|
||
/** Harcamalar; `range` verilmezse tüm dönem (`entries(id)` → tüm aralıkların öneki) */
|
||
entries: (id: string, range?: { from: string; to: string }) =>
|
||
range ? (['period', id, 'entries', range] as const) : (['period', id, 'entries'] as const),
|
||
}
|
||
|
||
/** 4xx hataları tekrar denemenin anlamı yok (yanlış istek / yetki); ağ ve 5xx için 2 kez dene. */
|
||
function shouldRetry(failureCount: number, error: unknown) {
|
||
if (error instanceof ApiError && error.status >= 400 && error.status < 500) return false
|
||
return failureCount < 2
|
||
}
|
||
|
||
export const queryClient = new QueryClient({
|
||
queryCache: new QueryCache({
|
||
onError: (error) => {
|
||
// Herhangi bir istek 401 alırsa oturum bitmiş demektir → "me" boşaltılır,
|
||
// korumalı sayfalar (Adım 4) kullanıcıyı giriş ekranına yönlendirir.
|
||
if (error instanceof ApiError && error.isUnauthorized) {
|
||
queryClient.setQueryData(queryKeys.me, null)
|
||
}
|
||
},
|
||
}),
|
||
defaultOptions: {
|
||
queries: {
|
||
retry: shouldRetry,
|
||
staleTime: 30_000, // 30 sn içinde aynı veri tekrar istenmez
|
||
refetchOnWindowFocus: true, // sekmeye dönünce güncel veri (ör. eşin eklediği harcama)
|
||
},
|
||
mutations: {
|
||
retry: false,
|
||
},
|
||
},
|
||
})
|