1import DateTimePicker, { DateTimePickerEvent } from '@react-native-community/datetimepicker'; 2import SegmentedControl from '@react-native-segmented-control/segmented-control'; 3import moment from 'moment'; 4import React, { useRef, useState } from 'react'; 5import { 6 SafeAreaView, 7 ScrollView, 8 StyleSheet, 9 View, 10 Text, 11 StatusBar, 12 Platform, 13 TextInput, 14 useColorScheme, 15 Switch, 16 TextProps, 17 TextInputProps, 18 Button, 19} from 'react-native'; 20import { Colors } from 'react-native/Libraries/NewAppScreen'; 21 22export const DAY_OF_WEEK = Object.freeze({ 23 Sunday: 0, 24 Monday: 1, 25 Tuesday: 2, 26 Wednesday: 3, 27 Thursday: 4, 28 Friday: 5, 29 Saturday: 6, 30}); 31 32const ThemedText = (props: TextProps) => { 33 const isDarkMode = useColorScheme() === 'dark'; 34 35 const textColorByMode = { color: isDarkMode ? Colors.white : Colors.black }; 36 37 const TextElement = React.createElement(Text, props); 38 return React.cloneElement(TextElement, { 39 style: [props.style, textColorByMode], 40 }); 41}; 42const ThemedTextInput = (props: TextInputProps) => { 43 const isDarkMode = useColorScheme() === 'dark'; 44 45 const textColorByMode = { color: isDarkMode ? Colors.white : Colors.black }; 46 47 const TextElement = React.createElement(TextInput, props); 48 return React.cloneElement(TextElement, { 49 style: [props.style, styles.textInput, textColorByMode], 50 placeholderTextColor: isDarkMode ? Colors.white : Colors.black, 51 }); 52}; 53 54const MODE_VALUES = Platform.select({ 55 ios: ['date', 'time', 'datetime', 'countdown'], 56 android: ['date', 'time'], 57})! as ['date', 'time', 'datetime', 'countdown']; 58const DISPLAY_VALUES = Platform.select({ 59 ios: ['default', 'spinner', 'compact', 'inline'], 60 android: ['default', 'spinner', 'clock', 'calendar'], 61})! as ['default', 'spinner', 'clock', 'calendar']; 62const MINUTE_INTERVALS = [1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30]; 63 64// This example is a refactored copy from https://github.com/react-native-community/react-native-datetimepicker/tree/master/example 65// Please try to keep it up to date when updating @react-native-community/datetimepicker package :) 66 67const DateTimePickerScreen = () => { 68 // Sat, 13 Nov 2021 10:00:00 GMT (local: Saturday, November 13, 2021 11:00:00 AM GMT+01:00) 69 const sourceMoment = moment.unix(1636797600); 70 const sourceDate = sourceMoment.local().toDate(); 71 const [show, setShow] = useState(true); 72 const [date, setDate] = useState<Date>(sourceDate); 73 const [mode, setMode] = useState<'date' | 'time' | 'datetime' | 'countdown'>(MODE_VALUES[0]); 74 const [textColor, setTextColor] = useState<string | undefined>(); 75 const [accentColor, setAccentColor] = useState<string | undefined>(); 76 const [display, setDisplay] = useState<'default' | 'spinner' | 'clock' | 'calendar'>( 77 DISPLAY_VALUES[0] 78 ); 79 const [interval, setMinInterval] = useState(1); 80 const [neutralButtonLabel, setNeutralButtonLabel] = useState<string | undefined>(); 81 const [disabled, setDisabled] = useState(false); 82 83 const scrollRef = useRef<ScrollView>(null); 84 85 const onChange = (event: DateTimePickerEvent, selectedDate?: Date | undefined) => { 86 if (Platform.OS === 'android') { 87 setShow(false); 88 } 89 const currentDate = selectedDate || date; 90 if (event.type === 'neutralButtonPressed') { 91 setDate(new Date(0)); 92 } else { 93 setDate(currentDate); 94 } 95 }; 96 97 const isDarkMode = useColorScheme() === 'dark'; 98 99 const backgroundStyle = { 100 backgroundColor: isDarkMode ? Colors.dark : Colors.lighter, 101 }; 102 103 return ( 104 <SafeAreaView style={[backgroundStyle, { flex: 1 }]}> 105 <StatusBar barStyle="dark-content" /> 106 <ScrollView 107 testID="DateTimePickerScrollView" 108 ref={scrollRef} 109 onContentSizeChange={() => { 110 if (Platform.OS === 'ios') { 111 scrollRef.current?.scrollToEnd({ animated: true }); 112 } 113 }}> 114 {/* @ts-expect-error */} 115 {global.HermesInternal != null && ( 116 <View style={styles.engine}> 117 <Text testID="hermesIndicator" style={styles.footer}> 118 Engine: Hermes 119 </Text> 120 </View> 121 )} 122 <View 123 testID="appRootView" 124 style={{ backgroundColor: isDarkMode ? Colors.black : Colors.white }}> 125 <ThemedText>mode prop:</ThemedText> 126 <SegmentedControl 127 values={MODE_VALUES} 128 selectedIndex={MODE_VALUES.indexOf(mode)} 129 onChange={(event) => { 130 setMode(MODE_VALUES[event.nativeEvent.selectedSegmentIndex]); 131 }} 132 /> 133 <ThemedText>display prop:</ThemedText> 134 <SegmentedControl 135 values={DISPLAY_VALUES} 136 selectedIndex={DISPLAY_VALUES.indexOf(display)} 137 onChange={(event) => { 138 setDisplay(DISPLAY_VALUES[event.nativeEvent.selectedSegmentIndex]); 139 }} 140 /> 141 <ThemedText>minute interval prop:</ThemedText> 142 <SegmentedControl 143 values={MINUTE_INTERVALS.map(String)} 144 selectedIndex={MINUTE_INTERVALS.indexOf(interval)} 145 onChange={(event) => { 146 setMinInterval(MINUTE_INTERVALS[event.nativeEvent.selectedSegmentIndex]); 147 }} 148 /> 149 {Platform.OS === 'ios' && ( 150 <> 151 <View style={styles.header}> 152 <ThemedText style={styles.textLabel}>text color (iOS only)</ThemedText> 153 <ThemedTextInput 154 value={textColor} 155 onChangeText={(text) => { 156 setTextColor(text.toLowerCase()); 157 }} 158 placeholder="textColor" 159 /> 160 </View> 161 <View style={styles.header}> 162 <ThemedText style={styles.textLabel}>accent color (iOS only)</ThemedText> 163 <ThemedTextInput 164 value={accentColor} 165 onChangeText={(text) => { 166 setAccentColor(text.toLowerCase()); 167 }} 168 placeholder="accentColor" 169 /> 170 </View> 171 <View style={styles.header}> 172 <ThemedText style={styles.textLabel}>disabled (iOS only)</ThemedText> 173 <Switch value={disabled} onValueChange={setDisabled} /> 174 </View> 175 </> 176 )} 177 {Platform.OS === 'android' && ( 178 <> 179 <View style={styles.header}> 180 <ThemedText style={styles.textLabel}>neutralButtonLabel (android only)</ThemedText> 181 <ThemedTextInput 182 value={neutralButtonLabel} 183 onChangeText={setNeutralButtonLabel} 184 placeholder="neutralButtonLabel" 185 testID="neutralButtonLabelTextInput" 186 /> 187 </View> 188 <View style={styles.header}> 189 <ThemedText style={styles.textLabel}> 190 [android] show and dismiss picker after 3 secs 191 </ThemedText> 192 </View> 193 </> 194 )} 195 <View style={[styles.button, { flexDirection: 'row', justifyContent: 'space-around' }]}> 196 <Button 197 testID="showPickerButton" 198 onPress={() => { 199 setShow(true); 200 }} 201 title="Show picker!" 202 /> 203 <Button testID="hidePicker" onPress={() => setShow(false)} title="Hide picker!" /> 204 </View> 205 <View style={[styles.header, { flexDirection: 'row', justifyContent: 'space-around' }]}> 206 <ThemedText testID="dateText" style={styles.dateTimeText}> 207 {moment(date).format('MM/DD/YYYY HH:mm')} 208 </ThemedText> 209 </View> 210 {show && ( 211 <DateTimePicker 212 testID="dateTimePicker" 213 minuteInterval={interval} 214 value={date} 215 mode={mode} 216 is24Hour 217 display={display} 218 onChange={onChange} 219 style={styles.iOsPicker} 220 textColor={textColor || undefined} 221 accentColor={accentColor || undefined} 222 neutralButtonLabel={neutralButtonLabel} 223 disabled={disabled} 224 /> 225 )} 226 </View> 227 </ScrollView> 228 </SafeAreaView> 229 ); 230}; 231 232const styles = StyleSheet.create({ 233 scrollView: { 234 backgroundColor: Colors.lighter, 235 }, 236 engine: { 237 position: 'absolute', 238 right: 0, 239 }, 240 body: { 241 backgroundColor: Colors.white, 242 }, 243 footer: { 244 color: Colors.dark, 245 fontSize: 12, 246 fontWeight: '600', 247 padding: 4, 248 paddingRight: 12, 249 textAlign: 'right', 250 }, 251 container: { 252 marginTop: 32, 253 flex: 1, 254 justifyContent: 'center', 255 backgroundColor: '#F5FCFF', 256 }, 257 containerWindows: { 258 marginTop: 32, 259 flex: 1, 260 justifyContent: 'center', 261 alignItems: 'center', 262 backgroundColor: '#F5FCFF', 263 }, 264 header: { 265 justifyContent: 'center', 266 alignItems: 'center', 267 flexDirection: 'row', 268 }, 269 textLabel: { 270 margin: 10, 271 flex: 1, 272 }, 273 textInput: { 274 height: 60, 275 flex: 1, 276 }, 277 button: { 278 alignItems: 'center', 279 marginBottom: 10, 280 }, 281 resetButton: { 282 width: 150, 283 }, 284 text: { 285 fontSize: 20, 286 fontWeight: 'bold', 287 }, 288 dateTimeText: { 289 fontSize: 16, 290 fontWeight: 'normal', 291 }, 292 iOsPicker: { 293 flex: 1, 294 marginTop: 30, 295 }, 296 windowsPicker: { 297 flex: 1, 298 paddingTop: 10, 299 width: 350, 300 }, 301}); 302 303DateTimePickerScreen.navigationOptions = { 304 title: 'DateTimePicker', 305}; 306 307export default DateTimePickerScreen; 308