1import * as SMS from 'expo-sms'; 2import React from 'react'; 3import { Button, StyleSheet, Text, TextInput, View } from 'react-native'; 4 5interface State { 6 phoneNumbers: string[]; 7 message?: string; 8 error?: string; 9 result?: string; 10} 11 12// See: https://github.com/expo/expo/pull/10229#discussion_r490961694 13// eslint-disable-next-line @typescript-eslint/ban-types 14export default class SMSScreen extends React.Component<{}, State> { 15 static navigationOptions = { 16 title: 'SMS', 17 }; 18 19 readonly state: State = { 20 phoneNumbers: [], 21 }; 22 23 _sendSMS = async () => { 24 const isAvailable = await SMS.isAvailableAsync(); 25 if (!isAvailable) { 26 this.setState({ 27 error: 'SMS functionality is not available on this device!', 28 }); 29 setTimeout(() => this.setState({ error: undefined }), 10000); 30 return; 31 } 32 try { 33 if (this.state.message) { 34 const { result } = await SMS.sendSMSAsync(this.state.phoneNumbers, this.state.message); 35 this.setState({ phoneNumbers: [], message: undefined, result }); 36 setTimeout(() => this.setState({ result: undefined }), 5000); 37 } 38 } catch (e) { 39 this.setState({ error: e.message }); 40 setTimeout(() => this.setState({ error: undefined }), 10000); 41 } 42 }; 43 44 _sendSMSWithInvalidRecipient = async (address: null | undefined) => { 45 const isAvailable = await SMS.isAvailableAsync(); 46 if (!isAvailable) { 47 this.setState({ 48 error: 'SMS functionality is not available on this device!', 49 }); 50 setTimeout(() => this.setState({ error: undefined }), 10000); 51 return; 52 } 53 try { 54 if (this.state.message) { 55 // @ts-ignore -- testing if addresses === null is handled 56 // expected behavior: exception is thrown 57 const { result } = await SMS.sendSMSAsync(address, this.state.message); 58 this.setState({ phoneNumbers: [], message: undefined, result }); 59 setTimeout(() => this.setState({ result: undefined }), 5000); 60 } 61 } catch (e) { 62 this.setState({ error: e.message }); 63 setTimeout(() => this.setState({ error: undefined }), 10000); 64 } 65 }; 66 67 render() { 68 return ( 69 <View style={styles.container}> 70 <TextInput 71 style={styles.phoneNumbers} 72 placeholder="Phone numbers, comma separated" 73 value={this.state.phoneNumbers.join(',')} 74 onChangeText={(phoneNumbers) => 75 this.setState({ 76 phoneNumbers: phoneNumbers.split(',').map((e) => e.trim()), 77 }) 78 } 79 /> 80 <TextInput 81 style={styles.message} 82 placeholder="Message" 83 value={this.state.message} 84 onChangeText={(message) => this.setState({ message })} 85 /> 86 <Button title="Send" disabled={!this.state.message} onPress={this._sendSMS}> 87 Send SMS 88 </Button> 89 <Button 90 title="Send message with null recipient" 91 disabled={!this.state.message} 92 onPress={() => this._sendSMSWithInvalidRecipient(undefined)}> 93 Send SMS 94 </Button> 95 <Button 96 title="Send message with undefined recipient" 97 disabled={!this.state.message} 98 onPress={() => this._sendSMSWithInvalidRecipient(null)}> 99 Send SMS 100 </Button> 101 {this.state.error && ( 102 <View style={[styles.textView, styles.errorView]}> 103 <Text style={styles.errorText}>{this.state.error}</Text> 104 </View> 105 )} 106 {this.state.result && ( 107 <View style={[styles.textView, styles.resultView]}> 108 <Text>{this.state.result}</Text> 109 </View> 110 )} 111 </View> 112 ); 113 } 114} 115 116const styles = StyleSheet.create({ 117 container: { 118 flex: 1, 119 marginBottom: 10, 120 padding: 10, 121 }, 122 phoneNumbers: { 123 height: 40, 124 }, 125 message: { 126 height: 40, 127 }, 128 errorView: { 129 backgroundColor: 'red', 130 }, 131 resultView: { 132 borderColor: 'blue', 133 borderWidth: 2, 134 }, 135 textView: { 136 height: 60, 137 justifyContent: 'center', 138 alignItems: 'center', 139 padding: 20, 140 marginTop: 20, 141 marginBottom: 20, 142 }, 143 errorText: { 144 color: 'white', 145 }, 146}); 147