@@ -610,7 +610,7 @@ function BulkImportPanel({ onImported, onCancel }) {
}
// ── Calendar Views ────────────────────────────────────────────────────────────
function ScheduleView ( { events , selectedDate , onSelect , filterKeyword = '' , filterTypeId = '' } ) {
function ScheduleView ( { events , selectedDate , onSelect , filterKeyword = '' , filterTypeId = '' , isMobile = false } ) {
const y = selectedDate . getFullYear ( ) , m = selectedDate . getMonth ( ) ;
const monthStart = new Date ( y , m , 1 ) , monthEnd = new Date ( y , m + 1 , 0 , 23 , 59 , 59 ) ;
const kw = filterKeyword . toLowerCase ( ) . trim ( ) ;
@@ -624,7 +624,15 @@ function ScheduleView({ events, selectedDate, onSelect, filterKeyword='', filter
return true ;
} ) ;
if ( ! filtered . length ) return < div style = { { textAlign : 'center' , padding : '60px 20px' , color : 'var(--text-tertiary)' , fontSize : 14 } } > { kw || filterTypeId ? 'No events match your filters' : 'No events in' } { ! kw && ! filterTypeId && ` ${ MONTHS [ m ] } ${ y } ` } < / div > ;
return < > { filtered . map ( e => { const s = new Date ( e . start _at ) ; const col = e . event _type ? . colour || '#9ca3af' ; return ( < div key = { e . id } onClick = { ( ) => onSelect ( e ) } style = { { display : 'flex' , alignItems : 'center' , gap : 10 , padding : '12px 14px' , borderBottom : '1px solid var(--border)' , cursor : 'pointer' } } onMouseEnter = { el => el . currentTarget . style . background = 'var(--background)' } onMouseLeave = { el => el . currentTarget . style . background = '' } > < div style = { { width : 36 , textAlign : 'center' , flexShrink : 0 } } > < div style = { { fontSize : 20 , fontWeight : 700 , lineHeight : 1 } } > { s . getDate ( ) } < / div > < div style = { { fontSize : 10 , color : 'var(--text-tertiary)' , textTransform : 'uppercase' } } > { SHORT _MONTHS [ s . getMonth ( ) ] } , { DAYS [ s . getDay ( ) ] } < / div > < / div > < div style = { { width : 62 , flexShrink : 0 , display : 'flex' , alignItems : 'flex-start' , gap : 5 , fontSize : 11 , color : 'var(--text-secondary)' } } > < span style = { { width : 8 , height : 8 , borderRadius : '50%' , background : col , flexShrink : 0 , marginTop : 3 } } / > { e . all _day ? < span > All day < / span > : < span style = { { lineHeight : 1.5 } } > { fmtTime ( e . start _at ) } – < br / > { fmtTime ( e . end _at ) } < / span > } < / div > < div style = { { flex : 1 , minWidth : 0 } } > < div style = { { fontSize : 14 , fontWeight : 600 , display : 'flex' , alignItems : 'center' , gap : 6 , flexWrap : 'nowrap' } } > { e . event _type ? . name && < span style = { { fontSize : 10 , color : 'var(--text-tertiary)' , textTransform : 'uppercase' , letterSpacing : '0.5px' , fontWeight : 600 , flexShrink : 0 } } > { e . event _type . name } : < / span > } < span style = { { minWidth : 0 , overflow : 'hidden' , textOverflow : 'ellipsis' , whiteSpace : 'nowrap' } } > { e . title } < / span > { ! ! e . track _availability && (
return < > { filtered . map ( e => { const s = new Date ( e . start _at ) ; const col = e . event _type ? . colour || '#9ca3af' ;
// Desktop: original pre-v0.9.64 sizes. Mobile: compact sizes from v0.9.64
const rowPad = isMobile ? '12px 14px' : '14px 20px' ;
const rowGap = isMobile ? 10 : 20 ;
const datW = isMobile ? 36 : 44 ; const datFs = isMobile ? 20 : 22 ; const datSFs = isMobile ? 10 : 11 ;
const timeW = isMobile ? 62 : 100 ; const timeGap = isMobile ? 5 : 8 ; const timeFs = isMobile ? 11 : 13 ;
const dotSz = isMobile ? 8 : 10 ;
const typeFs = isMobile ? 10 : 11 ; const titleGap = isMobile ? 6 : 8 ;
return ( < div key = { e . id } onClick = { ( ) => onSelect ( e ) } style = { { display : 'flex' , alignItems : 'center' , gap : rowGap , padding : rowPad , borderBottom : '1px solid var(--border)' , cursor : 'pointer' } } onMouseEnter = { el => el . currentTarget . style . background = 'var(--background)' } onMouseLeave = { el => el . currentTarget . style . background = '' } > < div style = { { width : datW , textAlign : 'center' , flexShrink : 0 } } > < div style = { { fontSize : datFs , fontWeight : 700 , lineHeight : 1 } } > { s . getDate ( ) } < / div > < div style = { { fontSize : datSFs , color : 'var(--text-tertiary)' , textTransform : 'uppercase' } } > { SHORT _MONTHS [ s . getMonth ( ) ] } , { DAYS [ s . getDay ( ) ] } < / div > < / div > < div style = { { width : timeW , flexShrink : 0 , display : 'flex' , alignItems : 'flex-start' , gap : timeGap , fontSize : timeFs , color : 'var(--text-secondary)' } } > < span style = { { width : dotSz , height : dotSz , borderRadius : '50%' , background : col , flexShrink : 0 , marginTop : 3 } } / > { e . all _day ? < span > All day < / span > : < span style = { { lineHeight : 1.5 } } > { fmtTime ( e . start _at ) } – < br / > { fmtTime ( e . end _at ) } < / span > } < / div > < div style = { { flex : 1 , minWidth : 0 } } > < div style = { { fontSize : 14 , fontWeight : 600 , display : 'flex' , alignItems : 'center' , gap : titleGap , flexWrap : 'nowrap' } } > { e . event _type ? . name && < span style = { { fontSize : typeFs , color : 'var(--text-tertiary)' , textTransform : 'uppercase' , letterSpacing : '0.5px' , fontWeight : 600 , flexShrink : 0 } } > { e . event _type . name } : < / span > } < span style = { { minWidth : 0 , overflow : 'hidden' , textOverflow : 'ellipsis' , whiteSpace : 'nowrap' } } > { e . title } < / span > { ! ! e . track _availability && (
e . my _response ? RESP _ICON [ e . my _response ] ( RESP _COLOR [ e . my _response ] ) : BELL _ICON
) } < / div > { e . location && < div style = { { fontSize : 12 , color : 'var(--text-tertiary)' , marginTop : 2 } } > { e . location } < / div > } < / div > < / div > ) ; } ) } < / > ;
}
@@ -885,7 +893,14 @@ export default function SchedulePage({ isToolManager, isMobile, onProfile, onHel
const handleSaved = ( ) => { load ( ) ; setPanel ( 'calendar' ) ; setEditingEvent ( null ) ; } ;
const handleDelete = async e => {
if ( ! confirm ( ` Delete " ${ e . title } "? ` ) ) return ;
try { await api . deleteEvent ( e . id ) ; toast ( 'Deleted' , 'success' ) ; load ( ) ; setDetailEvent ( null ) ; } catch ( err ) { toast ( err . message , 'error' ) ; }
try {
await api . deleteEvent ( e . id ) ;
toast ( 'Deleted' , 'success' ) ;
setPanel ( 'calendar' ) ;
setEditingEvent ( null ) ;
setDetailEvent ( null ) ;
load ( ) ; // reload list so deleted event disappears immediately
} catch ( err ) { toast ( err . message , 'error' ) ; }
} ;
if ( loading ) return < div style = { { display : 'flex' , alignItems : 'center' , justifyContent : 'center' , flex : 1 , color : 'var(--text-tertiary)' , fontSize : 14 } } > Loading schedule … < / div > ;
@@ -969,7 +984,11 @@ export default function SchedulePage({ isToolManager, isMobile, onProfile, onHel
< div style = { { display : 'flex' , alignItems : 'center' , gap : 8 , padding : '8px 16px' , borderBottom : '1px solid var(--border)' , background : 'var(--surface)' , flexShrink : 0 , flexWrap : 'nowrap' } } >
{ /* Mobile title + create */ }
{ isMobile && (
< >
< span style = { { fontSize : 15 , fontWeight : 700 , flex : 1 } } > Team Schedule < / span >
{ /* User footer trigger on mobile — compact avatar button */ }
< UserFooter onProfile = { onProfile } onHelp = { onHelp } onAbout = { onAbout } mobileCompact = { true } / >
< / >
) }
{ ! isMobile && (
@@ -1004,7 +1023,7 @@ export default function SchedulePage({ isToolManager, isMobile, onProfile, onHel
{ /* Calendar or panel content */ }
< div style = { { flex : 1 , overflowY : 'auto' , overflowX : panel === 'eventForm' ? 'auto' : 'hidden' } } >
{ panel === 'calendar' && view === 'schedule' && < ScheduleView events = { events } selectedDate = { selDate } onSelect = { openDetail } filterKeyword = { filterKeyword } filterTypeId = { filterTypeId } / > }
{ panel === 'calendar' && view === 'schedule' && < ScheduleView events = { events } selectedDate = { selDate } onSelect = { openDetail } filterKeyword = { filterKeyword } filterTypeId = { filterTypeId } isMobile = { isMobile } / > }
{ panel === 'calendar' && view === 'day' && < DayView events = { events } selectedDate = { selDate } onSelect = { openDetail } / > }
{ panel === 'calendar' && view === 'week' && < WeekView events = { events } selectedDate = { selDate } onSelect = { openDetail } / > }
{ panel === 'calendar' && view === 'month' && < MonthView events = { events } selectedDate = { selDate } onSelect = { openDetail } onSelectDay = { d => { setSelDate ( d ) ; setView ( 'schedule' ) ; } } / > }