react-native-tx-modern-datetimepicker
Version:
Fix bugs and improve for lib: HosseinShabani/react-native-modern-datepicker. A customizable calendar, time & month picker for React Native
273 lines (259 loc) • 6.43 kB
JavaScript
import React, { useEffect, useRef, useState } from 'react'
import {
View,
StyleSheet,
Text,
Animated,
TouchableOpacity,
Easing,
Image,
TextInput,
I18nManager,
} from 'react-native'
import { useCalendar } from '../DatePicker'
const SelectMonth = () => {
const {
options,
state,
utils,
selectorStartingYear,
selectorEndingYear,
mode,
minimumDate,
maximumDate,
onMonthYearChange,
} = useCalendar()
const [mainState, setMainState] = state
const [show, setShow] = useState(false)
const style = styles(options)
const [year, setYear] = useState(utils.getMonthYearText(mainState.activeDate).split('#')[1])
const openAnimation = useRef(new Animated.Value(0)).current
const currentMonth = Number(utils.getDate(mainState.activeDate).format('MM'))
const prevDisable = maximumDate && utils.checkYearDisabled(Number(utils.toEnglish(year)), true)
const nextDisable = minimumDate && utils.checkYearDisabled(Number(utils.toEnglish(year)), false)
useEffect(() => {
mainState.monthOpen && setShow(true)
Animated.timing(openAnimation, {
toValue: mainState.monthOpen ? 1 : 0,
duration: 300,
delay: mainState.monthOpen ? 0 : 200,
useNativeDriver: true,
// easing: Easing.bezier(0.17, 0.67, 0.46, 1),
}).start(() => {
!mainState.monthOpen && setShow(false)
})
}, [mainState.monthOpen, openAnimation])
useEffect(() => {
show && setYear(utils.getMonthYearText(mainState.activeDate).split('#')[1])
}, [mainState.activeDate, utils, show])
const onSelectMonth = (month) => {
if (show) {
let y = Number(utils.toEnglish(year))
const date = utils.getDate(utils.validYear(mainState.activeDate, y))
const activeDate = month !== null ? date.month(month) : date
setMainState({
type: 'set',
activeDate: utils.getFormated(activeDate),
})
month !== null && onMonthYearChange(utils.getFormated(activeDate, 'monthYearFormat'))
month !== null &&
mode !== 'monthYear' &&
setMainState({
type: 'toggleMonth',
})
}
}
useEffect(() => {
onSelectMonth(null)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [prevDisable, nextDisable])
const onChangeYear = (text) => {
if (text === '') {
setYear('')
} else if (Number(utils.toEnglish(text))) {
setYear(utils.toPersianNumber(text))
}
}
const onSelectYear = (number) => {
let y = Number(utils.toEnglish(year)) + number
if (y === 0) {
y = new Date().getFullYear()
}
if (y > selectorEndingYear) {
y = selectorEndingYear
} else if (y < selectorStartingYear) {
y = selectorStartingYear
}
setYear(utils.toPersianNumber(y))
}
const containerStyle = [
style.container,
{
opacity: openAnimation,
transform: [
{
scale: openAnimation.interpolate({
inputRange: [0, 1],
outputRange: [1.1, 1],
}),
},
],
},
]
return show ? (
<Animated.View style={containerStyle}>
<View style={[style.header, I18nManager.isRTL && style.reverseHeader]}>
<TouchableOpacity
activeOpacity={0.7}
style={style.arrowWrapper}
onPress={() => !nextDisable && onSelectYear(-1)}
>
<Image
source={require('../../assets/arrow.png')}
style={[style.arrow, style.leftArrow, nextDisable && style.disableArrow]}
/>
</TouchableOpacity>
<TextInput
style={style.yearInput}
keyboardType="numeric"
maxLength={4}
value={year}
onBlur={() => onSelectYear(0)}
underlineColorAndroid={'rgba(0,0,0,0)'}
returnKeyType="done"
autoCorrect={false}
blurOnSubmit
selectionColor={options.mainColor}
onChangeText={onChangeYear}
/>
<TouchableOpacity
activeOpacity={0.7}
style={style.arrowWrapper}
onPress={() => !prevDisable && onSelectYear(+1)}
>
<Image
source={require('../../assets/arrow.png')}
style={[style.arrow, prevDisable && style.disableArrow]}
/>
</TouchableOpacity>
</View>
<View style={[style.monthList, utils.flexDirection]}>
{[...Array(12).keys()].map((item) => {
const disabled = utils.checkSelectMonthDisabled(mainState.activeDate, item)
return (
<TouchableOpacity
key={item}
activeOpacity={0.8}
style={[style.item, currentMonth === item + 1 && style.selectedItem]}
onPress={() => !disabled && onSelectMonth(item)}
>
<Text
style={[
style.itemText,
currentMonth === item + 1 && style.selectedItemText,
disabled && style.disabledItemText,
]}
>
{utils.getMonthName(item)}
</Text>
</TouchableOpacity>
)
})}
</View>
</Animated.View>
) : null
}
const styles = (theme) =>
StyleSheet.create({
container: {
position: 'absolute',
width: '100%',
height: '100%',
top: 0,
right: 0,
backgroundColor: theme.backgroundColor,
borderRadius: 10,
flexDirection: 'column',
zIndex: 999,
justifyContent: 'center',
alignItems: 'center',
},
header: {
alignItems: 'center',
paddingHorizontal: 15,
justifyContent: 'space-between',
width: '80%',
flexDirection: 'row',
},
reverseHeader: {
flexDirection: 'row-reverse',
},
monthList: {
flexWrap: 'wrap',
margin: 25,
},
item: {
width: '30%',
marginHorizontal: '1.5%',
paddingVertical: 8,
marginVertical: 7,
alignItems: 'center',
...theme.viewMonthItemStyle,
},
selectedItem: {
backgroundColor: theme.mainColor,
borderRadius: 12,
...theme.viewMonthItemSelectedStyle,
},
itemText: {
fontFamily: theme.defaultFont,
fontSize: theme.textFontSize,
color: theme.textDefaultColor,
...theme.textMonthStyle,
},
selectedItemText: {
color: theme.selectedTextColor,
},
disabledItemText: {
opacity: 0.2,
},
arrowWrapper: {
padding: 13,
position: 'relative',
zIndex: 1,
opacity: 1,
},
disableArrow: {
opacity: 0,
},
arrow: {
width: 18,
height: 18,
opacity: 0.9,
tintColor: theme.mainColor,
margin: 2,
...theme.imageArrow,
},
leftArrow: {
transform: [
{
rotate: '180deg',
},
],
},
arrowDisable: {
opacity: 0,
},
yearInput: {
fontSize: theme.textHeaderFontSize,
paddingVertical: 2,
paddingHorizontal: 4,
color: theme.textHeaderColor,
fontFamily: theme.headerFont,
textAlignVertical: 'center',
minWidth: 100,
textAlign: 'center',
...theme.inputYearStyle,
},
})
export { SelectMonth }