1- import { isWeekend } from 'date-fns'
2- import { FC , useMemo } from 'react'
1+ import { format , isWeekend } from 'date-fns'
2+ import { FC , useCallback , useMemo , useState } from 'react'
33import classNames from 'classnames'
44
55import { LoadingSpinner } from '~/libs/ui'
6+ import { useCheckIsMobile } from '~/libs/shared'
67
78import { LeaveStatus , TeamLeaveDate } from '../../models'
89import { getDateKey , getMonthDates } from '../../utils'
@@ -60,6 +61,25 @@ export const TeamCalendar: FC<TeamCalendarProps> = (props: TeamCalendarProps) =>
6061 const currentDate = props . currentDate
6162 const isLoading = props . isLoading
6263 const teamLeaveDates = props . teamLeaveDates
64+ const [ openDateKey , setOpenDateKey ] = useState < string | undefined > ( undefined )
65+
66+ const isMobile : boolean = useCheckIsMobile ( )
67+
68+ const closePopover = useCallback ( ( ) => {
69+ setOpenDateKey ( undefined )
70+ } , [ ] )
71+
72+ const handleCellClick = useCallback (
73+ ( e : React . MouseEvent < HTMLButtonElement > ) => {
74+ if ( ! isMobile ) return
75+
76+ const dateKey = e . currentTarget . dataset . dateKey
77+ if ( ! dateKey ) return
78+
79+ setOpenDateKey ( prev => ( prev === dateKey ? undefined : dateKey ) )
80+ } ,
81+ [ isMobile ] ,
82+ )
6383
6484 const monthDates = useMemo (
6585 ( ) => getMonthDates ( currentDate . getFullYear ( ) , currentDate . getMonth ( ) ) ,
@@ -116,44 +136,126 @@ export const TeamCalendar: FC<TeamCalendarProps> = (props: TeamCalendarProps) =>
116136 const overflowCount = sortedUsers . length - displayedUsers . length
117137 const weekendClass = isWeekend ( date ) ? styles . weekend : undefined
118138
139+ // Mobile popover open/close
140+ const isOpen = openDateKey === dateKey
141+ const leaveCount = sortedUsers . length
142+
119143 return (
120144 < div
121145 key = { dateKey }
122146 className = { classNames ( styles . cell , weekendClass , {
123147 [ styles . loading ] : isLoading ,
148+ [ styles . hasLeave ] : leaveCount > 0 ,
124149 } ) }
125150 >
126- < span className = { styles . dateNumber } > { date . getDate ( ) } </ span >
127- < div className = { styles . userList } >
128- { displayedUsers . length > 0
129- && displayedUsers . map ( ( user , userIndex ) => {
130- const isHolidayStatus = user . status === LeaveStatus . WIPRO_HOLIDAY
131- || user . status === LeaveStatus . HOLIDAY
151+ { /* Whole cell tappable on mobile */ }
152+ < button
153+ type = 'button'
154+ className = { styles . cellButton }
155+ disabled = { isLoading }
156+ onClick = { handleCellClick }
157+ data-date-key = { dateKey }
158+ aria-haspopup = 'dialog'
159+ aria-expanded = { isMobile ? isOpen : undefined }
160+ aria-label = { `Open leave list for ${ dateKey } ` }
161+ >
162+ < span className = { styles . dateNumber } > { date . getDate ( ) } </ span >
163+
164+ { /* MOBILE: only show count badge */ }
165+ { isMobile && leaveCount > 0 && (
166+ < span className = { styles . countBadge } > { leaveCount } </ span >
167+ ) }
168+
169+ { /* DESKTOP: show list in the cell (your existing UI) */ }
170+ { ! isMobile && (
171+ < div className = { styles . userList } >
172+ { displayedUsers . length > 0
173+ && displayedUsers . map ( ( user , userIndex ) => {
174+ const isHolidayStatus
175+ = user . status === LeaveStatus . WIPRO_HOLIDAY
176+ || user . status === LeaveStatus . HOLIDAY
177+
178+ return (
179+ < div
180+ key = { `${ dateKey } -${ user . userId } -${ userIndex . toString ( ) } ` }
181+ className = { classNames (
182+ styles . userItem ,
183+ isHolidayStatus
184+ ? styles . userHoliday
185+ : styles . userLeave ,
186+ ) }
187+ >
188+ { getUserDisplayName ( user ) }
189+ </ div >
190+ )
191+ } ) }
192+ { overflowCount > 0 && (
193+ < div className = { styles . overflowIndicator } >
194+ { `+${ overflowCount } more` }
195+ </ div >
196+ ) }
197+ </ div >
198+ ) }
199+ </ button >
200+ </ div >
201+ )
202+ } ) }
203+ </ div >
204+
205+ { isMobile && openDateKey && ( ( ) => {
206+ const selectedDate = paddedDates . find ( d => d && getDateKey ( d ) === openDateKey )
207+ if ( ! selectedDate ) return undefined
208+
209+ const selectedEntry = teamLeaveDates . find ( item => item . date === openDateKey )
210+ const selectedUsers = [ ...( selectedEntry ?. usersOnLeave ?? [ ] ) ] . sort ( compareUsersByName )
211+
212+ return (
213+ < div className = { styles . modalRoot } >
214+ < div className = { styles . backdrop } onClick = { closePopover } />
215+
216+ < div className = { styles . popover } role = 'dialog' aria-label = 'Users on leave' >
217+ < div className = { styles . popoverHeader } >
218+ < div className = { styles . popoverTitle } >
219+ { format ( selectedDate , 'EEE, dd MMM yyyy' ) }
220+ </ div >
221+
222+ < button
223+ type = 'button'
224+ className = { styles . closeBtn }
225+ onClick = { closePopover }
226+ aria-label = 'Close'
227+ >
228+ ✕
229+ </ button >
230+ </ div >
231+
232+ < div className = { styles . popoverBody } >
233+ { selectedUsers . length === 0 ? (
234+ < div className = { styles . emptyState } > No leave</ div >
235+ ) : (
236+ selectedUsers . map ( ( user , idx ) => {
237+ const isHolidayStatus
238+ = user . status === LeaveStatus . WIPRO_HOLIDAY
239+ || user . status === LeaveStatus . HOLIDAY
132240
133241 return (
134242 < div
135- key = { `${ dateKey } -${ user . userId } -${ userIndex . toString ( ) } ` }
243+ key = { `${ openDateKey } -${ user . userId } -${ idx . toString ( ) } ` }
136244 className = { classNames (
137245 styles . userItem ,
138- isHolidayStatus
139- ? styles . userHoliday
140- : styles . userLeave ,
246+ isHolidayStatus ? styles . userHoliday : styles . userLeave ,
141247 ) }
142248 >
143249 { getUserDisplayName ( user ) }
144250 </ div >
145251 )
146- } ) }
147- { overflowCount > 0 && (
148- < div className = { styles . overflowIndicator } >
149- { `+${ overflowCount } more` }
150- </ div >
252+ } )
151253 ) }
152254 </ div >
153255 </ div >
154- )
155- } ) }
156- </ div >
256+ </ div >
257+ )
258+ } ) ( ) }
157259
158260 { isLoading && (
159261 < div className = { styles . loadingOverlay } >
@@ -162,6 +264,7 @@ export const TeamCalendar: FC<TeamCalendarProps> = (props: TeamCalendarProps) =>
162264 ) }
163265 </ div >
164266 )
267+
165268}
166269
167270export default TeamCalendar
0 commit comments