Skip to content

Commit a98616a

Browse files
authored
Merge pull request #64 from codeunia-dev/backend/events
Refactor EventsPage and EventDetailPage to utilize custom hooks
2 parents 1de8f45 + 4d15e61 commit a98616a

File tree

7 files changed

+729
-56
lines changed

7 files changed

+729
-56
lines changed

app/api/events/[slug]/route.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { NextRequest, NextResponse } from 'next/server'
2+
import { eventsService } from '@/lib/services/events'
3+
4+
// GET: Fetch a single event by slug
5+
export async function GET(request: NextRequest) {
6+
try {
7+
const { pathname } = request.nextUrl
8+
const slug = pathname.split('/').pop() || ''
9+
const event = await eventsService.getEventBySlug(slug)
10+
11+
if (!event) {
12+
return NextResponse.json(
13+
{ error: 'Event not found' },
14+
{ status: 404 }
15+
)
16+
}
17+
18+
return NextResponse.json(event)
19+
} catch (error) {
20+
console.error('Error in GET /api/events/[slug]:', error)
21+
return NextResponse.json(
22+
{ error: 'Failed to fetch event' },
23+
{ status: 500 }
24+
)
25+
}
26+
}
27+
28+
// PUT: Update an event
29+
export async function PUT(request: NextRequest) {
30+
try {
31+
const { pathname } = request.nextUrl
32+
const slug = pathname.split('/').pop() || ''
33+
const eventData = await request.json()
34+
35+
const event = await eventsService.updateEvent(slug, eventData)
36+
37+
return NextResponse.json(event)
38+
} catch (error) {
39+
console.error('Error in PUT /api/events/[slug]:', error)
40+
return NextResponse.json(
41+
{ error: 'Failed to update event' },
42+
{ status: 500 }
43+
)
44+
}
45+
}
46+
47+
// DELETE: Delete an event
48+
export async function DELETE(request: NextRequest) {
49+
try {
50+
const { pathname } = request.nextUrl
51+
const slug = pathname.split('/').pop() || ''
52+
await eventsService.deleteEvent(slug)
53+
54+
return NextResponse.json({ message: 'Event deleted successfully' })
55+
} catch (error) {
56+
console.error('Error in DELETE /api/events/[slug]:', error)
57+
return NextResponse.json(
58+
{ error: 'Failed to delete event' },
59+
{ status: 500 }
60+
)
61+
}
62+
}

app/api/events/featured/route.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { NextRequest, NextResponse } from 'next/server'
2+
import { eventsService } from '@/lib/services/events'
3+
4+
// GET: Fetch featured events
5+
export async function GET(request: NextRequest) {
6+
try {
7+
const { searchParams } = new URL(request.url)
8+
const limit = searchParams.get('limit') ? parseInt(searchParams.get('limit')!) : 5
9+
10+
const events = await eventsService.getFeaturedEvents(limit)
11+
12+
return NextResponse.json({ events })
13+
} catch (error) {
14+
console.error('Error in GET /api/events/featured:', error)
15+
return NextResponse.json(
16+
{ error: 'Failed to fetch featured events' },
17+
{ status: 500 }
18+
)
19+
}
20+
}

