Skip to content

Commit 92c7c94

Browse files
feat: also check valid range in input mode + show errors
1 parent 69b5477 commit 92c7c94

File tree

10 files changed

+159
-79
lines changed

10 files changed

+159
-79
lines changed

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ export default function ReadMeExampleSingle() {
9090
onDismiss={onDismissSingle}
9191
date={date}
9292
onConfirm={onConfirmSingle}
93+
// validRange={{
94+
// startDate: new Date(2021, 1, 2), // optional
95+
// endDate: new Date(), // optional
96+
// }}
9397
// onChange={} // same props as onConfirm but triggered without confirmed by user
9498
// saveLabel="Save" // optional
9599
// label="Select date" // optional
@@ -140,6 +144,10 @@ export default function ReadMeExampleRange() {
140144
startDate={range.startDate}
141145
endDate={range.endDate}
142146
onConfirm={onConfirm}
147+
// validRange={{
148+
// startDate: new Date(2021, 1, 2), // optional
149+
// endDate: new Date(), // optional
150+
// }}
143151
// onChange={} // same props as onConfirm but triggered without confirmed by user
144152
// locale={'nl'} // optional
145153
// saveLabel="Save" // optional
@@ -189,6 +197,10 @@ export default function ReadMeExampleMultiple() {
189197
onDismiss={onDismiss}
190198
dates={dates}
191199
onConfirm={onConfirm}
200+
// validRange={{
201+
// startDate: new Date(2021, 1, 2), // optional
202+
// endDate: new Date(), // optional
203+
// }}
192204
// locale={'nl'} // optional
193205
// saveLabel="Save" // optional
194206
// label="Select period" // optional

example/src/AppInner.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,10 @@ function AppInner({
321321
onDismiss={onDismissSingle}
322322
date={date}
323323
onConfirm={onChangeSingle}
324+
validRange={{
325+
startDate: new Date(2021, 1, 2),
326+
// endDate: new Date(),
327+
}}
324328
// saveLabel="Save" // optional
325329
// label="Select date" // optional
326330
// animationType="slide" // optional, default is 'slide' on ios/android and 'none' on web

example/src/ReadMeExampleMultiple.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ export default function ReadMeExampleMultiple() {
3030
onDismiss={onDismiss}
3131
dates={dates}
3232
onConfirm={onConfirm}
33+
// validRange={{
34+
// startDate: new Date(2021, 1, 2), // optional
35+
// endDate: new Date(), // optional
36+
// }}
3337
// locale={'nl'} // optional
3438
// saveLabel="Save" // optional
3539
// label="Select period" // optional

example/src/ReadMeExampleRange.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ export default function ReadMeExampleRange() {
3636
startDate={range.startDate}
3737
endDate={range.endDate}
3838
onConfirm={onConfirm}
39+
// validRange={{
40+
// startDate: new Date(2021, 1, 2), // optional
41+
// endDate: new Date(), // optional
42+
// }}
3943
// onChange={} // same props as onConfirm but triggered without confirmed by user
4044
// locale={'nl'} // optional
4145
// saveLabel="Save" // optional

example/src/ReadMeExampleSingle.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ export default function ReadMeExampleSingle() {
3030
onDismiss={onDismissSingle}
3131
date={date}
3232
onConfirm={onConfirmSingle}
33+
// validRange={{
34+
// startDate: new Date(2021, 1, 2), // optional
35+
// endDate: new Date(), // optional
36+
// }}
3337
// onChange={} // same props as onConfirm but triggered without confirmed by user
3438
// saveLabel="Save" // optional
3539
// label="Select date" // optional

src/Date/Calendar.tsx

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import {
99
dateToUnix,
1010
DisableWeekDaysType,
1111
getInitialIndex,
12-
isDateWithinOptionalRange,
1312
} from './dateUtils'
1413

1514
import CalendarHeader from './CalendarHeader'
@@ -124,20 +123,9 @@ function Calendar(
124123
onChange
125124
)
126125
const datesRef = useLatest<CalendarDates>(dates)
127-
const validRangeStart = useLatest(validRange?.startDate)
128-
const validRangeEnd = useLatest(validRange?.endDate)
129126

130127
const onPressDate = useCallback(
131128
(d: Date) => {
132-
const isWithinValidRange = isDateWithinOptionalRange(d, {
133-
startDate: validRangeStart.current,
134-
endDate: validRangeEnd.current,
135-
})
136-
137-
if (!isWithinValidRange) {
138-
return
139-
}
140-
141129
if (mode === 'single') {
142130
;(onChangeRef.current as SingleChange)({
143131
date: d,
@@ -171,15 +159,7 @@ function Calendar(
171159
})
172160
}
173161
},
174-
[
175-
validRangeStart,
176-
validRangeEnd,
177-
mode,
178-
onChangeRef,
179-
startDateRef,
180-
endDateRef,
181-
datesRef,
182-
]
162+
[mode, onChangeRef, startDateRef, endDateRef, datesRef]
183163
)
184164

185165
const firstDate = startDate || date || dates?.[0]

src/Date/CalendarEdit.tsx

Lines changed: 48 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@ import {
66
Keyboard,
77
} from 'react-native'
88

9-
import { CalendarDate, ModeType } from './Calendar'
9+
import { CalendarDate, ModeType, ValidRangeType } from './Calendar'
1010
import { LocalState } from './DatePickerModalContent'
1111
import TextInputWithMask from '../TextInputMask'
12-
import { Text, useTheme } from 'react-native-paper'
12+
import { HelperText, useTheme } from 'react-native-paper'
13+
import { dateToUnix, isDateWithinOptionalRange } from './dateUtils'
1314

1415
function CalendarEdit({
1516
mode,
@@ -19,6 +20,7 @@ function CalendarEdit({
1920
endLabel = 'End',
2021
collapsed,
2122
onChange,
23+
validRange,
2224
}: {
2325
mode: ModeType
2426
label?: string
@@ -27,6 +29,7 @@ function CalendarEdit({
2729
state: LocalState
2830
collapsed: boolean
2931
onChange: (s: LocalState) => any
32+
validRange: ValidRangeType | undefined
3033
}) {
3134
const dateInput = React.useRef<TextInputNative | null>(null)
3235
const startInput = React.useRef<TextInputNative | null>(null)
@@ -80,6 +83,7 @@ function CalendarEdit({
8083
value={state.date}
8184
onChange={(date) => onChange({ ...state, date })}
8285
onSubmitEditing={onSubmitInput}
86+
validRange={validRange}
8387
/>
8488
) : null}
8589
{mode === 'range' ? (
@@ -91,6 +95,7 @@ function CalendarEdit({
9195
onChange={(startDate) => onChange({ ...state, startDate })}
9296
returnKeyType={'next'}
9397
onSubmitEditing={onSubmitStartInput}
98+
validRange={validRange}
9499
/>
95100
<View style={styles.separator} />
96101
<CalendarInput
@@ -100,6 +105,7 @@ function CalendarEdit({
100105
onChange={(endDate) => onChange({ ...state, endDate })}
101106
isEndDate
102107
onSubmitEditing={onSubmitEndInput}
108+
validRange={validRange}
103109
/>
104110
</>
105111
) : null}
@@ -117,6 +123,7 @@ function CalendarInputPure(
117123
returnKeyType,
118124
onSubmitEditing,
119125
locale,
126+
validRange,
120127
}: {
121128
locale?: undefined | string
122129
label: string
@@ -125,11 +132,12 @@ function CalendarInputPure(
125132
isEndDate?: boolean
126133
returnKeyType?: string
127134
onSubmitEditing?: () => any
135+
validRange: ValidRangeType | undefined
128136
},
129137
ref: any
130138
) {
131139
const theme = useTheme()
132-
const [error, setError] = React.useState(false)
140+
const [error, setError] = React.useState<null | string>(null)
133141
const formatter = React.useMemo(() => {
134142
return new Intl.DateTimeFormat(locale, {
135143
month: '2-digit',
@@ -156,15 +164,40 @@ function CalendarInputPure(
156164
const day = Number(date.slice(dayIndex, dayIndex + 2))
157165
const year = Number(date.slice(yearIndex, yearIndex + 4))
158166
const month = Number(date.slice(monthIndex, monthIndex + 2))
159-
if (!Number.isNaN(day) && !Number.isNaN(year) && !Number.isNaN(month)) {
160-
setError(false)
161-
if (isEndDate) {
162-
onChange(new Date(year, month - 1, day, 23, 59, 59))
163-
} else {
164-
onChange(new Date(year, month - 1, day))
165-
}
167+
168+
if (Number.isNaN(day) || Number.isNaN(year) || Number.isNaN(month)) {
169+
setError(inputFormat)
170+
return
171+
}
172+
173+
const finalDate = isEndDate
174+
? new Date(year, month - 1, day, 23, 59, 59)
175+
: new Date(year, month - 1, day)
176+
177+
const validStart = validRange?.startDate
178+
const validEnd = validRange?.endDate
179+
if (
180+
!isDateWithinOptionalRange(finalDate, {
181+
startUnix: validStart ? dateToUnix(validStart) : undefined,
182+
endUnix: validEnd ? dateToUnix(validEnd) : undefined,
183+
})
184+
) {
185+
let errors =
186+
validStart && validEnd
187+
? [`${formatter.format(validStart)} - ${formatter.format(validEnd)}`]
188+
: [
189+
validStart ? `> ${formatter.format(validStart)}` : '',
190+
validEnd ? `< ${formatter.format(validEnd)}` : '',
191+
]
192+
setError(errors.filter((n) => n).join(' '))
193+
return
194+
}
195+
196+
setError(null)
197+
if (isEndDate) {
198+
onChange(finalDate)
166199
} else {
167-
setError(true)
200+
onChange(finalDate)
168201
}
169202
}
170203
return (
@@ -181,20 +214,11 @@ function CalendarInputPure(
181214
returnKeyType={returnKeyType}
182215
onSubmitEditing={onSubmitEditing}
183216
keyboardAppearance={theme.dark ? 'dark' : 'default'}
217+
error={!!error}
184218
/>
185-
{error && (
186-
<Text
187-
style={[
188-
{
189-
color: theme.colors.error,
190-
},
191-
theme.fonts.medium,
192-
styles.errorText,
193-
]}
194-
>
195-
{inputFormat}
196-
</Text>
197-
)}
219+
<HelperText type="error" visible={!!error}>
220+
{error}
221+
</HelperText>
198222
</View>
199223
)
200224
}
@@ -207,10 +231,6 @@ const styles = StyleSheet.create({
207231
inputContainer: { flex: 1 },
208232
input: { flex: 1 },
209233
separator: { width: 12 },
210-
errorText: {
211-
textAlign: 'right',
212-
marginTop: 12,
213-
},
214234
})
215235

216236
export default React.memo(CalendarEdit)

src/Date/DatePickerModalContent.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ export function DatePickerModalContent(
179179
endLabel={props.endLabel}
180180
collapsed={collapsed}
181181
onChange={onInnerChange}
182+
validRange={validRange}
182183
/>
183184
}
184185
/>

0 commit comments

Comments
 (0)