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 <Button 88 title="Send message with null recipient" 89 disabled={!this.state.message} 90 onPress={() => this._sendSMSWithInvalidRecipient(undefined)} 91 /> 92 <Button 93 title="Send message with undefined recipient" 94 disabled={!this.state.message} 95 onPress={() => this._sendSMSWithInvalidRecipient(null)} 96 /> 97 {this.state.error && ( 98 <View style={[styles.textView, styles.errorView]}> 99 <Text style={styles.errorText}>{this.state.error}</Text> 100 </View> 101 )} 102 {this.state.result && ( 103 <View style={[styles.textView, styles.resultView]}> 104 <Text>{this.state.result}</Text> 105 </View> 106 )} 107 </View> 108 ); 109 } 110} 111 112const styles = StyleSheet.create({ 113 container: { 114 flex: 1, 115 marginBottom: 10, 116 padding: 10, 117 }, 118 phoneNumbers: { 119 height: 40, 120 }, 121 message: { 122 height: 40, 123 }, 124 errorView: { 125 backgroundColor: 'red', 126 }, 127 resultView: { 128 borderColor: 'blue', 129 borderWidth: 2, 130 }, 131 textView: { 132 height: 60, 133 justifyContent: 'center', 134 alignItems: 'center', 135 padding: 20, 136 marginTop: 20, 137 marginBottom: 20, 138 }, 139 errorText: { 140 color: 'white', 141 }, 142}); 143