app/api/events/route.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { NextRequest, NextResponse } from 'next/server'
2+
import { eventsService, EventsFilters } from '@/lib/services/events'
3+
4+
// GET: Fetch events with optional filters
5+
export async function GET(request: NextRequest) {
6+
try {
7+
const { searchParams } = new URL(request.url)
8+
9+
const filters: EventsFilters = {
10+
search: searchParams.get('search') || undefined,
11+
category: searchParams.get('category') || undefined,
12+
status: searchParams.get('status') || undefined,
13+
featured: searchParams.get('featured') === 'true' ? true :
14+
searchParams.get('featured') === 'false' ? false : undefined,
15+
dateFilter: searchParams.get('dateFilter') as EventsFilters['dateFilter'] || undefined,
16+
limit: searchParams.get('limit') ? parseInt(searchParams.get('limit')!) : undefined,
17+
offset: searchParams.get('offset') ? parseInt(searchParams.get('offset')!) : undefined,
18+
}
19+
20+
const result = await eventsService.getEvents(filters)
21+
22+
return NextResponse.json(result)
23+
} catch (error) {
24+
console.error('Error in GET /api/events:', error)
25+
return NextResponse.json(
26+
{ error: 'Failed to fetch events' },
27+
{ status: 500 }
28+
)
29+
}
30+
}
31+
32+
// POST: Create a new event
33+
export async function POST(request: NextRequest) {
34+
try {
35+
const eventData = await request.json()
36+
37+
// Validate required fields
38+
const requiredFields = ['slug', 'title', 'excerpt', 'description', 'organizer', 'date', 'time', 'duration', 'category', 'location', 'capacity', 'price', 'payment']
39+
for (const field of requiredFields) {
40+
if (!eventData[field]) {
41+
return NextResponse.json(
42+
{ error: `Missing required field: ${field}` },
43+
{ status: 400 }
44+
)
45+
}
46+
}
47+
48+
const event = await eventsService.createEvent(eventData)
49+
50+
return NextResponse.json(event, { status: 201 })
51+
} catch (error) {
52+
console.error('Error in POST /api/events:', error)
53+
return NextResponse.json(
54+
{ error: 'Failed to create event' },
55+
{ status: 500 }
56+
)
57+
}
58+
}

app/events/[id]/page.tsx

Lines changed: 4 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ import { Badge } from "@/components/ui/badge"
88
import { ArrowLeft, Clock, Calendar, Users, DollarSign, Star, Sparkles} from "lucide-react"
99
import Link from "next/link"
1010
import { motion } from "framer-motion"
11-
import { Event, mockEvents } from "@/components/data/events"
1211
import Image from "next/image";
1312
import { Tabs as AnimatedTabs } from "@/components/ui/tabs";
1413
import React from "react";
14+
import { useEvent } from "@/hooks/useEvents"
1515

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

