fix: Implement comprehensive edit event button functionality and resolve authentication issues
Major fixes and improvements: - Fixed edit event button functionality with proper event handlers and DOM ready state checking - Added status column to tickets table via Supabase migration to resolve 500 API errors - Updated stats API to correctly calculate revenue from decimal price values - Resolved authentication redirect loops by fixing cookie configuration for Docker environment - Fixed Permissions-Policy header syntax errors - Added comprehensive debugging and error handling for event management - Implemented modal-based event editing with form validation and API integration - Enhanced event data loading with proper error handling and user feedback 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
247
create-test-data.cjs
Normal file
247
create-test-data.cjs
Normal file
@@ -0,0 +1,247 @@
|
||||
const { createClient } = require('@supabase/supabase-js');
|
||||
require('dotenv').config();
|
||||
|
||||
const supabaseUrl = process.env.PUBLIC_SUPABASE_URL;
|
||||
const supabaseServiceKey = process.env.SUPABASE_SERVICE_ROLE_KEY;
|
||||
|
||||
if (!supabaseUrl || !supabaseServiceKey) {
|
||||
console.error('❌ Missing required environment variables');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const supabase = createClient(supabaseUrl, supabaseServiceKey, {
|
||||
auth: {
|
||||
autoRefreshToken: false,
|
||||
persistSession: false
|
||||
}
|
||||
});
|
||||
|
||||
async function createTestData() {
|
||||
const eventId = '7ac12bd2-8509-4db3-b1bc-98a808646311';
|
||||
|
||||
console.log('🎫 Creating test ticket types and data...');
|
||||
|
||||
try {
|
||||
// Step 1: Check if ticket types already exist
|
||||
const { data: existingTicketTypes, error: checkError } = await supabase
|
||||
.from('ticket_types')
|
||||
.select('id, name, price')
|
||||
.eq('event_id', eventId);
|
||||
|
||||
if (checkError) {
|
||||
console.error('❌ Error checking existing ticket types:', checkError);
|
||||
return;
|
||||
}
|
||||
|
||||
if (existingTicketTypes && existingTicketTypes.length > 0) {
|
||||
console.log('✓ Ticket types already exist:', existingTicketTypes.map(t => t.name).join(', '));
|
||||
} else {
|
||||
console.log('Creating ticket types...');
|
||||
|
||||
// Create ticket types
|
||||
const ticketTypes = [
|
||||
{
|
||||
event_id: eventId,
|
||||
name: 'General Admission',
|
||||
description: 'Standard entry to the event',
|
||||
price: 50.00,
|
||||
quantity_available: 100,
|
||||
quantity_sold: 0,
|
||||
is_active: true,
|
||||
sort_order: 0
|
||||
},
|
||||
{
|
||||
event_id: eventId,
|
||||
name: 'VIP',
|
||||
description: 'VIP access with premium seating',
|
||||
price: 125.00,
|
||||
quantity_available: 25,
|
||||
quantity_sold: 0,
|
||||
is_active: true,
|
||||
sort_order: 1
|
||||
},
|
||||
{
|
||||
event_id: eventId,
|
||||
name: 'Student',
|
||||
description: 'Discounted tickets for students',
|
||||
price: 25.00,
|
||||
quantity_available: 50,
|
||||
quantity_sold: 0,
|
||||
is_active: true,
|
||||
sort_order: 2
|
||||
}
|
||||
];
|
||||
|
||||
const { data: newTicketTypes, error: createError } = await supabase
|
||||
.from('ticket_types')
|
||||
.insert(ticketTypes)
|
||||
.select();
|
||||
|
||||
if (createError) {
|
||||
console.error('❌ Error creating ticket types:', createError);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('✓ Created ticket types:', newTicketTypes.map(t => t.name).join(', '));
|
||||
}
|
||||
|
||||
// Step 2: Check if sample tickets exist
|
||||
const { data: existingTickets, error: ticketCheckError } = await supabase
|
||||
.from('tickets')
|
||||
.select('id, price')
|
||||
.eq('event_id', eventId);
|
||||
|
||||
if (ticketCheckError) {
|
||||
console.error('❌ Error checking tickets:', ticketCheckError);
|
||||
return;
|
||||
}
|
||||
|
||||
if (existingTickets && existingTickets.length > 0) {
|
||||
console.log(`✓ ${existingTickets.length} tickets already exist`);
|
||||
} else {
|
||||
console.log('Creating sample tickets...');
|
||||
|
||||
// Get ticket types to create tickets for
|
||||
const { data: ticketTypes, error: ttError } = await supabase
|
||||
.from('ticket_types')
|
||||
.select('id, name, price')
|
||||
.eq('event_id', eventId);
|
||||
|
||||
if (ttError || !ticketTypes || ticketTypes.length === 0) {
|
||||
console.error('❌ No ticket types found to create tickets for');
|
||||
return;
|
||||
}
|
||||
|
||||
// Create some sample sold tickets
|
||||
const sampleTickets = [];
|
||||
|
||||
// 5 general admission tickets
|
||||
const gaType = ticketTypes.find(t => t.name === 'General Admission');
|
||||
if (gaType) {
|
||||
for (let i = 1; i <= 5; i++) {
|
||||
sampleTickets.push({
|
||||
event_id: eventId,
|
||||
ticket_type_id: gaType.id,
|
||||
price: gaType.price,
|
||||
purchaser_email: `customer${i}@example.com`,
|
||||
purchaser_name: `Customer ${i}`,
|
||||
checked_in: i <= 2, // First 2 are checked in
|
||||
scanned_at: i <= 2 ? new Date().toISOString() : null,
|
||||
created_at: new Date(Date.now() - (i * 24 * 60 * 60 * 1000)).toISOString() // Spread over last 5 days
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 2 VIP tickets
|
||||
const vipType = ticketTypes.find(t => t.name === 'VIP');
|
||||
if (vipType) {
|
||||
for (let i = 1; i <= 2; i++) {
|
||||
sampleTickets.push({
|
||||
event_id: eventId,
|
||||
ticket_type_id: vipType.id,
|
||||
price: vipType.price,
|
||||
purchaser_email: `vip${i}@example.com`,
|
||||
purchaser_name: `VIP Customer ${i}`,
|
||||
checked_in: i === 1, // First VIP is checked in
|
||||
scanned_at: i === 1 ? new Date().toISOString() : null,
|
||||
created_at: new Date(Date.now() - (i * 12 * 60 * 60 * 1000)).toISOString() // Recent purchases
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 1 student ticket
|
||||
const studentType = ticketTypes.find(t => t.name === 'Student');
|
||||
if (studentType) {
|
||||
sampleTickets.push({
|
||||
event_id: eventId,
|
||||
ticket_type_id: studentType.id,
|
||||
price: studentType.price,
|
||||
purchaser_email: 'student1@university.edu',
|
||||
purchaser_name: 'Student User',
|
||||
checked_in: false,
|
||||
scanned_at: null,
|
||||
created_at: new Date(Date.now() - (6 * 60 * 60 * 1000)).toISOString() // 6 hours ago
|
||||
});
|
||||
}
|
||||
|
||||
if (sampleTickets.length > 0) {
|
||||
const { data: newTickets, error: createTicketsError } = await supabase
|
||||
.from('tickets')
|
||||
.insert(sampleTickets)
|
||||
.select();
|
||||
|
||||
if (createTicketsError) {
|
||||
console.error('❌ Error creating sample tickets:', createTicketsError);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`✓ Created ${newTickets.length} sample tickets`);
|
||||
}
|
||||
}
|
||||
|
||||
// Step 3: Test the stats API by calling it directly
|
||||
console.log('\n🧪 Testing stats calculation...');
|
||||
|
||||
const { data: tickets, error: ticketsError } = await supabase
|
||||
.from('tickets')
|
||||
.select(`
|
||||
id,
|
||||
ticket_type_id,
|
||||
price,
|
||||
checked_in,
|
||||
scanned_at
|
||||
`)
|
||||
.eq('event_id', eventId);
|
||||
|
||||
if (ticketsError) {
|
||||
console.error('❌ Error loading tickets for stats:', ticketsError);
|
||||
return;
|
||||
}
|
||||
|
||||
const { data: ticketTypes, error: ticketTypesError } = await supabase
|
||||
.from('ticket_types')
|
||||
.select('id, quantity_available, price')
|
||||
.eq('event_id', eventId);
|
||||
|
||||
if (ticketTypesError) {
|
||||
console.error('❌ Error loading ticket types for stats:', ticketTypesError);
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate stats manually to verify
|
||||
const soldTickets = tickets || []; // All tickets in table are considered sold
|
||||
const checkedInTickets = tickets?.filter(t => t.checked_in || t.scanned_at) || [];
|
||||
|
||||
const totalRevenue = soldTickets.reduce((sum, ticket) => {
|
||||
const priceInDollars = ticket.price || 0;
|
||||
return sum + Math.round(priceInDollars * 100); // Convert to cents
|
||||
}, 0);
|
||||
|
||||
const totalAvailable = ticketTypes?.reduce((sum, type) => sum + (type.quantity_available || 0), 0) || 0;
|
||||
const ticketsSold = soldTickets.length;
|
||||
const ticketsAvailable = totalAvailable - ticketsSold;
|
||||
|
||||
const stats = {
|
||||
totalRevenue,
|
||||
ticketsSold,
|
||||
ticketsAvailable,
|
||||
checkedIn: checkedInTickets.length
|
||||
};
|
||||
|
||||
console.log('✓ Calculated stats:', stats);
|
||||
|
||||
console.log('\n🎉 Test data setup complete!');
|
||||
console.log('=====================================');
|
||||
console.log(`Event ID: ${eventId}`);
|
||||
console.log(`Ticket types: ${ticketTypes?.length || 0}`);
|
||||
console.log(`Total tickets: ${tickets?.length || 0}`);
|
||||
console.log(`Sold tickets: ${ticketsSold}`);
|
||||
console.log(`Checked in: ${checkedInTickets.length}`);
|
||||
console.log(`Total revenue: $${(totalRevenue / 100).toFixed(2)}`);
|
||||
|
||||
} catch (error) {
|
||||
console.error('💥 Unexpected error:', error);
|
||||
}
|
||||
}
|
||||
|
||||
createTestData();
|
||||
Reference in New Issue
Block a user