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 const currentDate = selectedDate || date; 87 if (event.type === 'neutralButtonPressed') { 88 setDate(new Date(0)); 89 } else { 90 setDate(currentDate); 91 } 92 }; 93 94 const isDarkMode = useColorScheme() === 'dark'; 95 96 const backgroundStyle = { 97 backgroundColor: isDarkMode ? Colors.dark : Colors.lighter, 98 }; 99 100 return ( 101 <SafeAreaView style={[backgroundStyle, { flex: 1 }]}> 102 <StatusBar barStyle="dark-content" /> 103 <ScrollView 104 testID="DateTimePickerScrollView" 105 ref={scrollRef} 106 onContentSizeChange={() => { 107 if (Platform.OS === 'ios') { 108 scrollRef.current?.scrollToEnd({ animated: true }); 109 } 110 }}> 111 {/* @ts-expect-error */} 112 {global.HermesInternal != null && ( 113 <View style={styles.engine}> 114 <Text testID="hermesIndicator" style={styles.footer}> 115 Engine: Hermes 116 </Text> 117 </View> 118 )} 119 <View 120 testID="appRootView" 121 style={{ backgroundColor: isDarkMode ? Colors.black : Colors.white }}> 122 <ThemedText>mode prop:</ThemedText> 123 <SegmentedControl 124 values={MODE_VALUES} 125 selectedIndex={MODE_VALUES.indexOf(mode)} 126 onChange={(event) => { 127 setMode(MODE_VALUES[event.nativeEvent.selectedSegmentIndex]); 128 }} 129 /> 130 <ThemedText>display prop:</ThemedText> 131 <SegmentedControl 132 values={DISPLAY_VALUES} 133 selectedIndex={DISPLAY_VALUES.indexOf(display)} 134 onChange={(event) => { 135 setDisplay(DISPLAY_VALUES[event.nativeEvent.selectedSegmentIndex]); 136 }} 137 /> 138 <ThemedText>minute interval prop:</ThemedText> 139 <SegmentedControl 140 values={MINUTE_INTERVALS.map(String)} 141 selectedIndex={MINUTE_INTERVALS.indexOf(interval)} 142 onChange={(event) => { 143 setMinInterval(MINUTE_INTERVALS[event.nativeEvent.selectedSegmentIndex]); 144 }} 145 /> 146 {Platform.OS === 'ios' && ( 147 <> 148 <View style={styles.header}> 149 <ThemedText style={styles.textLabel}>text color (iOS only)</ThemedText> 150 <ThemedTextInput 151 value={textColor} 152 onChangeText={(text) => { 153 setTextColor(text.toLowerCase()); 154 }} 155 placeholder="textColor" 156 /> 157 </View> 158 <View style={styles.header}> 159 <ThemedText style={styles.textLabel}>accent color (iOS only)</ThemedText> 160 <ThemedTextInput 161 value={accentColor} 162 onChangeText={(text) => { 163 setAccentColor(text.toLowerCase()); 164 }} 165 placeholder="accentColor" 166 /> 167 </View> 168 <View style={styles.header}> 169 <ThemedText style={styles.textLabel}>disabled (iOS only)</ThemedText> 170 <Switch value={disabled} onValueChange={setDisabled} /> 171 </View> 172 </> 173 )} 174 {Platform.OS === 'android' && ( 175 <> 176 <View style={styles.header}> 177 <ThemedText style={styles.textLabel}>neutralButtonLabel (android only)</ThemedText> 178 <ThemedTextInput 179 value={neutralButtonLabel} 180 onChangeText={setNeutralButtonLabel} 181 placeholder="neutralButtonLabel" 182 testID="neutralButtonLabelTextInput" 183 /> 184 </View> 185 <View style={styles.header}> 186 <ThemedText style={styles.textLabel}> 187 [android] show and dismiss picker after 3 secs 188 </ThemedText> 189 </View> 190 </> 191 )} 192 <View style={[styles.button, { flexDirection: 'row', justifyContent: 'space-around' }]}> 193 <Button 194 testID="showPickerButton" 195 onPress={() => { 196 setShow(true); 197 }} 198 title="Show picker!" 199 /> 200 <Button testID="hidePicker" onPress={() => setShow(false)} title="Hide picker!" /> 201 </View> 202 <View style={[styles.header, { flexDirection: 'row', justifyContent: 'space-around' }]}> 203 <ThemedText testID="dateText" style={styles.dateTimeText}> 204 {moment(date).format('MM/DD/YYYY HH:mm')} 205 </ThemedText> 206 </View> 207 {show && ( 208 <DateTimePicker 209 testID="dateTimePicker" 210 minuteInterval={interval} 211 value={date} 212 mode={mode} 213 is24Hour 214 display={display} 215 onChange={onChange} 216 style={styles.iOsPicker} 217 textColor={textColor || undefined} 218 accentColor={accentColor || undefined} 219 neutralButtonLabel={neutralButtonLabel} 220 disabled={disabled} 221 /> 222 )} 223 </View> 224 </ScrollView> 225 </SafeAreaView> 226 ); 227}; 228 229const styles = StyleSheet.create({ 230 scrollView: { 231 backgroundColor: Colors.lighter, 232 }, 233 engine: { 234 position: 'absolute', 235 right: 0, 236 }, 237 body: { 238 backgroundColor: Colors.white, 239 }, 240 footer: { 241 color: Colors.dark, 242 fontSize: 12, 243 fontWeight: '600', 244 padding: 4, 245 paddingRight: 12, 246 textAlign: 'right', 247 }, 248 container: { 249 marginTop: 32, 250 flex: 1, 251 justifyContent: 'center', 252 backgroundColor: '#F5FCFF', 253 }, 254 containerWindows: { 255 marginTop: 32, 256 flex: 1, 257 justifyContent: 'center', 258 alignItems: 'center', 259 backgroundColor: '#F5FCFF', 260 }, 261 header: { 262 justifyContent: 'center', 263 alignItems: 'center', 264 flexDirection: 'row', 265 }, 266 textLabel: { 267 margin: 10, 268 flex: 1, 269 }, 270 textInput: { 271 height: 60, 272 flex: 1, 273 }, 274 button: { 275 alignItems: 'center', 276 marginBottom: 10, 277 }, 278 resetButton: { 279 width: 150, 280 }, 281 text: { 282 fontSize: 20, 283 fontWeight: 'bold', 284 }, 285 dateTimeText: { 286 fontSize: 16, 287 fontWeight: 'normal', 288 }, 289 iOsPicker: { 290 flex: 1, 291 marginTop: 30, 292 }, 293 windowsPicker: { 294 flex: 1, 295 paddingTop: 10, 296 width: 350, 297 }, 298}); 299 300DateTimePickerScreen.navigationOptions = { 301 title: 'DateTimePicker', 302}; 303 304export default DateTimePickerScreen; 305