From a387d3adb48a03032f982121f11cf0aeb53f57ef Mon Sep 17 00:00:00 2001 From: Riko Pernando Date: Sat, 26 Apr 2025 18:54:37 +0700 Subject: [PATCH 1/2] feat(event): slicing modal input for registering the selected event --- apps/web/app/events/[slug]/client-page.tsx | 36 ++++++-- apps/web/app/events/[slug]/page.tsx | 36 +++++--- .../components/events/registration-modal.tsx | 89 +++++++++++++++++++ 3 files changed, 142 insertions(+), 19 deletions(-) create mode 100644 apps/web/components/events/registration-modal.tsx diff --git a/apps/web/app/events/[slug]/client-page.tsx b/apps/web/app/events/[slug]/client-page.tsx index 95d4313..8effec2 100644 --- a/apps/web/app/events/[slug]/client-page.tsx +++ b/apps/web/app/events/[slug]/client-page.tsx @@ -19,6 +19,7 @@ import { DropdownMenuItem, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'; +import { RegistrationModal } from '@/components/events/registration-modal'; interface Event { title: string; @@ -62,7 +63,6 @@ const ClientEventPage: FC = ({ event }) => { const handleSocialShare = (platform: string) => { const text = encodeURIComponent(shareData.text); const url = encodeURIComponent(shareData.url); - // const title = encodeURIComponent(shareData.title); const shareUrls = { twitter: `https://twitter.com/intent/tweet?text=${text}&url=${url}`, @@ -79,6 +79,14 @@ const ClientEventPage: FC = ({ event }) => { ); }; + const handleRegistration = async (data: { + fullName: string; + email: string; + }) => { + // Here you would typically handle the registration with your backend + console.log('Registration submitted:', data); + }; + return (
@@ -160,7 +168,8 @@ const ClientEventPage: FC = ({ event }) => {

Tentang Acara

- {event.description} + {event.description || + `Bergabunglah dalam ${event.title} untuk meningkatkan kemampuan pengembangan software Anda. Acara ini dirancang untuk berbagi pengetahuan dan pengalaman dalam dunia teknologi.`}

@@ -169,7 +178,13 @@ const ClientEventPage: FC = ({ event }) => {
    {event.learningPoints?.map((point, index) => (
  • {point}
  • - ))} + )) || + [ + 'Fundamental dan konsep dasar', + 'Best practices dan pattern', + 'Tips dan trik dari praktisi', + 'Studi kasus dan implementasi praktis', + ].map((point, index) =>
  • {point}
  • )}

@@ -178,7 +193,12 @@ const ClientEventPage: FC = ({ event }) => {
    {event.requirements?.map((req, index) => (
  • {req}
  • - ))} + )) || + [ + 'Laptop dengan spesifikasi standar', + 'Pengetahuan dasar pemrograman', + 'Semangat belajar yang tinggi', + ].map((req, index) =>
  • {req}
  • )}
{event.coordinates && ( @@ -249,10 +269,10 @@ const ClientEventPage: FC = ({ event }) => { )} {event.status === 'upcoming' ? ( - + ) : ( + )} + + + + Daftar Event + + Silakan isi form pendaftaran untuk mengikuti event {eventTitle} + + +
+
+ + + setFormData({ ...formData, fullName: e.target.value }) + } + required + /> +
+
+ + + setFormData({ ...formData, email: e.target.value }) + } + required + /> +
+ +
+
+ + ); +} From 3ee616596d1bdde871fcef8c2f5cf9e87b553fe1 Mon Sep 17 00:00:00 2001 From: Riko Pernando Date: Sat, 26 Apr 2025 19:18:40 +0700 Subject: [PATCH 2/2] feat(event): event register api and integrate it for UI --- apps/web/app/api/events/register/route.ts | 67 +++++++++++++++++++ apps/web/app/events/[slug]/client-page.tsx | 11 +-- .../components/events/registration-modal.tsx | 64 +++++++++++++++--- apps/web/components/ui/use-toast.tsx | 7 ++ 4 files changed, 132 insertions(+), 17 deletions(-) create mode 100644 apps/web/app/api/events/register/route.ts create mode 100644 apps/web/components/ui/use-toast.tsx diff --git a/apps/web/app/api/events/register/route.ts b/apps/web/app/api/events/register/route.ts new file mode 100644 index 0000000..413c975 --- /dev/null +++ b/apps/web/app/api/events/register/route.ts @@ -0,0 +1,67 @@ +import { NextResponse } from 'next/server'; +import { supabase } from '@/lib/supabase'; + +export async function POST(request: Request) { + try { + const { fullName, email, eventId } = await request.json(); + + if (!fullName || !email || !eventId) { + return NextResponse.json( + { error: 'Missing required fields' }, + { status: 400 } + ); + } + + // First, create or get the profile + const { data: profile, error: profileError } = await supabase + .from('profiles') + .upsert( + { + email, + full_name: fullName, + }, + { onConflict: 'email' } + ) + .select() + .single(); + + if (profileError) { + return NextResponse.json( + { error: 'Failed to create profile' }, + { status: 500 } + ); + } + + // Then, register for the event + const { data: registration, error: registrationError } = await supabase + .from('events_participants') + .insert({ + event_id: eventId, + profile_id: profile.id, + status: 'registered', + }) + .select() + .single(); + + if (registrationError) { + if (registrationError.code === '23505') { + return NextResponse.json( + { error: 'Already registered for this event' }, + { status: 409 } + ); + } + return NextResponse.json( + { error: 'Failed to register for event' }, + { status: 500 } + ); + } + + return NextResponse.json(registration); + } catch (error) { + console.error('Registration error:', error); + return NextResponse.json( + { error: 'Internal server error' }, + { status: 500 } + ); + } +} diff --git a/apps/web/app/events/[slug]/client-page.tsx b/apps/web/app/events/[slug]/client-page.tsx index 8effec2..14f61b5 100644 --- a/apps/web/app/events/[slug]/client-page.tsx +++ b/apps/web/app/events/[slug]/client-page.tsx @@ -22,6 +22,7 @@ import { import { RegistrationModal } from '@/components/events/registration-modal'; interface Event { + id: string; title: string; date: string; time: string; @@ -79,14 +80,6 @@ const ClientEventPage: FC = ({ event }) => { ); }; - const handleRegistration = async (data: { - fullName: string; - email: string; - }) => { - // Here you would typically handle the registration with your backend - console.log('Registration submitted:', data); - }; - return (
@@ -270,8 +263,8 @@ const ClientEventPage: FC = ({ event }) => { {event.status === 'upcoming' ? ( ) : (
@@ -77,10 +117,18 @@ export function RegistrationModal({ setFormData({ ...formData, email: e.target.value }) } required + disabled={isLoading} />
- diff --git a/apps/web/components/ui/use-toast.tsx b/apps/web/components/ui/use-toast.tsx new file mode 100644 index 0000000..bbabe97 --- /dev/null +++ b/apps/web/components/ui/use-toast.tsx @@ -0,0 +1,7 @@ +import { Toast } from '@/components/ui/toast'; + +export function useToast() { + return { + toast: Toast, + }; +}