Files
donetick/src/views/components/DueDatePickerField.jsx
Mohamad Tarbin b2949b2dd9 Enhance project management UI and handle bulk changes (#186)
* enable hold to select, remove once x1 chip, unify reschedule modal

* project title still show fromwhen login from different account
it's was cache in local storage so makdikngsure we do clean up

* Fix: show the button for creating task on the modal instead of the panel

* Bulk moving project, Move the button in scanner to the modal

* - Handle bulk change for projects
- allow no assignee being selected
- choreactionmenu become modal on mobile
2026-08-02 16:14:52 -04:00

138 lines
3.6 KiB
JavaScript

import { CalendarMonth, Close } from '@mui/icons-material'
import { Box, Button, IconButton, Typography } from '@mui/joy'
import moment from 'moment'
import { useMemo, useState } from 'react'
import DueDatePickerModal from './DueDatePickerModal'
const DueDatePickerField = ({
dueDateOnly,
dueTime,
useCustomTime,
onDueDateChange,
onDueTimeChange,
onUseCustomTimeChange,
onClear,
emptyDisplay = 'icon-text',
size = 'sm',
}) => {
const [isOpen, setIsOpen] = useState(false)
const handleSave = ({
dueDateOnly: nextDate,
dueTime: nextTime,
useCustomTime: nextUseCustomTime,
}) => {
onDueDateChange?.({ target: { value: nextDate || '' } })
onUseCustomTimeChange?.(nextUseCustomTime)
onDueTimeChange?.({
target: { value: nextUseCustomTime && nextTime ? nextTime : '' },
})
setIsOpen(false)
}
const hasDueDate = Boolean(dueDateOnly)
const shouldShowLabel = hasDueDate || emptyDisplay === 'icon-text'
const dueDateLabel = useMemo(() => {
if (!dueDateOnly) {
return 'Due'
}
const formattedDate = moment(dueDateOnly).format('MMM D')
if (useCustomTime && dueTime) {
return `${formattedDate}, ${dueTime}`
}
return formattedDate
}, [dueDateOnly, dueTime, useCustomTime])
return (
<>
<Box
sx={{
position: 'relative',
display: 'flex',
alignItems: 'center',
}}
>
<Button
size={size}
variant={hasDueDate ? 'soft' : 'outlined'}
color='neutral'
onClick={() => setIsOpen(true)}
sx={{
minHeight: 40,
borderRadius: '128px',
minWidth: 'min-content',
px: shouldShowLabel ? 1.25 : 0.75,
gap: shouldShowLabel ? 1 : 0,
justifyContent: 'flex-start',
whiteSpace: 'nowrap',
transition: 'all 0.25s ease-in-out',
}}
>
<CalendarMonth sx={{ fontSize: '20px' }} />
<Typography
level='body-sm'
sx={{
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
maxWidth: shouldShowLabel ? 220 : 0,
opacity: shouldShowLabel ? 1 : 0,
transform: shouldShowLabel ? 'translateX(0)' : 'translateX(-4px)',
transition:
'max-width 0.25s ease-in-out, opacity 0.2s ease-in-out, transform 0.25s ease-in-out',
}}
>
{dueDateLabel}
</Typography>
</Button>
{hasDueDate && onClear && (
<IconButton
aria-label='Clear due date'
size='sm'
variant='soft'
color='danger'
onClick={e => {
e.stopPropagation()
onClear?.()
}}
sx={{
position: 'absolute',
top: -18,
right: -18,
zIndex: 10,
borderRadius: '50%',
'&:hover': {
bgcolor: 'danger.softBg',
},
}}
>
<Close sx={{ fontSize: '18px' }} />
</IconButton>
)}
</Box>
<DueDatePickerModal
open={isOpen}
onClose={() => setIsOpen(false)}
dueDateOnly={dueDateOnly}
dueTime={dueTime}
useCustomTime={useCustomTime}
onApply={handleSave}
onRemove={
onClear
? () => {
onClear()
setIsOpen(false)
}
: undefined
}
/>
</>
)
}
export default DueDatePickerField