Created
May 20, 2025 16:48
-
-
Save Avi-E-Koenig/9f692934e456d78de6a83214bf0eec6a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// React and types | |
import * as React from 'react'; | |
import type { Dayjs } from 'dayjs/esm'; | |
// Dayjs and locales | |
import 'dayjs/locale/he'; | |
import 'dayjs/locale/en'; | |
// MUI X Date Pickers | |
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; | |
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; | |
import { DatePicker } from '@mui/x-date-pickers/DatePicker'; | |
// MUI Core and Components | |
import Box from '@mui/material/Box'; | |
import { createTheme, ThemeProvider, useTheme } from '@mui/material/styles'; | |
// Project hooks/constants | |
import { useApplicationConfigs } from '@/hooks/useApplicationConfig'; | |
import { LOCALE } from '@/theme'; | |
// RTL and styling utilities | |
import { prefixer } from 'stylis'; | |
import rtlPlugin from 'stylis-plugin-rtl'; | |
import createCache from '@emotion/cache'; | |
import { CacheProvider } from '@emotion/react'; | |
/** | |
* DateRangeSelector - Two MUI DatePickers (from/to) with i18n labels, using latest MUI X API and Dayjs. | |
* Controlled via props. Handles RTL layout and text alignment with full MUI RTL support. | |
*/ | |
export default function DateRangeSelector({ | |
from, | |
to, | |
setFrom, | |
setTo, | |
}: { | |
from: Dayjs | null; | |
to: Dayjs | null; | |
setFrom: (date: Dayjs | null) => void; | |
setTo: (date: Dayjs | null) => void; | |
}) { | |
const { locale, dir, isDark } = useApplicationConfigs(); | |
const content = { | |
[LOCALE.EN]: { | |
from: 'From', | |
to: 'To', | |
error: 'Invalid date range', | |
fromError: 'Start date cannot be after end date', | |
toError: 'End date cannot be before start date', | |
}, | |
[LOCALE.HE]: { | |
from: 'מתאריך', | |
to: 'עד תאריך', | |
error: 'טווח תאריכים לא תקין', | |
fromError: 'תאריך התחלה לא יכול להיות אחרי תאריך סיום', | |
toError: 'תאריך סיום לא יכול להיות לפני תאריך התחלה', | |
}, | |
}; | |
const t = content[locale] || content[LOCALE.EN]; | |
const adapterLocale = locale === LOCALE.HE ? 'he' : 'en'; | |
// RTL support setup | |
const existingTheme = useTheme(); | |
const theme = React.useMemo( | |
() => | |
dir === 'rtl' | |
? createTheme(existingTheme, { | |
direction: 'rtl', | |
}) | |
: existingTheme, | |
[existingTheme, dir] | |
); | |
const cacheRtl = React.useMemo( | |
() => createCache({ key: 'pickers-rtl-demo', stylisPlugins: [prefixer, rtlPlugin] }), | |
[] | |
); | |
// Validation | |
const isInvalid = !!(from && to && from.isAfter(to)); | |
const textAlign: 'left' | 'right' = dir === 'rtl' ? 'right' : 'left'; | |
const pickerProps = ( | |
label: string, | |
value: Dayjs | null, | |
onChange: (date: Dayjs | null) => void, | |
error: boolean, | |
helperText: string | |
) => ({ | |
label, | |
value, | |
onChange, | |
sx: { | |
'& .MuiFormLabel-root': { | |
color: isDark ? 'white !important' : 'black !important', | |
}, | |
'& fieldset': { | |
borderColor: isDark ? 'white !important' : 'black !important', | |
}, | |
'& .MuiFormHelperText-root': { | |
color: isDark ? 'white !important' : 'black !important', | |
}, | |
}, | |
slotProps: { | |
textField: { | |
inputProps: { style: { textAlign } }, | |
error, | |
helperText, | |
}, | |
...(dir === 'rtl' && { | |
desktopPaper: { dir: 'rtl' }, | |
mobilePaper: { dir: 'rtl' }, | |
}), | |
}, | |
}); | |
// const dynamicBgColor = isDark ? 'var(--secondary-bg-dark)' : 'var(--secondary-bg-light)'; | |
const PickerContent = ( | |
<LocalizationProvider dateAdapter={AdapterDayjs} adapterLocale={adapterLocale}> | |
<Box | |
dir={dir} | |
sx={{ | |
// backgroundColor: dynamicBgColor, | |
borderRadius: 1, | |
width: 'max-content', | |
padding: 1, | |
display: 'flex', | |
gap: 2, | |
flexDirection: 'column', | |
}} | |
> | |
<Box sx={{ display: 'flex', gap: 2 }}> | |
<DatePicker | |
{...pickerProps(t.from, from, setFrom, isInvalid, isInvalid ? t.fromError : '')} | |
/> | |
<DatePicker {...pickerProps(t.to, to, setTo, isInvalid, isInvalid ? t.toError : '')} /> | |
</Box> | |
</Box> | |
</LocalizationProvider> | |
); | |
if (dir === 'rtl') { | |
return ( | |
<CacheProvider value={cacheRtl}> | |
<ThemeProvider theme={theme}>{PickerContent}</ThemeProvider> | |
</CacheProvider> | |
); | |
} | |
return PickerContent; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment