diff --git a/app/api/hackathons/[id]/route.ts b/app/api/hackathons/[id]/route.ts index d5ca61f0..48e5112d 100644 --- a/app/api/hackathons/[id]/route.ts +++ b/app/api/hackathons/[id]/route.ts @@ -113,27 +113,35 @@ export async function DELETE(_request: NextRequest, { params }: RouteContext) { try { const { id } = await params + console.log('🗑️ DELETE request for hackathon:', id) + // Check authentication const supabase = await createClient() - const { data: { user } } = await supabase.auth.getUser() + const { data: { user }, error: authError } = await supabase.auth.getUser() - if (!user) { + if (authError || !user) { + console.error('❌ Authentication error:', authError) return NextResponse.json( { error: 'Unauthorized: Authentication required' }, { status: 401 } ) } + console.log('✅ User authenticated:', user.id) + // Get the existing hackathon to check company_id const existingHackathon = await hackathonsService.getHackathonBySlug(id) if (!existingHackathon) { + console.error('❌ Hackathon not found:', id) return NextResponse.json( { error: 'Hackathon not found' }, { status: 404 } ) } + console.log('✅ Hackathon found:', existingHackathon.id, existingHackathon.title) + let isAuthorized = false // Check if user is admin @@ -145,6 +153,7 @@ export async function DELETE(_request: NextRequest, { params }: RouteContext) { if (profile?.is_admin) { isAuthorized = true + console.log('✅ User is admin') } // If not admin, check if user is a member of the company @@ -159,23 +168,30 @@ export async function DELETE(_request: NextRequest, { params }: RouteContext) { if (membership) { isAuthorized = true + console.log('✅ User is company member with role:', membership.role) } } if (!isAuthorized) { + console.error('❌ User not authorized to delete hackathon') return NextResponse.json( { error: 'Unauthorized: You must be a company member or admin to delete this hackathon' }, - { status: 401 } + { status: 403 } ) } + console.log('🗑️ Attempting to delete hackathon...') await hackathonsService.deleteHackathon(id) + console.log('✅ Hackathon deleted successfully') - return NextResponse.json({ message: 'Hackathon deleted successfully' }) + return NextResponse.json({ + success: true, + message: 'Hackathon deleted successfully' + }) } catch (error) { - console.error('Error in DELETE /api/hackathons/[id]:', error) + console.error('❌ Error in DELETE /api/hackathons/[id]:', error) return NextResponse.json( - { error: 'Failed to delete hackathon' }, + { error: error instanceof Error ? error.message : 'Failed to delete hackathon' }, { status: 500 } ) } diff --git a/app/dashboard/company/[slug]/hackathons/page.tsx b/app/dashboard/company/[slug]/hackathons/page.tsx index 049861e0..d4016773 100644 --- a/app/dashboard/company/[slug]/hackathons/page.tsx +++ b/app/dashboard/company/[slug]/hackathons/page.tsx @@ -8,9 +8,19 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/com import { Badge } from '@/components/ui/badge' import { Input } from '@/components/ui/input' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table' -import { Trophy, Search, Plus, Edit, Eye, Clock, CheckCircle, XCircle, AlertCircle } from 'lucide-react' +import { Trophy, Search, Plus, Edit, Eye, Clock, CheckCircle, XCircle, AlertCircle, Trash2 } from 'lucide-react' import { toast } from 'sonner' import Link from 'next/link' +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, +} from '@/components/ui/alert-dialog' interface Hackathon { id: string @@ -34,6 +44,9 @@ export default function CompanyHackathonsPage() { const [hackathons, setHackathons] = useState([]) const [loading, setLoading] = useState(true) const [searchTerm, setSearchTerm] = useState('') + const [deleteDialogOpen, setDeleteDialogOpen] = useState(false) + const [hackathonToDelete, setHackathonToDelete] = useState(null) + const [isDeleting, setIsDeleting] = useState(false) const canManageEvents = userRole && ['owner', 'admin', 'editor'].includes(userRole) @@ -65,6 +78,40 @@ export default function CompanyHackathonsPage() { } }, [currentCompany, fetchHackathons]) + const handleDeleteClick = (hackathon: Hackathon) => { + setHackathonToDelete(hackathon) + setDeleteDialogOpen(true) + } + + const handleDeleteConfirm = async () => { + if (!hackathonToDelete || !currentCompany) return + + try { + setIsDeleting(true) + // Use slug instead of id for the API endpoint + const response = await fetch(`/api/hackathons/${hackathonToDelete.slug}`, { + method: 'DELETE', + }) + + if (!response.ok) { + const errorData = await response.json() + throw new Error(errorData.error || 'Failed to delete hackathon') + } + + toast.success('Hackathon deleted successfully') + setDeleteDialogOpen(false) + setHackathonToDelete(null) + + // Refresh the list + fetchHackathons() + } catch (error) { + console.error('Error deleting hackathon:', error) + toast.error(error instanceof Error ? error.message : 'Failed to delete hackathon') + } finally { + setIsDeleting(false) + } + } + if (companyLoading || isPendingInvitation) { return (
@@ -287,17 +334,26 @@ export default function CompanyHackathonsPage() {
- {hackathon.approval_status === 'approved' && ( - )} +
) : ( @@ -318,6 +374,29 @@ export default function CompanyHackathonsPage() { )} + + {/* Delete Confirmation Dialog */} + + + + Are you sure? + + This will permanently delete the hackathon "{hackathonToDelete?.title}". + This action cannot be undone. + + + + Cancel + + {isDeleting ? 'Deleting...' : 'Delete'} + + + +
) } diff --git a/lib/services/hackathons.ts b/lib/services/hackathons.ts index 21005ef6..8eedba63 100644 --- a/lib/services/hackathons.ts +++ b/lib/services/hackathons.ts @@ -310,16 +310,26 @@ class HackathonsService { async deleteHackathon(slug: string) { const supabase = await createClient() - const { error } = await supabase + console.log('🗑️ Deleting hackathon with slug:', slug) + + const { data, error } = await supabase .from('hackathons') .delete() .eq('slug', slug) + .select() if (error) { - console.error('Error deleting hackathon:', error) - throw new Error('Failed to delete hackathon') + console.error('❌ Error deleting hackathon from database:', error) + throw new Error(`Failed to delete hackathon: ${error.message}`) } + if (!data || data.length === 0) { + console.warn('⚠️ No hackathon was deleted. Slug might not exist or RLS policy blocked deletion.') + throw new Error('Hackathon not found or you do not have permission to delete it') + } + + console.log('✅ Hackathon deleted from database:', data) + // Clear cache after deleting hackathon cache.clear() return true