fix: date time picker bugs has fixed
This commit is contained in:
parent
13a378b45c
commit
ffeb365e8d
@ -25,7 +25,7 @@ function BirthdayPage(): JSX.Element {
|
|||||||
const handleNext = () => navigate(routes.client.birthtime())
|
const handleNext = () => navigate(routes.client.birthtime())
|
||||||
const handleValid = (birthdate: string) => {
|
const handleValid = (birthdate: string) => {
|
||||||
dispatch(actions.birthdate.update(birthdate))
|
dispatch(actions.birthdate.update(birthdate))
|
||||||
setIsDisabled(false)
|
setIsDisabled(birthdate === '')
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -20,7 +20,7 @@ function BirthtimePage(): JSX.Element {
|
|||||||
<Title variant="h2" className="mt-24">{t('bornTimeQuestion')}</Title>
|
<Title variant="h2" className="mt-24">{t('bornTimeQuestion')}</Title>
|
||||||
<p className="description">{t('nasaDataUsing')}</p>
|
<p className="description">{t('nasaDataUsing')}</p>
|
||||||
<TimePicker value={birthtime} onChange={handleChange}/>
|
<TimePicker value={birthtime} onChange={handleChange}/>
|
||||||
<MainButton label={t('next')} onClick={handleNext} disabled={!birthtime}/>
|
<MainButton label={t('next')} onClick={handleNext}/>
|
||||||
</section>
|
</section>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,23 +1,23 @@
|
|||||||
import { FormField } from '../../types'
|
import { FormField } from '../../types'
|
||||||
import { normalize, calculateMaxValue } from './utils'
|
import { normalize, calculateMaxValue } from './utils'
|
||||||
|
|
||||||
type DatePartValue = number | undefined
|
type DatePartValue = string | undefined
|
||||||
|
|
||||||
type DateInputProps = Omit<FormField<DatePartValue>, 'onValid' | 'onInvalid'> & {
|
type DateInputProps = Omit<FormField<DatePartValue>, 'onValid' | 'onInvalid'> & {
|
||||||
max: number
|
max: number
|
||||||
maxLength: number
|
maxLength: number
|
||||||
onChange: (part: number) => void
|
onChange: (part: string) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
function DateInput(props: DateInputProps): JSX.Element {
|
function DateInput(props: DateInputProps): JSX.Element {
|
||||||
const { label, placeholder, name, value, max, maxLength, onChange } = props
|
const { label, placeholder, name, value = '', max, maxLength, onChange } = props
|
||||||
const validate = (value: number): boolean => value >= 0 && value <= max
|
const validate = (value: number): boolean => value >= 0 && value <= max
|
||||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const datePart = parseInt(e.target.value, 10)
|
const datePart = parseInt(e.target.value, 10)
|
||||||
if (isNaN(datePart)) return
|
if (isNaN(datePart)) return
|
||||||
if (datePart > calculateMaxValue(maxLength)) return
|
if (datePart > calculateMaxValue(maxLength)) return
|
||||||
if (!validate(datePart)) return
|
if (!validate(datePart)) return
|
||||||
onChange(datePart)
|
onChange(datePart > 0 ? normalize(datePart, maxLength) : '')
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className="date-picker__field">
|
<div className="date-picker__field">
|
||||||
@ -28,7 +28,7 @@ function DateInput(props: DateInputProps): JSX.Element {
|
|||||||
type="number"
|
type="number"
|
||||||
placeholder=" "
|
placeholder=" "
|
||||||
maxLength={maxLength}
|
maxLength={maxLength}
|
||||||
value={value ? normalize(value, maxLength) : ''}
|
value={value}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
/>
|
/>
|
||||||
<p className="date-picker__input-placeholder">{placeholder}</p>
|
<p className="date-picker__input-placeholder">{placeholder}</p>
|
||||||
|
|||||||
@ -3,30 +3,33 @@ import { useTranslation } from 'react-i18next'
|
|||||||
import { FormField } from '../../types'
|
import { FormField } from '../../types'
|
||||||
import DateInput from './DateInput'
|
import DateInput from './DateInput'
|
||||||
import ErrorText from './ErrorText'
|
import ErrorText from './ErrorText'
|
||||||
import { stringify, getMaxYear, isNotTheDate, getDaysInMonth } from './utils'
|
import { stringify, getCurrentYear } from './utils'
|
||||||
|
|
||||||
export function DatePicker(props: FormField<string>): JSX.Element {
|
export function DatePicker(props: FormField<string>): JSX.Element {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { name, value, onValid, onInvalid } = props
|
const { name, value, onValid, onInvalid } = props
|
||||||
|
const [initYear, initMonth, initDay] = value.split('-')
|
||||||
const date = new Date(value)
|
const [year, setYear] = useState(initYear)
|
||||||
|
const [month, setMonth] = useState(initMonth)
|
||||||
const [year, setYear] = useState(date.getFullYear())
|
const [day, setDay] = useState(initDay)
|
||||||
const [month, setMonth] = useState(date.getMonth())
|
|
||||||
const [day, setDay] = useState(date.getDate())
|
|
||||||
const [hasError, setHasError] = useState(false)
|
const [hasError, setHasError] = useState(false)
|
||||||
|
const isValid = (value: string) => {
|
||||||
|
const date = new Date(value)
|
||||||
|
const isCorrectDate = stringify(date) === value
|
||||||
|
const isNotFutureDate = date.getTime() <= Date.now()
|
||||||
|
const isNotMinDate = date.getFullYear() >= getCurrentYear() - 200
|
||||||
|
return isCorrectDate && isNotFutureDate && isNotMinDate
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isNaN(year) || isNaN(month) || isNaN(day)) return
|
if (year && month && day) {
|
||||||
const combinedDate = `${year}-${month}-${day}`
|
const currentValue = `${year}-${month}-${day}`
|
||||||
const date = new Date(combinedDate)
|
setHasError(!isValid(currentValue))
|
||||||
if (isNotTheDate(date)) {
|
isValid(currentValue) ? onValid(currentValue) : onInvalid()
|
||||||
setHasError(true)
|
} else {
|
||||||
onInvalid()
|
setHasError(false)
|
||||||
return
|
onValid('')
|
||||||
}
|
}
|
||||||
setHasError(false)
|
|
||||||
onValid(stringify(date))
|
|
||||||
}, [year, month, day, hasError, onValid, onInvalid])
|
}, [year, month, day, hasError, onValid, onInvalid])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -35,11 +38,11 @@ export function DatePicker(props: FormField<string>): JSX.Element {
|
|||||||
<DateInput
|
<DateInput
|
||||||
name='year'
|
name='year'
|
||||||
value={year}
|
value={year}
|
||||||
max={getMaxYear()}
|
max={getCurrentYear()}
|
||||||
maxLength={4}
|
maxLength={4}
|
||||||
label={t('year')}
|
label={t('year')}
|
||||||
placeholder='YYYY'
|
placeholder='YYYY'
|
||||||
onChange={(year: number) => setYear(year)}
|
onChange={(year: string) => setYear(year)}
|
||||||
/>
|
/>
|
||||||
<DateInput
|
<DateInput
|
||||||
name='month'
|
name='month'
|
||||||
@ -48,16 +51,16 @@ export function DatePicker(props: FormField<string>): JSX.Element {
|
|||||||
maxLength={2}
|
maxLength={2}
|
||||||
label={t('month')}
|
label={t('month')}
|
||||||
placeholder='MM'
|
placeholder='MM'
|
||||||
onChange={(month: number) => setMonth(month)}
|
onChange={(month: string) => setMonth(month)}
|
||||||
/>
|
/>
|
||||||
<DateInput
|
<DateInput
|
||||||
name='day'
|
name='day'
|
||||||
value={day}
|
value={day}
|
||||||
max={getDaysInMonth(year, month)}
|
max={31}
|
||||||
maxLength={2}
|
maxLength={2}
|
||||||
label={t('day')}
|
label={t('day')}
|
||||||
placeholder='DD'
|
placeholder='DD'
|
||||||
onChange={(day: number) => setDay(day)}
|
onChange={(day: string) => setDay(day)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<ErrorText
|
<ErrorText
|
||||||
|
|||||||
@ -6,7 +6,7 @@ export const calculateMaxValue = (digits: number): number => {
|
|||||||
return Math.pow(10, digits) - 1;
|
return Math.pow(10, digits) - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getMaxYear = (): number => {
|
export const getCurrentYear = (): number => {
|
||||||
return new Date().getFullYear()
|
return new Date().getFullYear()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,19 +23,15 @@ export const getDaysInMonth = (year: number, month: number): number => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const format = (hour: string, minute: string, period: string) => {
|
export const format = (hour: string, minute: string, period: string) => {
|
||||||
const formattedHour = period === 'AM' ? normalize(hour, 2) : String(Number(hour) + 12)
|
const formattedHour = hour === '12' ? (period === 'AM' ? '00' : '12') : (period === 'PM' ? String(Number(hour) + 12) : hour)
|
||||||
const formattedMinute = normalize(minute, 2)
|
const formattedMinute = normalize(minute, 2)
|
||||||
return `${formattedHour}:${formattedMinute}`
|
return `${formattedHour}:${formattedMinute}`
|
||||||
}
|
}
|
||||||
|
|
||||||
export const parse = (value: string) => {
|
export const parse = (value: string) => {
|
||||||
const [hour, minute] = value.split(':')
|
const [hourStr, minute] = value.split(':')
|
||||||
const numHour = Number(hour)
|
const hour = Number(hourStr)
|
||||||
const period = numHour < 12 ? 'AM' : 'PM'
|
const formattedHour = hour === 0 || hour === 12 ? '12' : hour > 12 ? String(hour - 12) : hourStr
|
||||||
const formattedHour = numHour > 12 ? String(numHour - 12) : String(numHour)
|
const period = hour < 12 ? 'AM' : 'PM'
|
||||||
return {
|
return { hour: formattedHour, minute, period }
|
||||||
hour: formattedHour,
|
|
||||||
minute,
|
|
||||||
period
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { useDispatch, useSelector } from 'react-redux'
|
|||||||
import { actions, RootState } from '../../store'
|
import { actions, RootState } from '../../store'
|
||||||
import Title from '../Title'
|
import Title from '../Title'
|
||||||
import Policy from '../Policy'
|
import Policy from '../Policy'
|
||||||
import EmailInput from '../EmailInput'
|
import EmailInput from './EmailInput'
|
||||||
import MainButton from '../MainButton'
|
import MainButton from '../MainButton'
|
||||||
import routes from '../../routes'
|
import routes from '../../routes'
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import type { PayloadAction } from '@reduxjs/toolkit'
|
|||||||
|
|
||||||
const birthtimeSlice = createSlice({
|
const birthtimeSlice = createSlice({
|
||||||
name: 'birthtime',
|
name: 'birthtime',
|
||||||
initialState: '',
|
initialState: '12:00',
|
||||||
reducers: {
|
reducers: {
|
||||||
update(state, action: PayloadAction<string>) {
|
update(state, action: PayloadAction<string>) {
|
||||||
state = action.payload
|
state = action.payload
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user