Skip to content

Commit 1456f51

Browse files
authored
Merge pull request #65 from codeunia-dev/admin/events
Added events in admin
2 parents a98616a + d1e7ba4 commit 1456f51

File tree

6 files changed

+1191
-4
lines changed

6 files changed

+1191
-4
lines changed

app/admin/events/page.tsx

Lines changed: 755 additions & 0 deletions
Large diffs are not rendered by default.

app/api/admin/events/route.ts

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
import { NextRequest, NextResponse } from 'next/server'
2+
import { createClient } from '@supabase/supabase-js'
3+
4+
// Admin-only endpoint for event management
5+
export async function POST(request: NextRequest) {
6+
try {
7+
const eventData = await request.json()
8+
9+
// Use service role client for admin operations (bypasses RLS)
10+
const supabase = createClient(
11+
process.env.NEXT_PUBLIC_SUPABASE_URL!,
12+
process.env.SUPABASE_SERVICE_ROLE_KEY!
13+
)
14+
15+
// Validate required fields
16+
const requiredFields = ['slug', 'title', 'excerpt', 'description', 'organizer', 'date', 'time', 'duration', 'category', 'location', 'capacity', 'price', 'payment']
17+
for (const field of requiredFields) {
18+
if (!eventData[field]) {
19+
return NextResponse.json(
20+
{ error: `Missing required field: ${field}` },
21+
{ status: 400 }
22+
)
23+
}
24+
}
25+
26+
// Create event using service role client
27+
const { data, error } = await supabase
28+
.from('events')
29+
.insert([{
30+
slug: eventData.slug,
31+
title: eventData.title,
32+
excerpt: eventData.excerpt,
33+
description: eventData.description,
34+
organizer: eventData.organizer,
35+
organizer_contact: eventData.organizer_contact,
36+
date: eventData.date,
37+
time: eventData.time,
38+
duration: eventData.duration,
39+
category: eventData.category,
40+
categories: eventData.categories || [],
41+
tags: eventData.tags || [],
42+
featured: eventData.featured || false,
43+
image: eventData.image || '',
44+
location: eventData.location,
45+
locations: eventData.locations || [],
46+
capacity: eventData.capacity,
47+
registered: eventData.registered || 0,
48+
price: eventData.price,
49+
payment: eventData.payment,
50+
status: eventData.status || 'live',
51+
event_type: eventData.eventType || ['Online'],
52+
team_size: eventData.teamSize || 1,
53+
user_types: eventData.userTypes || [],
54+
registration_required: eventData.registration_required || false,
55+
registration_deadline: eventData.registration_deadline || '',
56+
rules: eventData.rules || [],
57+
schedule: eventData.schedule || [],
58+
prize: eventData.prize || '',
59+
prize_details: eventData.prize_details || '',
60+
faq: eventData.faq || [],
61+
socials: eventData.socials || {},
62+
sponsors: eventData.sponsors || [],
63+
marking_scheme: eventData.marking_scheme
64+
}])
65+
.select()
66+
.single()
67+
68+
if (error) {
69+
console.error('Error creating event:', error)
70+
return NextResponse.json(
71+
{ error: 'Failed to create event: ' + error.message },
72+
{ status: 500 }
73+
)
74+
}
75+
76+
return NextResponse.json(data, { status: 201 })
77+
} catch (error) {
78+
console.error('Error in POST /api/admin/events:', error)
79+
return NextResponse.json(
80+
{ error: 'Failed to create event' },
81+
{ status: 500 }
82+
)
83+
}
84+
}
85+
86+
// Update event
87+
export async function PUT(request: NextRequest) {
88+
try {
89+
const eventData = await request.json()
90+
const { slug, ...updateData } = eventData
91+
92+
if (!slug) {
93+
return NextResponse.json(
94+
{ error: 'Missing event slug' },
95+
{ status: 400 }
96+
)
97+
}
98+
99+
// Use service role client for admin operations (bypasses RLS)
100+
const supabase = createClient(
101+
process.env.NEXT_PUBLIC_SUPABASE_URL!,
102+
process.env.SUPABASE_SERVICE_ROLE_KEY!
103+
)
104+
105+
// Update event using service role client
106+
const { data, error } = await supabase
107+
.from('events')
108+
.update({
109+
title: updateData.title,
110+
excerpt: updateData.excerpt,
111+
description: updateData.description,
112+
organizer: updateData.organizer,
113+
organizer_contact: updateData.organizer_contact,
114+
date: updateData.date,
115+
time: updateData.time,
116+
duration: updateData.duration,
117+
category: updateData.category,
118+
categories: updateData.categories || [],
119+
tags: updateData.tags || [],
120+
featured: updateData.featured || false,
121+
image: updateData.image || '',
122+
location: updateData.location,
123+
locations: updateData.locations || [],
124+
capacity: updateData.capacity,
125+
registered: updateData.registered || 0,
126+
price: updateData.price,
127+
payment: updateData.payment,
128+
status: updateData.status || 'live',
129+
event_type: updateData.eventType || ['Online'],
130+
team_size: updateData.teamSize || 1,
131+
user_types: updateData.userTypes || [],
132+
registration_required: updateData.registration_required || false,
133+
registration_deadline: updateData.registration_deadline || '',
134+
rules: updateData.rules || [],
135+
schedule: updateData.schedule || [],
136+
prize: updateData.prize || '',
137+
prize_details: updateData.prize_details || '',
138+
faq: updateData.faq || [],
139+
socials: updateData.socials || {},
140+
sponsors: updateData.sponsors || [],
141+
marking_scheme: updateData.marking_scheme
142+
})
143+
.eq('slug', slug)
144+
.select()
145+
.single()
146+
147+
if (error) {
148+
console.error('Error updating event:', error)
149+
return NextResponse.json(
150+
{ error: 'Failed to update event: ' + error.message },
151+
{ status: 500 }
152+
)
153+
}
154+
155+
return NextResponse.json(data, { status: 200 })
156+
} catch (error) {
157+
console.error('Error in PUT /api/admin/events:', error)
158+
return NextResponse.json(
159+
{ error: 'Failed to update event' },
160+
{ status: 500 }
161+
)
162+
}
163+
}
164+
165+
// Delete event
166+
export async function DELETE(request: NextRequest) {
167+
try {
168+
const { slug } = await request.json()
169+
170+
if (!slug) {
171+
return NextResponse.json(
172+
{ error: 'Missing event slug' },
173+
{ status: 400 }
174+
)
175+
}
176+
177+
// Use service role client for admin operations (bypasses RLS)
178+
const supabase = createClient(
179+
process.env.NEXT_PUBLIC_SUPABASE_URL!,
180+
process.env.SUPABASE_SERVICE_ROLE_KEY!
181+
)
182+
183+
// Delete event using service role client
184+
const { error } = await supabase
185+
.from('events')
186+
.delete()
187+
.eq('slug', slug)
188+
189+
if (error) {
190+
console.error('Error deleting event:', error)
191+
return NextResponse.json(
192+
{ error: 'Failed to delete event: ' + error.message },
193+
{ status: 500 }
194+
)
195+
}
196+
197+
return NextResponse.json({ success: true }, { status: 200 })
198+
} catch (error) {
199+
console.error('Error in DELETE /api/admin/events:', error)
200+
return NextResponse.json(
201+
{ error: 'Failed to delete event' },
202+
{ status: 500 }
203+
)
204+
}
205+
}

