Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions app/api/events/[slug]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { NextRequest, NextResponse } from 'next/server'
import { eventsService } from '@/lib/services/events'

// GET: Fetch a single event by slug
export async function GET(request: NextRequest) {
try {
const { pathname } = request.nextUrl
const slug = pathname.split('/').pop() || ''
const event = await eventsService.getEventBySlug(slug)

if (!event) {
return NextResponse.json(
{ error: 'Event not found' },
{ status: 404 }
)
}

return NextResponse.json(event)
} catch (error) {
console.error('Error in GET /api/events/[slug]:', error)
return NextResponse.json(
{ error: 'Failed to fetch event' },
{ status: 500 }
)
}
}

// PUT: Update an event
export async function PUT(request: NextRequest) {
try {
const { pathname } = request.nextUrl
const slug = pathname.split('/').pop() || ''
const eventData = await request.json()

const event = await eventsService.updateEvent(slug, eventData)

return NextResponse.json(event)
} catch (error) {
console.error('Error in PUT /api/events/[slug]:', error)
return NextResponse.json(
{ error: 'Failed to update event' },
{ status: 500 }
)
}
}

// DELETE: Delete an event
export async function DELETE(request: NextRequest) {
try {
const { pathname } = request.nextUrl
const slug = pathname.split('/').pop() || ''
await eventsService.deleteEvent(slug)

return NextResponse.json({ message: 'Event deleted successfully' })
} catch (error) {
console.error('Error in DELETE /api/events/[slug]:', error)
return NextResponse.json(
{ error: 'Failed to delete event' },
{ status: 500 }
)
}
}
20 changes: 20 additions & 0 deletions app/api/events/featured/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { NextRequest, NextResponse } from 'next/server'
import { eventsService } from '@/lib/services/events'

// GET: Fetch featured events
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url)
const limit = searchParams.get('limit') ? parseInt(searchParams.get('limit')!) : 5

const events = await eventsService.getFeaturedEvents(limit)

return NextResponse.json({ events })
} catch (error) {
console.error('Error in GET /api/events/featured:', error)
return NextResponse.json(
{ error: 'Failed to fetch featured events' },
{ status: 500 }
)
}
}
58 changes: 58 additions & 0 deletions app/api/events/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { NextRequest, NextResponse } from 'next/server'
import { eventsService, EventsFilters } from '@/lib/services/events'

// GET: Fetch events with optional filters
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url)

const filters: EventsFilters = {
search: searchParams.get('search') || undefined,
category: searchParams.get('category') || undefined,
status: searchParams.get('status') || undefined,
featured: searchParams.get('featured') === 'true' ? true :
searchParams.get('featured') === 'false' ? false : undefined,
dateFilter: searchParams.get('dateFilter') as EventsFilters['dateFilter'] || undefined,
limit: searchParams.get('limit') ? parseInt(searchParams.get('limit')!) : undefined,
offset: searchParams.get('offset') ? parseInt(searchParams.get('offset')!) : undefined,
}

const result = await eventsService.getEvents(filters)

return NextResponse.json(result)
} catch (error) {
console.error('Error in GET /api/events:', error)
return NextResponse.json(
{ error: 'Failed to fetch events' },
{ status: 500 }
)
}
}

// POST: Create a new event
export async function POST(request: NextRequest) {
try {
const eventData = await request.json()

// Validate required fields
const requiredFields = ['slug', 'title', 'excerpt', 'description', 'organizer', 'date', 'time', 'duration', 'category', 'location', 'capacity', 'price', 'payment']
for (const field of requiredFields) {
if (!eventData[field]) {
return NextResponse.json(
{ error: `Missing required field: ${field}` },
{ status: 400 }
)
}
}

const event = await eventsService.createEvent(eventData)

return NextResponse.json(event, { status: 201 })
} catch (error) {
console.error('Error in POST /api/events:', error)
return NextResponse.json(
{ error: 'Failed to create event' },
{ status: 500 }
)
}
}
34 changes: 4 additions & 30 deletions app/events/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import { Badge } from "@/components/ui/badge"
import { ArrowLeft, Clock, Calendar, Users, DollarSign, Star, Sparkles} from "lucide-react"
import Link from "next/link"
import { motion } from "framer-motion"
import { Event, mockEvents } from "@/components/data/events"
import Image from "next/image";
import { Tabs as AnimatedTabs } from "@/components/ui/tabs";
import React from "react";
import { useEvent } from "@/hooks/useEvents"

