import { keepPreviousData, useMutation, useQuery, useQueryClient, } from "@tanstack/react-query"; import { type CreateNonPeriodicExpenseInput, type CreatePeriodicExpenseInput, createNonPeriodicExpense as createNonPeriodicExpenseApi, createPeriodicExpense as createPeriodicExpenseApi, deletePeriodicExpense as deletePeriodicExpenseApi, fetchQuotes, generateMonthlyExpense as generateMonthlyExpenseApi, getDailyMinMax, getDailyQuotes, getExpenses, generateTelegramCode, getHistoricalMinMax, getMonthlyPayedTotal, getMonthlyTotals, getPendingUpcomingExpenses, getPeriodicExpenses, getQuoteHistory, getQuotes, getTelegramStatus, getTotalPending, importExpenses, importPeriodicExpenses, type PayExpenseInput, payExpense as payExpenseApi, type UpdateExpenseInput, updateExpense as updateExpenseApi, updatePeriodicExpense as updatePeriodicExpenseApi, } from "./api"; export const quoteKeys = { all: ["quotes"] as const, history: (type: string, startDate: string, endDate: string) => ["quotes", type, "history", startDate, endDate] as const, minMax: (type: string, startDate: string, endDate: string) => ["quotes", type, "minMax", startDate, endDate] as const, daily: (type: string, startDate: string, endDate: string) => ["quotes", type, "daily", startDate, endDate] as const, historicalMinMax: (type: string) => ["quotes", type, "historicalMinMax"] as const, }; export function useQuotes() { return useQuery({ queryKey: quoteKeys.all, queryFn: getQuotes, staleTime: 30_000, refetchInterval: 60_000, }); } export function useFetchQuotes() { const queryClient = useQueryClient(); return useMutation({ mutationFn: fetchQuotes, onSuccess: () => { queryClient.invalidateQueries({ queryKey: quoteKeys.all }); }, }); } export function useQuoteHistory( type: string, startDate: string, endDate: string, ) { return useQuery({ queryKey: quoteKeys.history(type, startDate, endDate), queryFn: () => getQuoteHistory(type, startDate, endDate), staleTime: 30_000, refetchInterval: 60_000, }); } export function useDailyMinMax( type: string, startDate: string, endDate: string, ) { return useQuery({ queryKey: quoteKeys.minMax(type, startDate, endDate), queryFn: () => getDailyMinMax(type, startDate, endDate), staleTime: 30_000, refetchInterval: 60_000, }); } export function useDailyQuotes( type: string, startDate: string, endDate: string, ) { return useQuery({ queryKey: quoteKeys.daily(type, startDate, endDate), queryFn: () => getDailyQuotes(type, startDate, endDate), staleTime: 30_000, refetchInterval: 60_000, }); } export function useHistoricalMinMax(type: string) { return useQuery({ queryKey: quoteKeys.historicalMinMax(type), queryFn: () => getHistoricalMinMax(type), staleTime: 30_000, }); } // Expenses export const expenseKeys = { periodic: ["periodic-expenses"] as const, all: ["expenses"] as const, byFilters: ( status: string, page: number, pageSize: number, periodicExpenseId?: number, search?: string, ) => ["expenses", status, page, pageSize, periodicExpenseId, search] as const, monthlyTotal: (year: number, month: number) => ["expenses", "monthly-total", year, month] as const, monthlyTotals: (year: number, month: number) => ["expenses", "totals", year, month] as const, totalPending: ["expenses", "pending-total"] as const, pendingUpcoming: ["expenses", "pending-upcoming"] as const, }; export function usePeriodicExpenses() { return useQuery({ queryKey: expenseKeys.periodic, queryFn: getPeriodicExpenses, }); } export function useCreatePeriodicExpense() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (data: CreatePeriodicExpenseInput) => createPeriodicExpenseApi(data), onSuccess: () => { queryClient.invalidateQueries({ queryKey: expenseKeys.periodic }); }, }); } export function useUpdatePeriodicExpense() { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ id, data, }: { id: number; data: CreatePeriodicExpenseInput; }) => updatePeriodicExpenseApi(id, data), onSuccess: () => { queryClient.invalidateQueries({ queryKey: expenseKeys.periodic }); }, }); } export function useDeletePeriodicExpense() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (id: number) => deletePeriodicExpenseApi(id), onSuccess: () => { queryClient.invalidateQueries({ queryKey: expenseKeys.periodic }); }, }); } export function useGenerateMonthlyExpense() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (id: number) => generateMonthlyExpenseApi(id), onSuccess: () => { queryClient.invalidateQueries({ queryKey: expenseKeys.all }); }, }); } export function useExpenses( status: string, page: number = 1, pageSize: number = 10, periodicExpenseId?: number, search?: string, ) { return useQuery({ queryKey: expenseKeys.byFilters( status, page, pageSize, periodicExpenseId, search, ), placeholderData: keepPreviousData, queryFn: () => getExpenses( status === "all" ? undefined : status, page, pageSize, periodicExpenseId, search, ), }); } export function useMonthlyTotals(year: number, month: number) { return useQuery({ queryKey: expenseKeys.monthlyTotals(year, month), queryFn: () => getMonthlyTotals(year, month), }); } export function usePendingUpcomingExpenses() { return useQuery({ queryKey: expenseKeys.pendingUpcoming, queryFn: getPendingUpcomingExpenses, }); } export function useTotalPending() { return useQuery({ queryKey: expenseKeys.totalPending, queryFn: getTotalPending, }); } export function useMonthlyPayedTotal(year: number, month: number) { return useQuery({ queryKey: expenseKeys.monthlyTotal(year, month), queryFn: () => getMonthlyPayedTotal(year, month), }); } export function useCreateNonPeriodicExpense() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (data: CreateNonPeriodicExpenseInput) => createNonPeriodicExpenseApi(data), onSuccess: () => { queryClient.invalidateQueries({ queryKey: expenseKeys.all }); }, }); } export function useImportExpenses() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (file: File) => importExpenses(file), onSuccess: () => { queryClient.invalidateQueries({ queryKey: expenseKeys.all }); }, }); } export function useImportPeriodicExpenses() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (file: File) => importPeriodicExpenses(file), onSuccess: () => { queryClient.invalidateQueries({ queryKey: expenseKeys.periodic }); }, }); } export function usePayExpense() { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ id, data }: { id: number; data: PayExpenseInput }) => payExpenseApi(id, data), onSuccess: () => { queryClient.invalidateQueries({ queryKey: expenseKeys.all }); }, }); } export function useUpdateExpense() { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ id, data }: { id: number; data: UpdateExpenseInput }) => updateExpenseApi(id, data), onSuccess: () => { queryClient.invalidateQueries({ queryKey: expenseKeys.all }); }, }); } // Telegram export function useTelegramStatus() { return useQuery({ queryKey: ["telegram", "status"], queryFn: getTelegramStatus, staleTime: 30_000, }); } export function useGenerateTelegramCode() { const queryClient = useQueryClient(); return useMutation({ mutationFn: generateTelegramCode, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["telegram", "status"] }); }, }); }