Initial commit: SmoothSchedule multi-tenant scheduling platform
This commit includes: - Django backend with multi-tenancy (django-tenants) - React + TypeScript frontend with Vite - Platform administration API with role-based access control - Authentication system with token-based auth - Quick login dev tools for testing different user roles - CORS and CSRF configuration for local development - Docker development environment setup 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
197
legacy_reference/frontend/src/hooks/useTransactionAnalytics.ts
Normal file
197
legacy_reference/frontend/src/hooks/useTransactionAnalytics.ts
Normal file
@@ -0,0 +1,197 @@
|
||||
/**
|
||||
* Transaction Analytics Hooks
|
||||
*
|
||||
* React Query hooks for fetching and managing transaction analytics data.
|
||||
*/
|
||||
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import {
|
||||
getTransactions,
|
||||
getTransaction,
|
||||
getTransactionSummary,
|
||||
getStripeCharges,
|
||||
getStripePayouts,
|
||||
getStripeBalance,
|
||||
exportTransactions,
|
||||
getTransactionDetail,
|
||||
refundTransaction,
|
||||
TransactionFilters,
|
||||
ExportRequest,
|
||||
RefundRequest,
|
||||
} from '../api/payments';
|
||||
|
||||
/**
|
||||
* Hook to fetch paginated transaction list with optional filters.
|
||||
*/
|
||||
export const useTransactions = (filters?: TransactionFilters) => {
|
||||
return useQuery({
|
||||
queryKey: ['transactions', filters],
|
||||
queryFn: async () => {
|
||||
const { data } = await getTransactions(filters);
|
||||
return data;
|
||||
},
|
||||
staleTime: 30 * 1000, // 30 seconds
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Hook to fetch a single transaction by ID.
|
||||
*/
|
||||
export const useTransaction = (id: number) => {
|
||||
return useQuery({
|
||||
queryKey: ['transaction', id],
|
||||
queryFn: async () => {
|
||||
const { data } = await getTransaction(id);
|
||||
return data;
|
||||
},
|
||||
enabled: !!id,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Hook to fetch transaction summary/analytics.
|
||||
*/
|
||||
export const useTransactionSummary = (filters?: Pick<TransactionFilters, 'start_date' | 'end_date'>) => {
|
||||
return useQuery({
|
||||
queryKey: ['transactionSummary', filters],
|
||||
queryFn: async () => {
|
||||
const { data } = await getTransactionSummary(filters);
|
||||
return data;
|
||||
},
|
||||
staleTime: 60 * 1000, // 1 minute
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Hook to fetch Stripe charges directly from Stripe API.
|
||||
*/
|
||||
export const useStripeCharges = (limit: number = 20) => {
|
||||
return useQuery({
|
||||
queryKey: ['stripeCharges', limit],
|
||||
queryFn: async () => {
|
||||
const { data } = await getStripeCharges(limit);
|
||||
return data;
|
||||
},
|
||||
staleTime: 30 * 1000,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Hook to fetch Stripe payouts.
|
||||
*/
|
||||
export const useStripePayouts = (limit: number = 20) => {
|
||||
return useQuery({
|
||||
queryKey: ['stripePayouts', limit],
|
||||
queryFn: async () => {
|
||||
const { data } = await getStripePayouts(limit);
|
||||
return data;
|
||||
},
|
||||
staleTime: 30 * 1000,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Hook to fetch current Stripe balance.
|
||||
*/
|
||||
export const useStripeBalance = () => {
|
||||
return useQuery({
|
||||
queryKey: ['stripeBalance'],
|
||||
queryFn: async () => {
|
||||
const { data } = await getStripeBalance();
|
||||
return data;
|
||||
},
|
||||
staleTime: 60 * 1000, // 1 minute
|
||||
refetchInterval: 5 * 60 * 1000, // Refresh every 5 minutes
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Hook to export transaction data.
|
||||
* Returns a mutation that triggers file download.
|
||||
*/
|
||||
export const useExportTransactions = () => {
|
||||
return useMutation({
|
||||
mutationFn: async (request: ExportRequest) => {
|
||||
const response = await exportTransactions(request);
|
||||
return response;
|
||||
},
|
||||
onSuccess: (response, request) => {
|
||||
// Create blob URL and trigger download
|
||||
const blob = new Blob([response.data], { type: response.headers['content-type'] });
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
|
||||
// Determine file extension based on format
|
||||
const extensions: Record<string, string> = {
|
||||
csv: 'csv',
|
||||
xlsx: 'xlsx',
|
||||
pdf: 'pdf',
|
||||
quickbooks: 'iif',
|
||||
};
|
||||
const ext = extensions[request.format] || 'txt';
|
||||
link.download = `transactions.${ext}`;
|
||||
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
window.URL.revokeObjectURL(url);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Hook to invalidate all transaction-related queries.
|
||||
* Useful after actions that modify transaction data.
|
||||
*/
|
||||
export const useInvalidateTransactions = () => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['transactions'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['transactionSummary'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['stripeCharges'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['stripePayouts'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['stripeBalance'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['transactionDetail'] });
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Hook to fetch detailed transaction information including refund data.
|
||||
*/
|
||||
export const useTransactionDetail = (id: number | null) => {
|
||||
return useQuery({
|
||||
queryKey: ['transactionDetail', id],
|
||||
queryFn: async () => {
|
||||
if (!id) return null;
|
||||
const { data } = await getTransactionDetail(id);
|
||||
return data;
|
||||
},
|
||||
enabled: !!id,
|
||||
staleTime: 10 * 1000, // 10 seconds (refresh often for live data)
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Hook to issue a refund for a transaction.
|
||||
* Automatically invalidates transaction queries on success.
|
||||
*/
|
||||
export const useRefundTransaction = () => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async ({ transactionId, request }: { transactionId: number; request?: RefundRequest }) => {
|
||||
const { data } = await refundTransaction(transactionId, request);
|
||||
return data;
|
||||
},
|
||||
onSuccess: (data, variables) => {
|
||||
// Invalidate all relevant queries
|
||||
queryClient.invalidateQueries({ queryKey: ['transactions'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['transactionSummary'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['transactionDetail', variables.transactionId] });
|
||||
queryClient.invalidateQueries({ queryKey: ['stripeCharges'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['stripeBalance'] });
|
||||
},
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user