fix: date time picker bugs has fixed

This commit is contained in:
Aidar Shaikhutdin @makeweb.space 2023-05-08 20:47:21 +06:00
parent 13a378b45c
commit ffeb365e8d
9 changed files with 40 additions and 41 deletions

View File

@ -25,7 +25,7 @@ function BirthdayPage(): JSX.Element {
const handleNext = () => navigate(routes.client.birthtime())
const handleValid = (birthdate: string) => {
dispatch(actions.birthdate.update(birthdate))
setIsDisabled(false)
setIsDisabled(birthdate === '')
}
return (

View File

@ -20,7 +20,7 @@ function BirthtimePage(): JSX.Element {
<Title variant="h2" className="mt-24">{t('bornTimeQuestion')}</Title>
<p className="description">{t('nasaDataUsing')}</p>
<TimePicker value={birthtime} onChange={handleChange}/>
<MainButton label={t('next')} onClick={handleNext} disabled={!birthtime}/>
<MainButton label={t('next')} onClick={handleNext}/>
</section>
)
}

View File

@ -1,23 +1,23 @@
import { FormField } from '../../types'
import { normalize, calculateMaxValue } from './utils'
type DatePartValue = number | undefined
type DatePartValue = string | undefined
type DateInputProps = Omit<FormField<DatePartValue>, 'onValid' | 'onInvalid'> & {
max: number
maxLength: number
onChange: (part: number) => void
onChange: (part: string) => void
}
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 handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const datePart = parseInt(e.target.value, 10)
if (isNaN(datePart)) return
if (datePart > calculateMaxValue(maxLength)) return
if (!validate(datePart)) return
onChange(datePart)
onChange(datePart > 0 ? normalize(datePart, maxLength) : '')
}
return (
<div className="date-picker__field">
@ -28,7 +28,7 @@ function DateInput(props: DateInputProps): JSX.Element {
type="number"
placeholder=" "
maxLength={maxLength}
value={value ? normalize(value, maxLength) : ''}
value={value}
onChange={handleChange}
/>
<p className="date-picker__input-placeholder">{placeholder}</p>

View File

@ -3,30 +3,33 @@ import { useTranslation } from 'react-i18next'
import { FormField } from '../../types'
import DateInput from './DateInput'
import ErrorText from './ErrorText'
import { stringify, getMaxYear, isNotTheDate, getDaysInMonth } from './utils'
import { stringify, getCurrentYear } from './utils'
export function DatePicker(props: FormField<string>): JSX.Element {
const { t } = useTranslation()
const { name, value, onValid, onInvalid } = props
const date = new Date(value)
const [year, setYear] = useState(date.getFullYear())
const [month, setMonth] = useState(date.getMonth())
const [day, setDay] = useState(date.getDate())
const [initYear, initMonth, initDay] = value.split('-')
const [year, setYear] = useState(initYear)
const [month, setMonth] = useState(initMonth)
const [day, setDay] = useState(initDay)
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(() => {
if (isNaN(year) || isNaN(month) || isNaN(day)) return
const combinedDate = `${year}-${month}-${day}`
const date = new Date(combinedDate)
if (isNotTheDate(date)) {
setHasError(true)
onInvalid()
return
if (year && month && day) {
const currentValue = `${year}-${month}-${day}`
setHasError(!isValid(currentValue))
isValid(currentValue) ? onValid(currentValue) : onInvalid()
} else {
setHasError(false)
onValid('')
}
setHasError(false)
onValid(stringify(date))
}, [year, month, day, hasError, onValid, onInvalid])
return (
@ -35,11 +38,11 @@ export function DatePicker(props: FormField<string>): JSX.Element {
<DateInput
name='year'
value={year}
max={getMaxYear()}
max={getCurrentYear()}
maxLength={4}
label={t('year')}
placeholder='YYYY'
onChange={(year: number) => setYear(year)}
onChange={(year: string) => setYear(year)}
/>
<DateInput
name='month'
@ -48,16 +51,16 @@ export function DatePicker(props: FormField<string>): JSX.Element {
maxLength={2}
label={t('month')}
placeholder='MM'
onChange={(month: number) => setMonth(month)}
onChange={(month: string) => setMonth(month)}
/>
<DateInput
name='day'
value={day}
max={getDaysInMonth(year, month)}
max={31}
maxLength={2}
label={t('day')}
placeholder='DD'
onChange={(day: number) => setDay(day)}
onChange={(day: string) => setDay(day)}
/>
</div>
<ErrorText

View File

@ -6,7 +6,7 @@ export const calculateMaxValue = (digits: number): number => {
return Math.pow(10, digits) - 1;
}
export const getMaxYear = (): number => {
export const getCurrentYear = (): number => {
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) => {
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)
return `${formattedHour}:${formattedMinute}`
}
export const parse = (value: string) => {
const [hour, minute] = value.split(':')
const numHour = Number(hour)
const period = numHour < 12 ? 'AM' : 'PM'
const formattedHour = numHour > 12 ? String(numHour - 12) : String(numHour)
return {
hour: formattedHour,
minute,
period
}
const [hourStr, minute] = value.split(':')
const hour = Number(hourStr)
const formattedHour = hour === 0 || hour === 12 ? '12' : hour > 12 ? String(hour - 12) : hourStr
const period = hour < 12 ? 'AM' : 'PM'
return { hour: formattedHour, minute, period }
}

View File

@ -5,7 +5,7 @@ import { useDispatch, useSelector } from 'react-redux'
import { actions, RootState } from '../../store'
import Title from '../Title'
import Policy from '../Policy'
import EmailInput from '../EmailInput'
import EmailInput from './EmailInput'
import MainButton from '../MainButton'
import routes from '../../routes'

View File

@ -3,7 +3,7 @@ import type { PayloadAction } from '@reduxjs/toolkit'
const birthtimeSlice = createSlice({
name: 'birthtime',
initialState: '',
initialState: '12:00',
reducers: {
update(state, action: PayloadAction<string>) {
state = action.payload