6868
export default function EventDetailPage() {
6969
const [isAuthenticated, setIsAuthenticated] = useState(false)
70-
const [isLoading, setIsLoading] = useState(true)
71-
const [event, setEvent] = useState<Event | null>(null)
72-
const [fetchError, setFetchError] = useState<string | null>(null)
7370
const params = useParams()
7471

7572
const slug = params?.id as string
7673

74+
// Use custom hook for fetching event
75+
const { event, loading: isLoading, error: fetchError } = useEvent(slug)
76+
7777
useEffect(() => {
7878
const checkAuth = async () => {
7979
const supabase = createClient()
@@ -83,32 +83,6 @@ export default function EventDetailPage() {
8383
checkAuth()
8484
}, [])
8585

86-
useEffect(() => {
87-
const fetchEvent = async () => {
88-
setIsLoading(true)
89-
setFetchError(null)
90-
91-
// For now, using mock data since events table doesn't exist yet
92-
// In a real app, this would fetch from Supabase
93-
try {
94-
// Simulate API delay
95-
await new Promise(resolve => setTimeout(resolve, 1000))
96-
const foundEvent = mockEvents.find(e => e.slug === slug)
97-
if (foundEvent) {
98-
setEvent(foundEvent)
99-
} else {
100-
setFetchError('Event not found.')
101-
setEvent(null)
102-
}
103-
} catch {
104-
setFetchError('Failed to fetch event.')
105-
setEvent(null)
106-
}
107-
setIsLoading(false)
108-
}
109-
if (slug) fetchEvent()
110-
}, [slug])
111-
11286
const getCategoryColor = (category: string) => {
11387
switch (category) {
11488
case "Hackathons":

app/events/page.tsx

Lines changed: 22 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { Input } from "@/components/ui/input"
99
import { Search, Clock, ArrowRight, Calendar, Star, Users, MapPin, DollarSign, Filter, Link as LinkIcon, Sparkles } from "lucide-react"
1010
import Link from "next/link"
1111
import { motion } from "framer-motion"
12-
import { mockEvents, Event } from "@/components/data/events"
12+
import { Event } from "@/components/data/events"
1313
import Header from "@/components/header";
1414
import Footer from "@/components/footer";
1515
import Image from "next/image";
@@ -18,6 +18,7 @@ import { Checkbox } from "@/components/ui/checkbox"
1818
import "keen-slider/keen-slider.min.css"
1919
import { useKeenSlider } from "keen-slider/react"
2020
import { cn } from "@/lib/utils";
21+
import { useEvents, useFeaturedEvents } from "@/hooks/useEvents"
2122

2223
// Event categories for dropdown
2324
const eventCategories = [
@@ -35,8 +36,6 @@ const eventCategories = [
3536

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

51+
// Use custom hooks for data fetching
52+
const { data: eventsData, loading: eventsLoading } = useEvents({
53+
search: searchTerm,
54+
category: selectedCategory,
55+
dateFilter: dateFilter === "Upcoming" ? "upcoming" : "all"
56+
})
57+
58+
const { loading: featuredLoading } = useFeaturedEvents(5)
59+
60+
// Extract events from the response
61+
const events = eventsData?.events || []
62+
const isLoading = eventsLoading || featuredLoading
63+
5264
// Unique values for filters
5365
const allStatuses = ["Live", "Expired", "Closed", "Recent"]
5466
const allLocations = Array.from(new Set(events.flatMap(e => e.locations))).sort()
@@ -85,7 +97,7 @@ export default function EventsPage() {
8597
return matchesSearch && matchesStatus && matchesLocation && matchesEventType && matchesTeamSize && matchesPayment && matchesUserType && matchesCategory && matchesDate && matchesDropdownCategory
8698
})
8799

88-
const featuredEvents = filteredEvents.filter((event) => event.featured)
100+
const filteredFeaturedEvents = filteredEvents.filter((event) => event.featured)
89101
const regularEvents = filteredEvents.filter((event) => !event.featured)
90102

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

103115
// Autoplay effect
104116
useEffect(() => {
105117
if (!slider) return
106-
if (featuredEvents.length > 1) {
118+
if (filteredFeaturedEvents.length > 1) {
107119
const autoplay = () => {
108120
slider.current?.next()
109121
}
@@ -127,25 +139,9 @@ export default function EventsPage() {
127139
// If less than 2, clear any existing interval
128140
if (sliderTimer.current) clearInterval(sliderTimer.current)
129141
}
130-
}, [slider, featuredEvents.length])
142+
}, [slider, filteredFeaturedEvents.length])
143+
131144

132-
useEffect(() => {
133-
const fetchEvents = async () => {
134-
setIsLoading(true)
135-
136-
// For now, using mock data since events table doesn't exist yet
137-
// In a real app, this would fetch from Supabase
138-
try {
139-
// Simulate API delay
140-
await new Promise(resolve => setTimeout(resolve, 1000))
141-
setEvents(mockEvents)
142-
} catch {
143-
setEvents([])
144-
}
145-
setIsLoading(false)
146-
}
147-
fetchEvents()
148-
}, [])
149145

150146
// Date filter logic
151147
function isDateMatch(event: Event) {
@@ -525,7 +521,7 @@ export default function EventsPage() {
525521
</section>
526522

527523
{/* Featured Events - Redesigned */}
528-
{featuredEvents.length > 0 && (
524+
{filteredFeaturedEvents.length > 0 && (
529525
<section className="py-16 relative">
530526
<div className="container px-4 mx-auto relative">
531527
<motion.div
@@ -593,7 +589,7 @@ export default function EventsPage() {
593589
}}
594590
className="keen-slider"
595591
>
596-
{(featuredEvents.length > 2 ? [...featuredEvents, ...featuredEvents] : featuredEvents).map((event, index) => (
592+
{(filteredFeaturedEvents.length > 2 ? [...filteredFeaturedEvents, ...filteredFeaturedEvents] : filteredFeaturedEvents).map((event, index) => (
597593
<motion.div
598594
key={event.id + '-' + index}
599595
className="keen-slider__slide"

0 commit comments

Comments
 (0)