// import Header from "@/components/header";
import Footer from "@/components/footer";
Expand Down Expand Up @@ -67,13 +67,13 @@ const RotatingSponsorsGrid = ({ sponsors }: { sponsors?: Sponsor[] }) => {

export default function EventDetailPage() {
const [isAuthenticated, setIsAuthenticated] = useState(false)
const [isLoading, setIsLoading] = useState(true)
const [event, setEvent] = useState<Event | null>(null)
const [fetchError, setFetchError] = useState<string | null>(null)
const params = useParams()

const slug = params?.id as string

// Use custom hook for fetching event
const { event, loading: isLoading, error: fetchError } = useEvent(slug)

useEffect(() => {
const checkAuth = async () => {
const supabase = createClient()
Expand All @@ -83,32 +83,6 @@ export default function EventDetailPage() {
checkAuth()
}, [])

useEffect(() => {
const fetchEvent = async () => {
setIsLoading(true)
setFetchError(null)

// For now, using mock data since events table doesn't exist yet
// In a real app, this would fetch from Supabase
try {
// Simulate API delay
await new Promise(resolve => setTimeout(resolve, 1000))
const foundEvent = mockEvents.find(e => e.slug === slug)
if (foundEvent) {
setEvent(foundEvent)
} else {
setFetchError('Event not found.')
setEvent(null)
}
} catch {
setFetchError('Failed to fetch event.')
setEvent(null)
}
setIsLoading(false)
}
if (slug) fetchEvent()
}, [slug])

const getCategoryColor = (category: string) => {
switch (category) {
case "Hackathons":
Expand Down
48 changes: 22 additions & 26 deletions app/events/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { Input } from "@/components/ui/input"
import { Search, Clock, ArrowRight, Calendar, Star, Users, MapPin, DollarSign, Filter, Link as LinkIcon, Sparkles } from "lucide-react"
import Link from "next/link"
import { motion } from "framer-motion"
import { mockEvents, Event } from "@/components/data/events"
import { Event } from "@/components/data/events"
import Header from "@/components/header";
import Footer from "@/components/footer";
import Image from "next/image";
Expand All @@ -18,6 +18,7 @@ import { Checkbox } from "@/components/ui/checkbox"
import "keen-slider/keen-slider.min.css"
import { useKeenSlider } from "keen-slider/react"
import { cn } from "@/lib/utils";
import { useEvents, useFeaturedEvents } from "@/hooks/useEvents"

// Event categories for dropdown
const eventCategories = [
Expand All @@ -35,8 +36,6 @@ const eventCategories = [

export default function EventsPage() {
const [searchTerm, setSearchTerm] = useState("")
const [isLoading, setIsLoading] = useState(true)
const [events, setEvents] = useState<Event[]>([])
const [dateFilter] = useState("Upcoming")
const [filterOpen, setFilterOpen] = useState(false)
const [selectedStatuses, setSelectedStatuses] = useState<string[]>([])
Expand All @@ -49,6 +48,19 @@ export default function EventsPage() {
const [selectedCategory, setSelectedCategory] = useState<string>("All")
const [copiedEventId, setCopiedEventId] = useState<string | null>(null)

// Use custom hooks for data fetching
const { data: eventsData, loading: eventsLoading } = useEvents({
search: searchTerm,
category: selectedCategory,
dateFilter: dateFilter === "Upcoming" ? "upcoming" : "all"
})

const { loading: featuredLoading } = useFeaturedEvents(5)

// Extract events from the response
const events = eventsData?.events || []
const isLoading = eventsLoading || featuredLoading

// Unique values for filters
const allStatuses = ["Live", "Expired", "Closed", "Recent"]
const allLocations = Array.from(new Set(events.flatMap(e => e.locations))).sort()
Expand Down Expand Up @@ -85,7 +97,7 @@ export default function EventsPage() {
return matchesSearch && matchesStatus && matchesLocation && matchesEventType && matchesTeamSize && matchesPayment && matchesUserType && matchesCategory && matchesDate && matchesDropdownCategory
})

const featuredEvents = filteredEvents.filter((event) => event.featured)
const filteredFeaturedEvents = filteredEvents.filter((event) => event.featured)
const regularEvents = filteredEvents.filter((event) => !event.featured)

// Add keen-slider hook for featured events with autoplay and navigation
Expand All @@ -97,13 +109,13 @@ export default function EventsPage() {
"(min-width: 640px)": { slides: { perView: 1.5, spacing: 24 } },
"(min-width: 1024px)": { slides: { perView: 2.2, spacing: 32 } },
},
loop: featuredEvents.length > 1,
loop: filteredFeaturedEvents.length > 1,
})

// Autoplay effect
useEffect(() => {
if (!slider) return
if (featuredEvents.length > 1) {
if (filteredFeaturedEvents.length > 1) {
const autoplay = () => {
slider.current?.next()
}
Expand All @@ -127,25 +139,9 @@ export default function EventsPage() {
// If less than 2, clear any existing interval
if (sliderTimer.current) clearInterval(sliderTimer.current)
}
}, [slider, featuredEvents.length])
}, [slider, filteredFeaturedEvents.length])


useEffect(() => {
const fetchEvents = async () => {
setIsLoading(true)

// For now, using mock data since events table doesn't exist yet
// In a real app, this would fetch from Supabase
try {
// Simulate API delay
await new Promise(resolve => setTimeout(resolve, 1000))
setEvents(mockEvents)
} catch {
setEvents([])
}
setIsLoading(false)
}
fetchEvents()
}, [])

// Date filter logic
function isDateMatch(event: Event) {
Expand Down Expand Up @@ -525,7 +521,7 @@ export default function EventsPage() {
</section>

{/* Featured Events - Redesigned */}
{featuredEvents.length > 0 && (
{filteredFeaturedEvents.length > 0 && (
<section className="py-16 relative">
<div className="container px-4 mx-auto relative">
<motion.div
Expand Down Expand Up @@ -593,7 +589,7 @@ export default function EventsPage() {
}}
className="keen-slider"
>
{(featuredEvents.length > 2 ? [...featuredEvents, ...featuredEvents] : featuredEvents).map((event, index) => (
{(filteredFeaturedEvents.length > 2 ? [...filteredFeaturedEvents, ...filteredFeaturedEvents] : filteredFeaturedEvents).map((event, index) => (
<motion.div
key={event.id + '-' + index}
className="keen-slider__slide"
Expand Down
Loading