@@ -31,6 +31,16 @@ const HomePage: React.FC = () => {
3131 const [ invitations , setInvitations ] = useState < Invitation [ ] > ( [ ] ) ;
3232 const [ loading , setLoading ] = useState ( true ) ;
3333 const [ isCreateSpotModalOpen , setCreateSpotModalOpen ] = useState ( false ) ;
34+ const [ isEditSpotModalOpen , setIsEditSpotModalOpen ] = useState ( false ) ;
35+ const [ editingSpot , setEditingSpot ] = useState < Spot | null > ( null ) ;
36+ const [ editFormData , setEditFormData ] = useState ( {
37+ location : '' ,
38+ date : '' ,
39+ timing : '' ,
40+ budget : '' ,
41+ description : '' ,
42+ feedback : '' ,
43+ } ) ;
3444 const [ dbSetupError , setDbSetupError ] = useState < string | null > ( null ) ;
3545
3646 const [ newSpotData , setNewSpotData ] = useState ( {
@@ -277,10 +287,57 @@ const HomePage: React.FC = () => {
277287 user_id : profile . id ,
278288 status,
279289 } ) ;
280- // Real-time subscription will update the UI automatically
281- } catch ( error ) {
290+ // Refresh data to show updated status
291+ await fetchData ( ) ;
292+ } catch ( error : any ) {
282293 console . error ( "Failed to create RSVP:" , error ) ;
283- alert ( "Failed to create RSVP. Please try again." ) ;
294+ alert ( `Failed to create RSVP: ${ error . message || 'Please try again.' } ` ) ;
295+ }
296+ } ;
297+
298+ // Handle spot update
299+ const handleUpdateSpot = async ( e : React . FormEvent ) => {
300+ e . preventDefault ( ) ;
301+ if ( ! editingSpot || ! profile ) return ;
302+
303+ try {
304+ let userId = profile . id ;
305+ if ( ! userId . match ( / ^ [ 0 - 9 a - f ] { 8 } - [ 0 - 9 a - f ] { 4 } - [ 0 - 9 a - f ] { 4 } - [ 0 - 9 a - f ] { 4 } - [ 0 - 9 a - f ] { 12 } $ / i) ) {
306+ const { data : dbProfile } = await supabase
307+ . from ( 'profiles' )
308+ . select ( 'id' )
309+ . or ( `email.eq.${ profile . email } ,phone.eq.${ profile . phone } ,username.eq.${ profile . username } ` )
310+ . single ( ) ;
311+ if ( dbProfile ) userId = dbProfile . id ;
312+ }
313+
314+ await spotService . updateSpot ( editingSpot . id , {
315+ location : editFormData . location ,
316+ date : editFormData . date ,
317+ timing : editFormData . timing ,
318+ budget : Number ( editFormData . budget ) ,
319+ description : editFormData . description ,
320+ feedback : editFormData . feedback ,
321+ day : new Date ( editFormData . date ) . toLocaleDateString ( 'en-US' , { weekday : 'long' } ) ,
322+ } ) ;
323+
324+ setIsEditSpotModalOpen ( false ) ;
325+ setEditingSpot ( null ) ;
326+ await fetchData ( ) ;
327+ notify ( "Spot Updated" , "Spot details have been updated successfully" ) ;
328+ } catch ( error : any ) {
329+ alert ( `Failed to update spot: ${ error . message || 'Please try again.' } ` ) ;
330+ }
331+ } ;
332+
333+ // Handle spot delete
334+ const handleDeleteSpot = async ( spotId : string ) => {
335+ try {
336+ await spotService . deleteSpot ( spotId ) ;
337+ await fetchData ( ) ;
338+ notify ( "Spot Deleted" , "Spot has been deleted successfully" ) ;
339+ } catch ( error : any ) {
340+ alert ( `Failed to delete spot: ${ error . message || 'Please try again.' } ` ) ;
284341 }
285342 } ;
286343
@@ -337,16 +394,51 @@ const HomePage: React.FC = () => {
337394 { /* SPOT DETAILS */ }
338395 < Card >
339396 < div className = "space-y-4" >
340- < div >
341- < h2 className = "text-2xl font-bold text-indigo-400 mb-2" > { spot . location } </ h2 >
342- < p className = "text-zinc-400" >
343- { new Date ( spot . date ) . toLocaleDateString ( 'en-US' , {
344- weekday : 'long' ,
345- year : 'numeric' ,
346- month : 'long' ,
347- day : 'numeric'
348- } ) } at { spot . timing }
349- </ p >
397+ < div className = "flex items-start justify-between" >
398+ < div className = "flex-1" >
399+ < h2 className = "text-2xl font-bold text-indigo-400 mb-2" > { spot . location } </ h2 >
400+ < p className = "text-zinc-400" >
401+ { new Date ( spot . date ) . toLocaleDateString ( 'en-US' , {
402+ weekday : 'long' ,
403+ year : 'numeric' ,
404+ month : 'long' ,
405+ day : 'numeric'
406+ } ) } at { spot . timing }
407+ </ p >
408+ </ div >
409+ { isAdmin && (
410+ < div className = "flex gap-2" >
411+ < Button
412+ size = "sm"
413+ variant = "secondary"
414+ onClick = { ( ) => {
415+ setEditingSpot ( spot ) ;
416+ setEditFormData ( {
417+ location : spot . location ,
418+ date : spot . date . split ( 'T' ) [ 0 ] ,
419+ timing : spot . timing ,
420+ budget : spot . budget . toString ( ) ,
421+ description : spot . description || '' ,
422+ feedback : spot . feedback || '' ,
423+ } ) ;
424+ setIsEditSpotModalOpen ( true ) ;
425+ } }
426+ >
427+ Edit
428+ </ Button >
429+ < Button
430+ size = "sm"
431+ variant = "secondary"
432+ onClick = { ( ) => {
433+ if ( confirm ( 'Are you sure you want to delete this spot?' ) ) {
434+ handleDeleteSpot ( spot . id ) ;
435+ }
436+ } }
437+ >
438+ Delete
439+ </ Button >
440+ </ div >
441+ ) }
350442 </ div >
351443 { spot . description && (
352444 < div >
@@ -361,26 +453,27 @@ const HomePage: React.FC = () => {
361453 </ div >
362454 </ Card >
363455
364- < Card className = "h-[350px] p-0 overflow-hidden" >
456+ < Card className = "h-[250px] md:h-[ 350px] p-0 overflow-hidden" >
365457 < div ref = { mapRef } className = "w-full h-full" />
366458 </ Card >
367459
368460 { /* RSVP CONFIRMATION SECTION */ }
369- < Card >
370- < h2 className = "text-lg font-bold mb-4" > Confirm Your Attendance</ h2 >
371- < p className = "text-sm text-zinc-400 mb-4" >
461+ < Card className = "p-4 md:p-6" >
462+ < h2 className = "text-base md:text- lg font-bold mb-3 md: mb-4" > Confirm Your Attendance</ h2 >
463+ < p className = "text-xs md:text- sm text-zinc-400 mb-4" >
372464 Let us know if you're coming to this spot!
373465 </ p >
374466
375467 { myInvitation ? (
376468 < div className = "space-y-4" >
377- < div className = "flex gap-2" >
469+ < div className = "flex flex-wrap gap-2" >
378470 < Button
379471 size = "sm"
380472 onClick = { ( ) =>
381473 handleRSVP ( myInvitation . id , InvitationStatus . CONFIRMED )
382474 }
383475 variant = { myInvitation . status === InvitationStatus . CONFIRMED ? "default" : "secondary" }
476+ className = "flex-1 min-w-[100px] text-xs md:text-sm"
384477 >
385478 ✓ Confirm
386479 </ Button >
@@ -390,6 +483,7 @@ const HomePage: React.FC = () => {
390483 onClick = { ( ) =>
391484 handleRSVP ( myInvitation . id , InvitationStatus . DECLINED )
392485 }
486+ className = "flex-1 min-w-[100px] text-xs md:text-sm"
393487 >
394488 ✗ Not Interested
395489 </ Button >
@@ -399,6 +493,7 @@ const HomePage: React.FC = () => {
399493 onClick = { ( ) =>
400494 handleRSVP ( myInvitation . id , InvitationStatus . PENDING )
401495 }
496+ className = "flex-1 min-w-[100px] text-xs md:text-sm"
402497 >
403498 ⏳ Waitlist
404499 </ Button >
@@ -408,24 +503,27 @@ const HomePage: React.FC = () => {
408503 </ div >
409504 </ div >
410505 ) : (
411- < div className = "flex gap-2" >
506+ < div className = "flex flex-wrap gap-2" >
412507 < Button
413508 size = "sm"
414509 onClick = { ( ) => handleCreateRSVP ( InvitationStatus . CONFIRMED ) }
510+ className = "flex-1 min-w-[100px] text-xs md:text-sm"
415511 >
416512 ✓ Confirm
417513 </ Button >
418514 < Button
419515 size = "sm"
420516 variant = "secondary"
421517 onClick = { ( ) => handleCreateRSVP ( InvitationStatus . DECLINED ) }
518+ className = "flex-1 min-w-[100px] text-xs md:text-sm"
422519 >
423520 ✗ Not Interested
424521 </ Button >
425522 < Button
426523 size = "sm"
427524 variant = "secondary"
428525 onClick = { ( ) => handleCreateRSVP ( InvitationStatus . PENDING ) }
526+ className = "flex-1 min-w-[100px] text-xs md:text-sm"
429527 >
430528 ⏳ Waitlist
431529 </ Button >
@@ -434,36 +532,36 @@ const HomePage: React.FC = () => {
434532 </ Card >
435533
436534 { /* RSVP STATUS - REAL-TIME UPDATES */ }
437- < Card >
438- < h2 className = "text-lg font-bold mb-4" > Who's Coming? ({ invitations . filter ( i => i . status === InvitationStatus . CONFIRMED ) . length } )</ h2 >
535+ < Card className = "p-4 md:p-6" >
536+ < h2 className = "text-base md:text- lg font-bold mb-4" > Who's Coming? ({ invitations . filter ( i => i . status === InvitationStatus . CONFIRMED ) . length } )</ h2 >
439537
440538 < div className = "space-y-3" >
441539 { invitations
442540 . sort ( ( a , b ) => {
443541 // Sort: Confirmed first, then Pending, then Declined
444- const statusOrder = { confirmed : 0 , pending : 1 , declined : 2 } ;
445- return statusOrder [ a . status ] - statusOrder [ b . status ] ;
542+ const statusOrder : Record < string , number > = { confirmed : 0 , pending : 1 , declined : 2 } ;
543+ return ( statusOrder [ a . status ] || 1 ) - ( statusOrder [ b . status ] || 1 ) ;
446544 } )
447545 . map ( ( inv ) => (
448546 < div
449547 key = { inv . id }
450- className = "flex items-center justify-between p-3 bg-zinc-900/50 rounded-lg border border-white/5"
548+ className = "flex flex-col sm:flex-row sm: items-center sm: justify-between gap-3 p-3 bg-zinc-900/50 rounded-lg border border-white/5"
451549 >
452- < div className = "flex items-center gap-3" >
550+ < div className = "flex items-center gap-3 min-w-0 " >
453551 < img
454552 src = { inv . profiles . profile_pic_url || "https://api.dicebear.com/7.x/thumbs/svg?seed=default" }
455553 alt = { inv . profiles . name }
456- className = "w-10 h-10 rounded-full border border-white/10"
554+ className = "w-10 h-10 rounded-full border border-white/10 flex-shrink-0 "
457555 />
458- < div >
459- < span className = "font-medium text-sm" > { inv . profiles . name } </ span >
460- < div className = "text-xs text-zinc-500" >
556+ < div className = "min-w-0" >
557+ < span className = "font-medium text-sm md:text-base block truncate " > { inv . profiles . name } </ span >
558+ < div className = "text-xs text-zinc-500 truncate " >
461559 @{ inv . profiles . username }
462560 </ div >
463561 </ div >
464562 </ div >
465- < div className = "flex items-center gap-3" >
466- < span className = { `px-3 py-1 rounded-full text-xs font-bold uppercase ${
563+ < div className = "flex items-center gap-3 flex-shrink-0 " >
564+ < span className = { `px-2 md:px- 3 py-1 rounded-full text-xs font-bold uppercase whitespace-nowrap ${
467565 inv . status === InvitationStatus . CONFIRMED
468566 ? 'bg-green-500/20 text-green-400 border border-green-500/30'
469567 : inv . status === InvitationStatus . PENDING
@@ -541,6 +639,69 @@ const HomePage: React.FC = () => {
541639 </ Button >
542640 </ form >
543641 </ Modal >
642+
643+ { /* EDIT SPOT MODAL */ }
644+ < Modal
645+ isOpen = { isEditSpotModalOpen }
646+ onClose = { ( ) => {
647+ setIsEditSpotModalOpen ( false ) ;
648+ setEditingSpot ( null ) ;
649+ } }
650+ title = "Edit Spot"
651+ >
652+ < form onSubmit = { handleUpdateSpot } className = "space-y-4" >
653+ < Input
654+ label = "Location"
655+ value = { editFormData . location }
656+ onChange = { ( e ) => setEditFormData ( { ...editFormData , location : e . target . value } ) }
657+ required
658+ />
659+ < Input
660+ type = "date"
661+ label = "Date"
662+ value = { editFormData . date }
663+ onChange = { ( e ) => setEditFormData ( { ...editFormData , date : e . target . value } ) }
664+ required
665+ />
666+ < Input
667+ type = "time"
668+ label = "Time"
669+ value = { editFormData . timing }
670+ onChange = { ( e ) => setEditFormData ( { ...editFormData , timing : e . target . value } ) }
671+ required
672+ />
673+ < Input
674+ type = "number"
675+ label = "Budget"
676+ value = { editFormData . budget }
677+ onChange = { ( e ) => setEditFormData ( { ...editFormData , budget : e . target . value } ) }
678+ required
679+ />
680+ < Textarea
681+ label = "Description"
682+ value = { editFormData . description }
683+ onChange = { ( e ) => setEditFormData ( { ...editFormData , description : e . target . value } ) }
684+ />
685+ < Textarea
686+ label = "Admin Feedback"
687+ value = { editFormData . feedback }
688+ onChange = { ( e ) => setEditFormData ( { ...editFormData , feedback : e . target . value } ) }
689+ />
690+ < div className = "flex gap-2" >
691+ < Button type = "submit" className = "flex-1" > Update Spot</ Button >
692+ < Button
693+ type = "button"
694+ variant = "secondary"
695+ onClick = { ( ) => {
696+ setIsEditSpotModalOpen ( false ) ;
697+ setEditingSpot ( null ) ;
698+ } }
699+ >
700+ Cancel
701+ </ Button >
702+ </ div >
703+ </ form >
704+ </ Modal >
544705 </ div >
545706 ) ;
546707} ;
0 commit comments