#771 implement timezone bottom sheet on mobile

This commit is contained in:
lethemanh
2026-04-09 11:38:09 +07:00
parent 91f0a5526f
commit cbe73b1e04
15 changed files with 397 additions and 132 deletions
+1 -1
View File
@@ -36,7 +36,7 @@ import './Calendar.styl'
import './CustomCalendar.styl'
import { useCalendarEventHandlers } from './hooks/useCalendarEventHandlers'
import { useCalendarViewHandlers } from './hooks/useCalendarViewHandlers'
import { TimezoneSelector } from './TimezoneSelector'
import { TimezoneSelector } from '../Timezone/TimezoneSelector'
import {
eventToFullCalendarFormat,
extractEvents,
@@ -1,111 +0,0 @@
import {
browserDefaultTimeZone,
getTimezoneOffset,
resolveTimezone
} from '@/utils/timezone'
import { TIMEZONES } from '@/utils/timezone-data'
import { Button, Popover } from '@linagora/twake-mui'
import { MouseEvent, useMemo, useRef, useState } from 'react'
import { useI18n } from 'twake-i18n'
import { TimezoneAutocomplete } from '../Timezone/TimezoneAutocomplete'
interface TimezoneSelectProps {
value: string
onChange: (value: string) => void
referenceDate: Date
}
export function TimezoneSelector({
value,
onChange,
referenceDate
}: TimezoneSelectProps) {
const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null)
const inputRef = useRef<HTMLInputElement>(null)
const timezoneList = useTimeZoneList()
const effectiveTimezone = value
? resolveTimezone(value)
: timezoneList.browserTz
const selectedOffset = getTimezoneOffset(effectiveTimezone, referenceDate)
const handleOpen = (event: MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget)
}
const handleClose = () => {
setAnchorEl(null)
}
const open = Boolean(anchorEl)
const { t } = useI18n()
return (
<>
<Button
variant="text"
size="small"
onClick={handleOpen}
sx={{
textTransform: 'none',
minWidth: 'auto',
padding: '2px 4px',
margin: 0,
lineHeight: 1.2
}}
>
{selectedOffset || t('common.select_timezone')}
</Button>
<Popover
open={open}
anchorEl={anchorEl}
onClose={handleClose}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'left'
}}
transformOrigin={{
vertical: 'top',
horizontal: 'left'
}}
slotProps={{
paper: {
sx: { width: 280, maxHeight: 400, overflow: 'hidden', p: 0 }
},
transition: {
onEntered: () => {
inputRef.current?.focus()
}
}
}}
>
<TimezoneAutocomplete
size="medium"
value={effectiveTimezone}
onChange={onChange}
zones={timezoneList.zones}
getTimezoneOffset={(tzName: string) =>
getTimezoneOffset(tzName, referenceDate)
}
inputRef={inputRef}
openOnFocus
showIcon={false}
inputFontSize="14px"
inputPadding="2px 4px"
onClose={handleClose}
disableClearable={true}
/>
</Popover>
</>
)
}
export function useTimeZoneList() {
return useMemo(() => {
const zones = Object.keys(TIMEZONES.zones).sort()
const browserTz = resolveTimezone(browserDefaultTimeZone)
return { zones, browserTz, getTimezoneOffset }
}, [])
}