11import React , { useState , useMemo , useEffect , useRef } from 'react' ;
22import { Link } from 'react-router-dom' ;
3- import { getEventAttendanceSummary } from '../../APIFunctions/SCEvents' ;
3+ import { getEventAttendanceSummary , joinWaitlistForSCEvent } from '../../APIFunctions/SCEvents' ;
44
55// ─── tiny helpers ────────────────────────────────────────────────────────────
66
@@ -281,6 +281,9 @@ function EventPopup({ event, onClose, isAdminView, user }) {
281281 const [ attendeeCount , setAttendeeCount ] = useState ( null ) ;
282282 const [ attendanceLoading , setAttendanceLoading ] = useState ( false ) ;
283283 const [ attendanceLoaded , setAttendanceLoaded ] = useState ( false ) ;
284+ const [ waitlistSubmitting , setWaitlistSubmitting ] = useState ( false ) ;
285+ const [ waitlistMessage , setWaitlistMessage ] = useState ( '' ) ;
286+ const [ waitlistError , setWaitlistError ] = useState ( '' ) ;
284287 const canEditEvent =
285288 Array . isArray ( event . admins ) &&
286289 userId &&
@@ -292,6 +295,13 @@ function EventPopup({ event, onClose, isAdminView, user }) {
292295 ? Math . max ( maxAttendees - attendeeCount , 0 )
293296 : null ;
294297 const registrationCta = getRegistrationCta ( event ) ;
298+ const isFull = hasCapacityLimit && typeof remainingSpots === 'number' && remainingSpots <= 0 ;
299+ const shouldShowWaitlistJoin =
300+ ! canEditEvent &&
301+ event . status === 'published' &&
302+ ! registrationCta . disabled &&
303+ isFull &&
304+ ! ! event . waitlist_enabled ;
295305
296306 useEffect ( ( ) => {
297307 function onKey ( e ) {
@@ -342,6 +352,41 @@ function EventPopup({ event, onClose, isAdminView, user }) {
342352 } ;
343353 } , [ eventId , authToken ] ) ;
344354
355+ async function handleJoinWaitlist ( ) {
356+ setWaitlistError ( '' ) ;
357+ setWaitlistMessage ( '' ) ;
358+
359+ if ( ! authToken ) {
360+ setWaitlistError ( 'You must be logged in to join the waitlist.' ) ;
361+ return ;
362+ }
363+
364+ if ( ! eventId ) {
365+ setWaitlistError ( 'Missing event id.' ) ;
366+ return ;
367+ }
368+
369+ setWaitlistSubmitting ( true ) ;
370+ const response = await joinWaitlistForSCEvent ( eventId , authToken ) ;
371+ setWaitlistSubmitting ( false ) ;
372+
373+ if ( response . error ) {
374+ let msg = '' ;
375+ const data = response . responseData ;
376+
377+ if ( data && typeof data === 'object' && data . error ) {
378+ msg = String ( data . error ) ;
379+ } else if ( typeof data === 'string' && data . trim ( ) ) {
380+ msg = data . trim ( ) ;
381+ }
382+
383+ setWaitlistError ( msg || 'Failed to join waitlist.' ) ;
384+ return ;
385+ }
386+
387+ setWaitlistMessage ( 'Joined waitlist successfully.' ) ;
388+ }
389+
345390 return (
346391 < div className = "fixed inset-0 z-50 flex items-center justify-center bg-slate-950/70 p-4" >
347392 < div
@@ -424,7 +469,7 @@ function EventPopup({ event, onClose, isAdminView, user }) {
424469 < p className = "text-center text-xs text-slate-400" >
425470 { attendeeCount } { attendeeCount === 1 ? 'person' : 'people' } registered
426471 { event . waitlist_enabled && (
427- < span className = "ml-1 text-amber-300" > · waitlist enabled </ span >
472+ < span className = "ml-1 text-amber-300" > · waitlist available </ span >
428473 ) }
429474 </ p >
430475 ) }
@@ -433,7 +478,7 @@ function EventPopup({ event, onClose, isAdminView, user }) {
433478 < p className = "text-center text-xs text-slate-400" >
434479 { remainingSpots } spot{ remainingSpots !== 1 ? 's' : '' } left
435480 { event . waitlist_enabled && (
436- < span className = "ml-1 text-amber-300" > · waitlist enabled </ span >
481+ < span className = "ml-1 text-amber-300" > · waitlist available </ span >
437482 ) }
438483 </ p >
439484 ) }
@@ -483,7 +528,18 @@ function EventPopup({ event, onClose, isAdminView, user }) {
483528 </ div >
484529 ) }
485530
486- { ! canEditEvent && event . status === 'published' && ! registrationCta . disabled && (
531+ { shouldShowWaitlistJoin && (
532+ < button
533+ type = "button"
534+ onClick = { handleJoinWaitlist }
535+ disabled = { waitlistSubmitting }
536+ className = "inline-flex w-full items-center justify-center rounded-xl bg-gradient-to-r from-amber-500 to-orange-500 px-6 py-2.5 text-sm font-semibold text-white transition-all duration-200 hover:from-amber-400 hover:to-orange-400 disabled:cursor-not-allowed disabled:opacity-70"
537+ >
538+ { waitlistSubmitting ? 'Joining waitlist...' : 'Join waitlist' }
539+ </ button >
540+ ) }
541+
542+ { ! shouldShowWaitlistJoin && ! canEditEvent && event . status === 'published' && ! registrationCta . disabled && (
487543 < Link
488544 to = { `/events/${ event . id } /register` }
489545 className = "inline-flex w-full items-center justify-center rounded-xl bg-gradient-to-r from-sky-500 to-indigo-500 px-6 py-2.5 text-sm font-semibold text-white transition-all duration-200 hover:from-sky-400 hover:to-indigo-400 focus:outline-none focus:ring-2 focus:ring-sky-500"
@@ -492,6 +548,14 @@ function EventPopup({ event, onClose, isAdminView, user }) {
492548 { registrationCta . label }
493549 </ Link >
494550 ) }
551+
552+ { waitlistError && (
553+ < p className = "text-center text-xs text-red-300" > { waitlistError } </ p >
554+ ) }
555+
556+ { waitlistMessage && (
557+ < p className = "text-center text-xs text-emerald-300" > { waitlistMessage } </ p >
558+ ) }
495559 </ div >
496560 </ div >
497561 </ div >
0 commit comments