app/api/events/route.ts

Lines changed: 78 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { NextRequest, NextResponse } from 'next/server'
22
import { eventsService, EventsFilters } from '@/lib/services/events'
3+
import { createClient } from '@/lib/supabase/server'
4+
import { createClient as createServiceClient } from '@supabase/supabase-js';
35

46
// GET: Fetch events with optional filters
57
export async function GET(request: NextRequest) {
@@ -34,6 +36,25 @@ export async function POST(request: NextRequest) {
3436
try {
3537
const eventData = await request.json()
3638

39+
// Check for admin authentication header or session
40+
const supabase = await createClient()
41+
const { data: { user } } = await supabase.auth.getUser()
42+
43+
let isAuthorized = false
44+
45+
// Check if user is authenticated and is admin
46+
if (user && user.user_metadata?.role === 'admin') {
47+
isAuthorized = true
48+
}
49+
50+
// If not authorized through session, check if it's a direct admin request
51+
if (!isAuthorized) {
52+
return NextResponse.json(
53+
{ error: 'Unauthorized: Admin access required' },
54+
{ status: 401 }
55+
)
56+
}
57+
3758
// Validate required fields
3859
const requiredFields = ['slug', 'title', 'excerpt', 'description', 'organizer', 'date', 'time', 'duration', 'category', 'location', 'capacity', 'price', 'payment']
3960
for (const field of requiredFields) {
@@ -45,14 +66,68 @@ export async function POST(request: NextRequest) {
4566
}
4667
}
4768

48-
const event = await eventsService.createEvent(eventData)
69+
// Use service role client for admin operations to bypass RLS
70+
const serviceSupabase = createServiceClient(
71+
process.env.NEXT_PUBLIC_SUPABASE_URL!,
72+
process.env.SUPABASE_SERVICE_ROLE_KEY!
73+
)
74+
75+
// Create event using service role client
76+
const { data, error } = await serviceSupabase
77+
.from('events')
78+
.insert([{
79+
slug: eventData.slug,
80+
title: eventData.title,
81+
excerpt: eventData.excerpt,
82+
description: eventData.description,
83+
organizer: eventData.organizer,
84+
organizer_contact: eventData.organizer_contact,
85+
date: eventData.date,
86+
time: eventData.time,
87+
duration: eventData.duration,
88+
category: eventData.category,
89+
categories: eventData.categories || [],
90+
tags: eventData.tags || [],
91+
featured: eventData.featured || false,
92+
image: eventData.image || '',
93+
location: eventData.location,
94+
locations: eventData.locations || [],
95+
capacity: eventData.capacity,
96+
registered: eventData.registered || 0,
97+
price: eventData.price,
98+
payment: eventData.payment,
99+
status: eventData.status || 'live',
100+
event_type: eventData.eventType || ['Online'],
101+
team_size: eventData.teamSize || 1,
102+
user_types: eventData.userTypes || [],
103+
registration_required: eventData.registration_required || false,
104+
registration_deadline: eventData.registration_deadline || '',
105+
rules: eventData.rules || [],
106+
schedule: eventData.schedule || [],
107+
prize: eventData.prize || '',
108+
prize_details: eventData.prize_details || '',
109+
faq: eventData.faq || [],
110+
socials: eventData.socials || {},
111+
sponsors: eventData.sponsors || [],
112+
marking_scheme: eventData.marking_scheme
113+
}])
114+
.select()
115+
.single()
49116

50-
return NextResponse.json(event, { status: 201 })
117+
if (error) {
118+
console.error('Error creating event:', error)
119+
return NextResponse.json(
120+
{ error: 'Failed to create event: ' + error.message },
121+
{ status: 500 }
122+
)
123+
}
124+
125+
return NextResponse.json(data, { status: 201 })
51126
} catch (error) {
52127
console.error('Error in POST /api/events:', error)
53128
return NextResponse.json(
54129
{ error: 'Failed to create event' },
55130
{ status: 500 }
56131
)
57132
}
58-
}
133+
}

0 commit comments

Comments
 (0)