Files
blackcanyontickets/reactrebuild0825/src/queries/tickets.ts
dzinesco aa81eb5adb feat: add advanced analytics and territory management system
- Add comprehensive analytics components with export functionality
- Implement territory management with manager performance tracking
- Add seatmap components for venue layout management
- Create customer management features with modal interface
- Add advanced hooks for dashboard flags and territory data
- Implement seat selection and venue management utilities
- Add type definitions for ticketing and seatmap systems

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-26 09:25:10 -06:00

147 lines
4.6 KiB
TypeScript

import { useMemo } from 'react';
import { useTicketStore } from '../stores/ticketStore';
import { useEventStore } from '../stores/eventStore';
import { useClaims } from '../hooks/useClaims';
import type { Ticket } from '../types/business';
/**
* Hook to get tickets with territory filtering applied
* Respects user role and territory access controls
*/
export const useTicketsQuery = (eventId?: string, selectedTerritoryIds?: string[]) => {
const { tickets, isLoading, error } = useTicketStore();
const { getEvent } = useEventStore();
const { claims } = useClaims();
const filteredTickets = useMemo(() => {
if (!claims) {
return [];
}
let ticketsToFilter = tickets;
// Filter by event if specified
if (eventId) {
ticketsToFilter = ticketsToFilter.filter(ticket => ticket.eventId === eventId);
}
// Apply territory filtering based on role
if (claims.role === 'territoryManager') {
// Territory managers can only see tickets for events in their territories
const userTerritoryIds = claims.territoryIds || [];
ticketsToFilter = ticketsToFilter.filter(ticket => {
const event = getEvent(ticket.eventId);
return event && userTerritoryIds.includes(event.territoryId || '');
});
} else if (claims.role === 'orgAdmin' || claims.role === 'superadmin') {
// Admins can optionally filter by selected territories
if (selectedTerritoryIds && selectedTerritoryIds.length > 0) {
ticketsToFilter = ticketsToFilter.filter(ticket => {
const event = getEvent(ticket.eventId);
return event && selectedTerritoryIds.includes(event.territoryId || '');
});
}
}
return ticketsToFilter;
}, [tickets, eventId, claims, selectedTerritoryIds, getEvent]);
return {
tickets: filteredTickets,
isLoading,
error,
totalCount: filteredTickets.length,
isFiltered: (claims?.role === 'territoryManager') ||
(selectedTerritoryIds && selectedTerritoryIds.length > 0)
};
};
/**
* Hook to get tickets for a specific event with territory validation
*/
export const useEventTicketsQuery = (eventId: string) => {
const { tickets, isLoading, error } = useTicketStore();
const { getEvent } = useEventStore();
const { claims } = useClaims();
const eventTickets = useMemo(() => {
if (!claims) {
return [];
}
const event = getEvent(eventId);
if (!event) {
return [];
}
// Check territory access for territory managers
if (claims.role === 'territoryManager') {
const userTerritoryIds = claims.territoryIds || [];
if (!userTerritoryIds.includes(event.territoryId || '')) {
return []; // Access denied to event, so no tickets
}
}
return tickets.filter(ticket => ticket.eventId === eventId);
}, [eventId, tickets, getEvent, claims]);
return {
tickets: eventTickets,
isLoading,
error,
hasAccess: eventTickets.length > 0 || claims?.role !== 'territoryManager'
};
};
/**
* Hook to get ticket statistics with territory filtering
*/
export const useTicketStatsQuery = (selectedTerritoryIds?: string[]) => {
const { tickets } = useTicketStore();
const { getEvent } = useEventStore();
const { claims } = useClaims();
const stats = useMemo(() => {
if (!claims) {
return {
totalSold: 0,
totalRevenue: 0,
pendingTickets: 0,
scannedTickets: 0
};
}
let ticketsToAnalyze = tickets;
// Apply territory filtering based on role
if (claims.role === 'territoryManager') {
const userTerritoryIds = claims.territoryIds || [];
ticketsToAnalyze = ticketsToAnalyze.filter(ticket => {
const event = getEvent(ticket.eventId);
return event && userTerritoryIds.includes(event.territoryId || '');
});
} else if (claims.role === 'orgAdmin' || claims.role === 'superadmin') {
if (selectedTerritoryIds && selectedTerritoryIds.length > 0) {
ticketsToAnalyze = ticketsToAnalyze.filter(ticket => {
const event = getEvent(ticket.eventId);
return event && selectedTerritoryIds.includes(event.territoryId || '');
});
}
}
const totalSold = ticketsToAnalyze.length;
const totalRevenue = ticketsToAnalyze.reduce((sum, ticket) => sum + ticket.price, 0);
const pendingTickets = ticketsToAnalyze.filter(ticket => ticket.status === 'pending').length;
const scannedTickets = ticketsToAnalyze.filter(ticket => ticket.status === 'scanned').length;
return {
totalSold,
totalRevenue,
pendingTickets,
scannedTickets
};
}, [tickets, claims, selectedTerritoryIds, getEvent]);
return stats;
};