feat: replace TextField with MUI DatePicker and TimePicker in DateTimeFields

- Replace native HTML date/time inputs with MUI X Date Pickers components
- Add DatePicker for start/end dates
- Add TimePicker for start/end times
This commit is contained in:
lenhanphung
2025-10-27 16:33:47 +07:00
committed by Benoit TELLIER
parent 01f79553c0
commit 3c75a7e82e
@@ -1,5 +1,10 @@
import React from "react"; import React from "react";
import { Box, TextField, Typography } from "@mui/material"; import { Box, Typography } from "@mui/material";
import { DatePicker } from "@mui/x-date-pickers/DatePicker";
import { TimePicker } from "@mui/x-date-pickers/TimePicker";
import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider";
import { AdapterMoment } from "@mui/x-date-pickers/AdapterMoment";
import moment, { Moment } from "moment";
/** /**
* Props for DateTimeFields component * Props for DateTimeFields component
@@ -40,104 +45,130 @@ export const DateTimeFields: React.FC<DateTimeFieldsProps> = ({
onEndTimeChange, onEndTimeChange,
}) => { }) => {
return ( return (
<Box display="flex" gap={1} flexDirection="column"> <LocalizationProvider dateAdapter={AdapterMoment} adapterLocale="en">
{/* First row: 4 fields */} <Box display="flex" gap={1} flexDirection="column">
<Box display="flex" gap={1} flexDirection="row" alignItems="flex-start"> {/* First row: 4 fields */}
{/* Start Date - 30% */} <Box display="flex" gap={1} flexDirection="row" alignItems="flex-start">
<Box sx={{ flexGrow: 0.3, flexBasis: "30%" }}> {/* Start Date - 30% */}
{showMore && ( <Box sx={{ flexGrow: 0.3, flexBasis: "25%", minWidth: 0 }}>
<Typography variant="caption" display="block" mb={0.5}> {showMore && (
Start Date <Typography variant="caption" display="block" mb={0.5}>
</Typography> Start Date
)} </Typography>
<TextField )}
fullWidth <DatePicker
label={!showMore ? "Start Date" : ""} label={!showMore ? "Start Date" : ""}
type="date" value={startDate ? moment(startDate) : null}
value={startDate} onChange={(newValue: Moment | null) => {
onChange={(e) => onStartDateChange(e.target.value)} onStartDateChange(newValue?.format("YYYY-MM-DD") || "");
size="small" }}
margin="dense" slotProps={{
InputLabelProps={{ shrink: true }} textField: {
/> size: "small",
</Box> margin: "dense" as const,
fullWidth: true,
InputLabelProps: { shrink: true },
sx: { width: "100%" },
},
}}
/>
</Box>
{/* Start Time - 20% */} {/* Start Time - 20% */}
<Box sx={{ flexGrow: 0.2, flexBasis: "20%" }}> <Box sx={{ flexGrow: 0.2, flexBasis: "25%", minWidth: 0 }}>
{showMore && ( {showMore && (
<Typography variant="caption" display="block" mb={0.5}> <Typography variant="caption" display="block" mb={0.5}>
Start Time Start Time
</Typography> </Typography>
)} )}
<TextField <TimePicker
fullWidth label={!showMore ? "Start Time" : ""}
label={!showMore ? "Start Time" : ""} value={startTime ? moment(startTime, "HH:mm") : null}
type="time" onChange={(newValue: Moment | null) => {
value={startTime} onStartTimeChange(newValue?.format("HH:mm") || "");
onChange={(e) => onStartTimeChange(e.target.value)} }}
disabled={allday} disabled={allday}
size="small" slotProps={{
margin="dense" textField: {
InputLabelProps={{ shrink: true }} size: "small",
/> margin: "dense" as const,
</Box> fullWidth: true,
InputLabelProps: { shrink: true },
sx: { width: "100%" },
},
}}
/>
</Box>
{/* End Time - 20% */} {/* End Time - 20% */}
<Box sx={{ flexGrow: 0.2, flexBasis: "20%" }}> <Box sx={{ flexGrow: 0.2, flexBasis: "25%", minWidth: 0 }}>
{showMore && ( {showMore && (
<Typography variant="caption" display="block" mb={0.5}> <Typography variant="caption" display="block" mb={0.5}>
End Time End Time
</Typography> </Typography>
)} )}
<TextField <TimePicker
fullWidth label={!showMore ? "End Time" : ""}
label={!showMore ? "End Time" : ""} value={endTime ? moment(endTime, "HH:mm") : null}
type="time" onChange={(newValue: Moment | null) => {
value={endTime} onEndTimeChange(newValue?.format("HH:mm") || "");
onChange={(e) => onEndTimeChange(e.target.value)} }}
disabled={allday} disabled={allday}
error={!!validation.errors.dateTime} slotProps={{
size="small" textField: {
margin="dense" size: "small",
InputLabelProps={{ shrink: true }} margin: "dense" as const,
/> fullWidth: true,
</Box> InputLabelProps: { shrink: true },
error: !!validation.errors.dateTime,
sx: { width: "100%" },
},
}}
/>
</Box>
{/* End Date - 30% */} {/* End Date - 30% */}
<Box sx={{ flexGrow: 0.3, flexBasis: "30%" }}> <Box sx={{ flexGrow: 0.3, flexBasis: "25%", minWidth: 0 }}>
{showMore && ( {showMore && (
<Typography variant="caption" display="block" mb={0.5}> <Typography variant="caption" display="block" mb={0.5}>
End Date End Date
</Typography> </Typography>
)} )}
<TextField <DatePicker
fullWidth label={!showMore ? "End Date" : ""}
label={!showMore ? "End Date" : ""} value={endDate ? moment(endDate) : null}
type="date" onChange={(newValue: Moment | null) => {
value={endDate} onEndDateChange(newValue?.format("YYYY-MM-DD") || "");
onChange={(e) => onEndDateChange(e.target.value)} }}
error={!!validation.errors.dateTime} slotProps={{
size="small" textField: {
margin="dense" size: "small",
InputLabelProps={{ shrink: true }} margin: "dense" as const,
/> fullWidth: true,
</Box> InputLabelProps: { shrink: true },
</Box> error: !!validation.errors.dateTime,
sx: { width: "100%" },
{/* Second row: Error message - 2 columns 50% each */} },
{validation.errors.dateTime && ( }}
<Box display="flex" gap={1} flexDirection="row"> />
{/* Empty left column - 50% */}
<Box sx={{ flexGrow: 0.5, flexBasis: "50%" }} />
{/* Error message right column - 50% */}
<Box sx={{ flexGrow: 0.5, flexBasis: "50%" }}>
<Typography variant="caption" color="error">
{validation.errors.dateTime}
</Typography>
</Box> </Box>
</Box> </Box>
)}
</Box> {/* Second row: Error message - 2 columns 50% each */}
{validation.errors.dateTime && (
<Box display="flex" gap={1} flexDirection="row">
{/* Empty left column - 50% */}
<Box sx={{ flexGrow: 0.5, flexBasis: "50%" }} />
{/* Error message right column - 50% */}
<Box sx={{ flexGrow: 0.5, flexBasis: "50%" }}>
<Typography variant="caption" sx={{ color: "error.main" }}>
{validation.errors.dateTime}
</Typography>
</Box>
</Box>
)}
</Box>
</LocalizationProvider>
); );
}; };