@ -8,8 +8,9 @@ import {
updateCourt ,
updateCourt ,
deleteCourt ,
deleteCourt ,
getCourtDependencies ,
getCourtDependencies ,
getSports ,
} from '@/src/lib/api/courts' ;
} from '@/src/lib/api/courts' ;
import type { Court , CourtRequest , CourtDependencies } from '@/src/types/courts' ;
import type { Court , CourtRequest , CourtDependencies , Sport , SportVariation } from '@/src/types/courts' ;
import { formatTimestamp } from '@/src/types/courts' ;
import { formatTimestamp } from '@/src/types/courts' ;
interface ClubCourtsTabProps {
interface ClubCourtsTabProps {
@ -244,9 +245,31 @@ interface CourtFormModalProps {
function CourtFormModal ( { clubId , court , onClose , onSuccess } : CourtFormModalProps ) {
function CourtFormModal ( { clubId , court , onClose , onSuccess } : CourtFormModalProps ) {
const isEditing = ! ! court ;
const isEditing = ! ! court ;
const [ name , setName ] = useState ( court ? . name || '' ) ;
const [ name , setName ] = useState ( court ? . name || '' ) ;
const [ sportVariationId , setSportVariationId ] = useState < number > ( court ? . sport_variation_id || 0 ) ;
const [ sports , setSports ] = useState < Sport [ ] > ( [ ] ) ;
const [ loadingSports , setLoadingSports ] = useState ( true ) ;
const [ saving , setSaving ] = useState ( false ) ;
const [ saving , setSaving ] = useState ( false ) ;
const [ error , setError ] = useState ( '' ) ;
const [ error , setError ] = useState ( '' ) ;
const [ fieldError , setFieldError ] = useState ( '' ) ;
const [ fieldError , setFieldError ] = useState ( '' ) ;
const [ sportVariationError , setSportVariationError ] = useState ( '' ) ;
useEffect ( ( ) = > {
async function loadSports() {
setLoadingSports ( true ) ;
const result = await getSports ( ) ;
if ( result . success ) {
setSports ( result . data . sports ) ;
// Auto-select first variation if creating new court
if ( ! isEditing && result . data . sports . length > 0 && result . data . sports [ 0 ] . variations . length > 0 ) {
setSportVariationId ( result . data . sports [ 0 ] . variations [ 0 ] . sport_variation_id ) ;
}
} else {
setError ( result . error . detail ) ;
}
setLoadingSports ( false ) ;
}
loadSports ( ) ;
} , [ isEditing ] ) ;
async function handleSubmit ( e : React.FormEvent ) {
async function handleSubmit ( e : React.FormEvent ) {
e . preventDefault ( ) ;
e . preventDefault ( ) ;
@ -256,12 +279,19 @@ function CourtFormModal({ clubId, court, onClose, onSuccess }: CourtFormModalPro
return ;
return ;
}
}
if ( ! sportVariationId || sportVariationId === 0 ) {
setSportVariationError ( 'Sport variation is required' ) ;
return ;
}
setSaving ( true ) ;
setSaving ( true ) ;
setError ( '' ) ;
setError ( '' ) ;
setFieldError ( '' ) ;
setFieldError ( '' ) ;
setSportVariationError ( '' ) ;
const request : CourtRequest = {
const request : CourtRequest = {
name : name.trim ( ) ,
name : name.trim ( ) ,
sport_variation_id : sportVariationId ,
} ;
} ;
const result = isEditing
const result = isEditing
@ -336,9 +366,46 @@ function CourtFormModal({ clubId, court, onClose, onSuccess }: CourtFormModalPro
{ fieldError && (
{ fieldError && (
< p className = "mt-1 text-sm text-red-600" > { fieldError } < / p >
< p className = "mt-1 text-sm text-red-600" > { fieldError } < / p >
) }
) }
< p className = "mt-2 text-xs text-slate-500" >
< / div >
Examples : "Court 1" , "North Court" , "VIP Court"
< / p >
{ /* Sport Variation */ }
< div >
< label className = "block text-sm font-semibold text-slate-900 mb-2" >
Sport & Type < span className = "text-red-600" > * < / span >
< / label >
{ loadingSports ? (
< div className = "flex items-center justify-center py-3 border-2 border-slate-200 rounded-lg" >
< Loader2 className = "w-5 h-5 text-slate-600 animate-spin" / >
< / div >
) : (
< select
value = { sportVariationId }
onChange = { ( e ) = > setSportVariationId ( Number ( e . target . value ) ) }
className = { ` w-full px-4 py-3 border-2 rounded-lg font-medium transition-colors ${
sportVariationError
? 'border-red-300 focus:border-red-500'
: 'border-slate-200 focus:border-slate-900'
} focus :outline - none ` }
disabled = { saving || isEditing }
>
< option value = { 0 } disabled > Select sport variation < / option >
{ sports . map ( ( sport ) = >
sport . variations . map ( ( variation ) = > (
< option key = { variation . sport_variation_id } value = { variation . sport_variation_id } >
{ sport . name } - { variation . name }
< / option >
) )
) }
< / select >
) }
{ sportVariationError && (
< p className = "mt-1 text-sm text-red-600" > { sportVariationError } < / p >
) }
{ isEditing && (
< p className = "mt-2 text-xs text-slate-500" >
Sport type cannot be changed after creation
< / p >
) }
< / div >
< / div >
{ /* Actions */ }
{ /* Actions */ }