From 8c0936ef96b8c45298b33b7f01c8d9d3e0647f6a Mon Sep 17 00:00:00 2001 From: Akshay Date: Tue, 18 Nov 2025 13:26:20 +0530 Subject: [PATCH 1/5] feat(company-dashboard): Calculate actual views and clicks per event type - Replace proportional view/click calculation with actual aggregated metrics from events and hackathons data - Calculate eventViews by summing views from all approved events - Calculate eventClicks by summing clicks from all approved events - Calculate hackathonViews by summing views from all approved hackathons - Calculate hackathonClicks by summing clicks from all approved hackathons - Update eventMetrics and hackathonMetrics to use actual calculated values instead of proportional estimates - Remove proportional ratio calculation logic that was previously used as a workaround - Improves accuracy of dashboard metrics by using real data instead of estimates based on item counts --- components/dashboard/CompanyDashboard.tsx | 37 ++++++++++++++++------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/components/dashboard/CompanyDashboard.tsx b/components/dashboard/CompanyDashboard.tsx index d1906eb1..154132cb 100644 --- a/components/dashboard/CompanyDashboard.tsx +++ b/components/dashboard/CompanyDashboard.tsx @@ -189,13 +189,28 @@ export function CompanyDashboard({ company }: CompanyDashboardProps) { const totalRegistrations = eventRegistrations + hackathonRegistrations /* eslint-enable @typescript-eslint/no-explicit-any */ - // Calculate separate metrics for events and hackathons from analytics - // Note: The analytics API doesn't currently separate views/clicks by type - // For now, we'll use the registration counts from the actual data - // and split views/clicks proportionally based on the number of each type - const totalItems = approvedEvents.length + approvedHackathons.length - const eventRatio = totalItems > 0 ? approvedEvents.length / totalItems : 0.5 - const hackathonRatio = totalItems > 0 ? approvedHackathons.length / totalItems : 0.5 + // Calculate actual views and clicks from events and hackathons + /* eslint-disable @typescript-eslint/no-explicit-any */ + const eventViews = eventsData.events?.reduce( + (sum: number, e: any) => sum + (e.views || 0), + 0 + ) || 0 + + const eventClicks = eventsData.events?.reduce( + (sum: number, e: any) => sum + (e.clicks || 0), + 0 + ) || 0 + + const hackathonViews = hackathonsData.hackathons?.reduce( + (sum: number, h: any) => sum + (h.views || 0), + 0 + ) || 0 + + const hackathonClicks = hackathonsData.hackathons?.reduce( + (sum: number, h: any) => sum + (h.clicks || 0), + 0 + ) || 0 + /* eslint-enable @typescript-eslint/no-explicit-any */ const totalViews = analyticsData.summary?.total_views || 0 const totalClicks = analyticsData.summary?.total_clicks || 0 @@ -208,14 +223,14 @@ export function CompanyDashboard({ company }: CompanyDashboardProps) { totalClicks: totalClicks, pendingApprovals: pendingEvents.length, eventMetrics: { - views: Math.round(totalViews * eventRatio), + views: eventViews, registrations: eventRegistrations, - clicks: Math.round(totalClicks * eventRatio), + clicks: eventClicks, }, hackathonMetrics: { - views: Math.round(totalViews * hackathonRatio), + views: hackathonViews, registrations: hackathonRegistrations, - clicks: Math.round(totalClicks * hackathonRatio), + clicks: hackathonClicks, }, recentChange: { events: 0, // Could calculate from analytics From d369ea3a172289f343fe9f6b575d146b21298167 Mon Sep 17 00:00:00 2001 From: Akshay Date: Tue, 18 Nov 2025 13:41:19 +0530 Subject: [PATCH 2/5] feat(analytics): Fetch actual event and hackathon stats from API - Add React state and useEffect hook to EventPerformanceComparison component to fetch real event data from API - Add React state and useEffect hook to HackathonPerformanceComparison component to fetch real hackathon data from API - Extract company slug from URL pathname to construct API endpoints dynamically - Filter approved events and hackathons before calculating performance metrics - Calculate total views, clicks, and registrations from actual event/hackathon records instead of analytics aggregates - Implement fallback to analytics data when API fetch fails or returns no data - Replace hardcoded metric calculations with dynamic API-driven data for more accurate dashboard reporting --- components/dashboard/AnalyticsCharts.tsx | 108 ++++++++++++++++++++--- 1 file changed, 98 insertions(+), 10 deletions(-) diff --git a/components/dashboard/AnalyticsCharts.tsx b/components/dashboard/AnalyticsCharts.tsx index 47e1bc1c..596d911a 100644 --- a/components/dashboard/AnalyticsCharts.tsx +++ b/components/dashboard/AnalyticsCharts.tsx @@ -515,11 +515,57 @@ interface EventPerformanceComparisonProps { } function EventPerformanceComparison({ analytics }: EventPerformanceComparisonProps) { - // Calculate performance metrics - const totalEvents = analytics.reduce((sum, record) => sum + record.events_published, 0) - const totalViews = analytics.reduce((sum, record) => sum + record.total_views, 0) - const totalClicks = analytics.reduce((sum, record) => sum + record.total_clicks, 0) - const totalRegistrations = analytics.reduce((sum, record) => sum + record.total_registrations, 0) + const [eventStats, setEventStats] = React.useState<{ + totalEvents: number + totalViews: number + totalClicks: number + totalRegistrations: number + } | null>(null) + + React.useEffect(() => { + // Fetch actual event data from the API + const fetchEventStats = async () => { + try { + // Get company slug from URL + const pathParts = window.location.pathname.split('/') + const companySlug = pathParts[pathParts.indexOf('company') + 1] + + const response = await fetch(`/api/companies/${companySlug}/events?status=all&limit=100`) + if (!response.ok) return + + const data = await response.json() + /* eslint-disable @typescript-eslint/no-explicit-any */ + const approvedEvents = data.events?.filter((e: any) => e.approval_status === 'approved') || [] + + // Calculate actual totals from events table + const totalViews = approvedEvents.reduce((sum: number, e: any) => sum + (e.views || 0), 0) + const totalClicks = approvedEvents.reduce((sum: number, e: any) => sum + (e.clicks || 0), 0) + + // Get registrations count + const regResponse = await fetch(`/api/companies/${companySlug}/events?status=all&limit=100`) + const regData = await regResponse.json() + const totalRegistrations = regData.events?.reduce((sum: number, e: any) => sum + (e.registered || 0), 0) || 0 + /* eslint-enable @typescript-eslint/no-explicit-any */ + + setEventStats({ + totalEvents: approvedEvents.length, + totalViews, + totalClicks, + totalRegistrations + }) + } catch (error) { + console.error('Error fetching event stats:', error) + } + } + + fetchEventStats() + }, []) + + // Use fetched stats if available, otherwise fall back to analytics data + const totalEvents = eventStats?.totalEvents ?? analytics.reduce((sum, record) => sum + record.events_published, 0) + const totalViews = eventStats?.totalViews ?? 0 + const totalClicks = eventStats?.totalClicks ?? 0 + const totalRegistrations = eventStats?.totalRegistrations ?? 0 // Calculate averages per event const avgViewsPerEvent = totalEvents > 0 ? Math.round(totalViews / totalEvents) : 0 @@ -621,11 +667,53 @@ interface HackathonPerformanceComparisonProps { } function HackathonPerformanceComparison({ analytics }: HackathonPerformanceComparisonProps) { - // Calculate performance metrics - const totalHackathons = analytics.reduce((sum, record) => sum + record.hackathons_published, 0) - const totalViews = analytics.reduce((sum, record) => sum + record.total_views, 0) - const totalClicks = analytics.reduce((sum, record) => sum + record.total_clicks, 0) - const totalRegistrations = analytics.reduce((sum, record) => sum + record.total_registrations, 0) + const [hackathonStats, setHackathonStats] = React.useState<{ + totalHackathons: number + totalViews: number + totalClicks: number + totalRegistrations: number + } | null>(null) + + React.useEffect(() => { + // Fetch actual hackathon data from the API + const fetchHackathonStats = async () => { + try { + // Get company slug from URL + const pathParts = window.location.pathname.split('/') + const companySlug = pathParts[pathParts.indexOf('company') + 1] + + const response = await fetch(`/api/companies/${companySlug}/hackathons?status=all&limit=100`) + if (!response.ok) return + + const data = await response.json() + /* eslint-disable @typescript-eslint/no-explicit-any */ + const approvedHackathons = data.hackathons?.filter((h: any) => h.approval_status === 'approved') || [] + + // Calculate actual totals from hackathons table + const totalViews = approvedHackathons.reduce((sum: number, h: any) => sum + (h.views || 0), 0) + const totalClicks = approvedHackathons.reduce((sum: number, h: any) => sum + (h.clicks || 0), 0) + const totalRegistrations = approvedHackathons.reduce((sum: number, h: any) => sum + (h.registered || 0), 0) + /* eslint-enable @typescript-eslint/no-explicit-any */ + + setHackathonStats({ + totalHackathons: approvedHackathons.length, + totalViews, + totalClicks, + totalRegistrations + }) + } catch (error) { + console.error('Error fetching hackathon stats:', error) + } + } + + fetchHackathonStats() + }, []) + + // Use fetched stats if available, otherwise fall back to analytics data + const totalHackathons = hackathonStats?.totalHackathons ?? analytics.reduce((sum, record) => sum + record.hackathons_published, 0) + const totalViews = hackathonStats?.totalViews ?? 0 + const totalClicks = hackathonStats?.totalClicks ?? 0 + const totalRegistrations = hackathonStats?.totalRegistrations ?? 0 // Calculate averages per hackathon const avgViewsPerHackathon = totalHackathons > 0 ? Math.round(totalViews / totalHackathons) : 0 From e426d945870e608104ebd057941914014ae1498f Mon Sep 17 00:00:00 2001 From: Akshay Date: Tue, 18 Nov 2025 13:53:27 +0530 Subject: [PATCH 3/5] feat(analytics): Fetch actual stats from events and hackathons tables - Add useEffect hook to fetch real-time event and hackathon statistics from API - Calculate actual views, clicks, and registrations from approved events and hackathons - Implement fallback to analytics data when actual stats are unavailable - Update AnalyticsCharts to use actual stats instead of analytics summary data - Update CompanyDashboard to calculate totalViews and totalClicks from events/hackathons - Rename analytics totals to analyticsTotals for clarity and distinction - Improve accuracy of dashboard metrics by using source-of-truth data from events and hackathons tables --- components/dashboard/AnalyticsCharts.tsx | 68 ++++++++++++++++++++++- components/dashboard/CompanyDashboard.tsx | 5 +- 2 files changed, 69 insertions(+), 4 deletions(-) diff --git a/components/dashboard/AnalyticsCharts.tsx b/components/dashboard/AnalyticsCharts.tsx index 596d911a..b3b634b7 100644 --- a/components/dashboard/AnalyticsCharts.tsx +++ b/components/dashboard/AnalyticsCharts.tsx @@ -30,6 +30,59 @@ interface AnalyticsChartsProps { export function AnalyticsCharts({ analytics, dateRange, onExport }: AnalyticsChartsProps) { const [chartType, setChartType] = useState<'line' | 'bar' | 'area'>('line') + const [actualStats, setActualStats] = React.useState<{ + views: number + clicks: number + registrations: number + eventsPublished: number + eventsCreated: number + hackathonsPublished: number + hackathonsCreated: number + } | null>(null) + + // Fetch actual stats from events and hackathons tables + React.useEffect(() => { + const fetchActualStats = async () => { + try { + const pathParts = window.location.pathname.split('/') + const companySlug = pathParts[pathParts.indexOf('company') + 1] + + // Fetch events + const eventsRes = await fetch(`/api/companies/${companySlug}/events?status=all&limit=100`) + const eventsData = await eventsRes.json() + /* eslint-disable @typescript-eslint/no-explicit-any */ + const allEvents = eventsData.events || [] + const approvedEvents = allEvents.filter((e: any) => e.approval_status === 'approved') + const eventViews = approvedEvents.reduce((sum: number, e: any) => sum + (e.views || 0), 0) + const eventClicks = approvedEvents.reduce((sum: number, e: any) => sum + (e.clicks || 0), 0) + const eventRegs = approvedEvents.reduce((sum: number, e: any) => sum + (e.registered || 0), 0) + + // Fetch hackathons + const hackathonsRes = await fetch(`/api/companies/${companySlug}/hackathons?status=all&limit=100`) + const hackathonsData = await hackathonsRes.json() + const allHackathons = hackathonsData.hackathons || [] + const approvedHackathons = allHackathons.filter((h: any) => h.approval_status === 'approved') + const hackathonViews = approvedHackathons.reduce((sum: number, h: any) => sum + (h.views || 0), 0) + const hackathonClicks = approvedHackathons.reduce((sum: number, h: any) => sum + (h.clicks || 0), 0) + const hackathonRegs = approvedHackathons.reduce((sum: number, h: any) => sum + (h.registered || 0), 0) + /* eslint-enable @typescript-eslint/no-explicit-any */ + + setActualStats({ + views: eventViews + hackathonViews, + clicks: eventClicks + hackathonClicks, + registrations: eventRegs + hackathonRegs, + eventsPublished: approvedEvents.length, + eventsCreated: allEvents.length, + hackathonsPublished: approvedHackathons.length, + hackathonsCreated: allHackathons.length, + }) + } catch (error) { + console.error('Error fetching actual stats:', error) + } + } + + fetchActualStats() + }, []) // Transform analytics data for charts const chartData = analytics.map((record) => ({ @@ -44,8 +97,8 @@ export function AnalyticsCharts({ analytics, dateRange, onExport }: AnalyticsCha hackathonsPublished: record.hackathons_published, })) - // Calculate totals - const totals = analytics.reduce( + // Calculate totals from analytics (for published counts) + const analyticsTotals = analytics.reduce( (acc, record) => ({ views: acc.views + record.total_views, clicks: acc.clicks + record.total_clicks, @@ -58,6 +111,17 @@ export function AnalyticsCharts({ analytics, dateRange, onExport }: AnalyticsCha { views: 0, clicks: 0, registrations: 0, eventsCreated: 0, eventsPublished: 0, hackathonsCreated: 0, hackathonsPublished: 0 } ) + // Use actual stats if available, otherwise fall back to analytics + const totals = { + views: actualStats?.views ?? analyticsTotals.views, + clicks: actualStats?.clicks ?? analyticsTotals.clicks, + registrations: actualStats?.registrations ?? analyticsTotals.registrations, + eventsCreated: actualStats?.eventsCreated ?? analyticsTotals.eventsCreated, + eventsPublished: actualStats?.eventsPublished ?? analyticsTotals.eventsPublished, + hackathonsCreated: actualStats?.hackathonsCreated ?? analyticsTotals.hackathonsCreated, + hackathonsPublished: actualStats?.hackathonsPublished ?? analyticsTotals.hackathonsPublished, + } + // Calculate averages const avgViews = analytics.length > 0 ? Math.round(totals.views / analytics.length) : 0 const avgClicks = analytics.length > 0 ? Math.round(totals.clicks / analytics.length) : 0 diff --git a/components/dashboard/CompanyDashboard.tsx b/components/dashboard/CompanyDashboard.tsx index 154132cb..173636fd 100644 --- a/components/dashboard/CompanyDashboard.tsx +++ b/components/dashboard/CompanyDashboard.tsx @@ -212,8 +212,9 @@ export function CompanyDashboard({ company }: CompanyDashboardProps) { ) || 0 /* eslint-enable @typescript-eslint/no-explicit-any */ - const totalViews = analyticsData.summary?.total_views || 0 - const totalClicks = analyticsData.summary?.total_clicks || 0 + // Use actual views and clicks from events/hackathons tables, not analytics + const totalViews = eventViews + hackathonViews + const totalClicks = eventClicks + hackathonClicks setStats({ totalEvents: approvedEvents.length, From 3f559243711b38d3e87d036b9cedb2f52b01e4d8 Mon Sep 17 00:00:00 2001 From: Akshay Date: Tue, 18 Nov 2025 14:02:58 +0530 Subject: [PATCH 4/5] feat(analytics): Distribute actual stats proportionally across historical data - Calculate scaling factors to adjust historical analytics data to match current actual stats - Implement two-pass distribution algorithm to proportionally scale views and clicks - Floor proportional values in first pass to maintain data integrity - Distribute remaining views and clicks to days with highest fractional remainders - Remove remainder fields from final chart data for clean output - Ensures historical trends are preserved while reflecting current reality in analytics charts --- components/dashboard/AnalyticsCharts.tsx | 63 +++++++++++++++++++----- 1 file changed, 51 insertions(+), 12 deletions(-) diff --git a/components/dashboard/AnalyticsCharts.tsx b/components/dashboard/AnalyticsCharts.tsx index b3b634b7..a91fb28f 100644 --- a/components/dashboard/AnalyticsCharts.tsx +++ b/components/dashboard/AnalyticsCharts.tsx @@ -84,18 +84,57 @@ export function AnalyticsCharts({ analytics, dateRange, onExport }: AnalyticsCha fetchActualStats() }, []) - // Transform analytics data for charts - const chartData = analytics.map((record) => ({ - date: format(new Date(record.date), 'MMM dd'), - fullDate: record.date, - views: record.total_views, - clicks: record.total_clicks, - registrations: record.total_registrations, - eventsCreated: record.events_created, - eventsPublished: record.events_published, - hackathonsCreated: record.hackathons_created, - hackathonsPublished: record.hackathons_published, - })) + // Calculate scaling factor to adjust historical data to match current reality + const analyticsHistoricalTotal = analytics.reduce((sum, record) => sum + record.total_views, 0) + const actualCurrentTotal = actualStats?.views ?? analyticsHistoricalTotal + + const analyticsHistoricalClicks = analytics.reduce((sum, record) => sum + record.total_clicks, 0) + const actualCurrentClicks = actualStats?.clicks ?? analyticsHistoricalClicks + + // Transform analytics data for charts with proportional distribution + // First pass: calculate proportions and floor values + const chartDataWithRemainder = analytics.map((record) => { + const viewsProportion = analyticsHistoricalTotal > 0 ? (record.total_views / analyticsHistoricalTotal) * actualCurrentTotal : 0 + const clicksProportion = analyticsHistoricalClicks > 0 ? (record.total_clicks / analyticsHistoricalClicks) * actualCurrentClicks : 0 + + return { + date: format(new Date(record.date), 'MMM dd'), + fullDate: record.date, + views: Math.floor(viewsProportion), + viewsRemainder: viewsProportion - Math.floor(viewsProportion), + clicks: Math.floor(clicksProportion), + clicksRemainder: clicksProportion - Math.floor(clicksProportion), + registrations: record.total_registrations, + eventsCreated: record.events_created, + eventsPublished: record.events_published, + hackathonsCreated: record.hackathons_created, + hackathonsPublished: record.hackathons_published, + } + }) + + // Second pass: distribute remaining views to days with highest remainders + const totalFlooredViews = chartDataWithRemainder.reduce((sum, d) => sum + d.views, 0) + const viewsToDistribute = actualCurrentTotal - totalFlooredViews + + const totalFlooredClicks = chartDataWithRemainder.reduce((sum, d) => sum + d.clicks, 0) + const clicksToDistribute = actualCurrentClicks - totalFlooredClicks + + // Sort by remainder and add 1 to top N days + const sortedByViewsRemainder = [...chartDataWithRemainder].sort((a, b) => b.viewsRemainder - a.viewsRemainder) + for (let i = 0; i < viewsToDistribute && i < sortedByViewsRemainder.length; i++) { + const index = chartDataWithRemainder.indexOf(sortedByViewsRemainder[i]) + chartDataWithRemainder[index].views += 1 + } + + const sortedByClicksRemainder = [...chartDataWithRemainder].sort((a, b) => b.clicksRemainder - a.clicksRemainder) + for (let i = 0; i < clicksToDistribute && i < sortedByClicksRemainder.length; i++) { + const index = chartDataWithRemainder.indexOf(sortedByClicksRemainder[i]) + chartDataWithRemainder[index].clicks += 1 + } + + // Final chart data without remainder fields + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const chartData = chartDataWithRemainder.map(({ viewsRemainder, clicksRemainder, ...rest }) => rest) // Calculate totals from analytics (for published counts) const analyticsTotals = analytics.reduce( From 9a0c5901bf5eafb0c8c7dc019dd4d5d20dad1dc5 Mon Sep 17 00:00:00 2001 From: Akshay Date: Tue, 18 Nov 2025 16:27:39 +0530 Subject: [PATCH 5/5] feat(hackathons): Add metadata to registration and create cleanup script - Add hackathon metadata (id, slug, title) to master_registrations table during registration - Include note clarifying integer to string conversion for activity_id - Create delete-test-company.js script for cleaning up test data - Script handles cascading deletion of events, hackathons, registrations, and analytics - Improves data tracking and provides utility for development/testing cleanup --- app/api/hackathons/[id]/register/route.ts | 6 + delete-test-company.js | 232 ++++++++++++++++++++++ 2 files changed, 238 insertions(+) create mode 100644 delete-test-company.js diff --git a/app/api/hackathons/[id]/register/route.ts b/app/api/hackathons/[id]/register/route.ts index 021a97b1..9a982f5b 100644 --- a/app/api/hackathons/[id]/register/route.ts +++ b/app/api/hackathons/[id]/register/route.ts @@ -82,6 +82,7 @@ export async function POST( const fullName = profile ? `${profile.first_name || ''} ${profile.last_name || ''}`.trim() : '' // Register user in master_registrations table + // Note: hackathon.id is an integer, convert to string for activity_id const { error: registrationError } = await supabase .from('master_registrations') .insert({ @@ -92,6 +93,11 @@ export async function POST( full_name: fullName || undefined, email: profile?.email || user.email, phone: profile?.phone || undefined, + metadata: { + hackathon_id: hackathon.id, + hackathon_slug: hackathon.slug, + hackathon_title: hackathon.title + } }) if (registrationError) { diff --git a/delete-test-company.js b/delete-test-company.js new file mode 100644 index 00000000..746c1384 --- /dev/null +++ b/delete-test-company.js @@ -0,0 +1,232 @@ +const { createClient } = require('@supabase/supabase-js') + +const supabaseUrl = 'https://ocnorlktyfswjqgvzrve.supabase.co' +const supabaseKey = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im9jbm9ybGt0eWZzd2pxZ3Z6cnZlIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTc1MDQzNTY4NSwiZXhwIjoyMDY2MDExNjg1fQ.QP6L8TLHMk5dreFc_OTdeLzk-adB90WL9LSlmQgoRCs' + +const supabase = createClient(supabaseUrl, supabaseKey) + +async function deleteTestCompany() { + const companySlug = 'vertex-digital-solutions' + + console.log('='.repeat(80)) + console.log('DELETING TEST COMPANY: Vertex Digital Solutions') + console.log('='.repeat(80)) + console.log() + + try { + // First, get the company to confirm it exists + const { data: company, error: fetchError } = await supabase + .from('companies') + .select('id, name, slug') + .eq('slug', companySlug) + .single() + + if (fetchError || !company) { + console.log('❌ Company not found or already deleted') + return + } + + console.log('Found company:') + console.log(`- ID: ${company.id}`) + console.log(`- Name: ${company.name}`) + console.log(`- Slug: ${company.slug}`) + console.log() + + // Get counts before deletion + const { count: eventsCount } = await supabase + .from('events') + .select('*', { count: 'exact', head: true }) + .eq('company_id', company.id) + + const { count: hackathonsCount } = await supabase + .from('hackathons') + .select('*', { count: 'exact', head: true }) + .eq('company_id', company.id) + + const { count: membersCount } = await supabase + .from('company_members') + .select('*', { count: 'exact', head: true }) + .eq('company_id', company.id) + + const { count: analyticsCount } = await supabase + .from('company_analytics') + .select('*', { count: 'exact', head: true }) + .eq('company_id', company.id) + + console.log('Data to be deleted:') + console.log(`- Events: ${eventsCount || 0}`) + console.log(`- Hackathons: ${hackathonsCount || 0}`) + console.log(`- Members: ${membersCount || 0}`) + console.log(`- Analytics Records: ${analyticsCount || 0}`) + console.log() + + console.log('⚠️ WARNING: This will permanently delete all data!') + console.log('Press Ctrl+C within 5 seconds to cancel...') + console.log() + + // Wait 5 seconds + await new Promise(resolve => setTimeout(resolve, 5000)) + + console.log('Proceeding with deletion...') + console.log() + + // Step 1: Get all events and hackathons IDs + const { data: events } = await supabase + .from('events') + .select('id') + .eq('company_id', company.id) + + const { data: hackathons } = await supabase + .from('hackathons') + .select('id') + .eq('company_id', company.id) + + const eventIds = events?.map(e => e.id) || [] + const hackathonIds = hackathons?.map(h => h.id) || [] + + // Step 2: Delete event registrations + if (eventIds.length > 0) { + console.log('Step 1: Deleting event registrations...') + const { error: eventRegsError } = await supabase + .from('event_registrations') + .delete() + .in('event_id', eventIds) + + if (eventRegsError && eventRegsError.code !== 'PGRST116') { + console.error('Warning: Error deleting event registrations:', eventRegsError) + } else { + console.log('✓ Event registrations deleted') + } + } + + // Step 3: Delete hackathon registrations + if (hackathonIds.length > 0) { + console.log('Step 2: Deleting hackathon registrations...') + const { error: hackRegsError } = await supabase + .from('hackathon_registrations') + .delete() + .in('hackathon_id', hackathonIds) + + if (hackRegsError && hackRegsError.code !== 'PGRST116') { + console.error('Warning: Error deleting hackathon registrations:', hackRegsError) + } else { + console.log('✓ Hackathon registrations deleted') + } + } + + // Step 4: Delete event_audit_log records + console.log('Step 3: Deleting event audit logs...') + const { error: auditError } = await supabase + .from('event_audit_log') + .delete() + .eq('company_id', company.id) + + if (auditError && auditError.code !== 'PGRST116') { + console.error('Warning: Error deleting audit logs:', auditError) + } else { + console.log('✓ Audit logs deleted') + } + + // Step 5: Delete event_moderation_log records + console.log('Step 4: Deleting moderation logs...') + const { error: moderationError } = await supabase + .from('event_moderation_log') + .delete() + .eq('company_id', company.id) + + if (moderationError && moderationError.code !== 'PGRST116') { + console.error('Warning: Error deleting moderation logs:', moderationError) + } else { + console.log('✓ Moderation logs deleted') + } + + // Step 6: Delete events + if (eventIds.length > 0) { + console.log('Step 5: Deleting events...') + const { error: eventsError } = await supabase + .from('events') + .delete() + .eq('company_id', company.id) + + if (eventsError) { + console.error('❌ Error deleting events:', eventsError) + return + } + console.log('✓ Events deleted') + } + + // Step 7: Delete hackathons + if (hackathonIds.length > 0) { + console.log('Step 6: Deleting hackathons...') + const { error: hackathonsError } = await supabase + .from('hackathons') + .delete() + .eq('company_id', company.id) + + if (hackathonsError) { + console.error('❌ Error deleting hackathons:', hackathonsError) + return + } + console.log('✓ Hackathons deleted') + } + + // Step 8: Delete company analytics + console.log('Step 7: Deleting analytics...') + const { error: analyticsError } = await supabase + .from('company_analytics') + .delete() + .eq('company_id', company.id) + + if (analyticsError && analyticsError.code !== 'PGRST116') { + console.error('Warning: Error deleting analytics:', analyticsError) + } else { + console.log('✓ Analytics deleted') + } + + // Step 9: Delete company members + console.log('Step 8: Deleting company members...') + const { error: membersError } = await supabase + .from('company_members') + .delete() + .eq('company_id', company.id) + + if (membersError) { + console.error('❌ Error deleting members:', membersError) + return + } + console.log('✓ Company members deleted') + + // Step 10: Finally delete the company + console.log('Step 9: Deleting company...') + const { error: deleteError } = await supabase + .from('companies') + .delete() + .eq('id', company.id) + + if (deleteError) { + console.error('❌ Error deleting company:', deleteError) + return + } + console.log('✓ Company deleted') + + console.log('✅ Successfully deleted Vertex Digital Solutions!') + console.log() + console.log('All related data has been removed:') + console.log('- Company record') + console.log('- All events') + console.log('- All hackathons') + console.log('- All company members') + console.log('- All analytics records') + console.log('- All moderation logs') + console.log('- All audit logs') + console.log() + console.log('='.repeat(80)) + console.log('You can now create a fresh company with clean data!') + console.log('='.repeat(80)) + + } catch (error) { + console.error('❌ Unexpected error:', error) + } +} + +deleteTestCompany().catch(console.error)