Custom text input box, how to add margin - react-native-gifted-chat

I'm trying to make the input bar look like this:
but I can't get it to space properly. I also can't get rid of the line/divider. Right now, it looks like this:
There's no spacing on the bottom or the top
This is my code:
<GiftedChat
messages={messages}
onSend={newMessage => handleSend(newMessage)}
user={{ _id: 1 }} // ideally this would be the current user id
renderSystemMessage={customSystemMessage}
renderBubble={renderBubble}
renderInputToolbar={noinput ? () => (<View style = {{flex:1, backgroundColor: 'white'}}></View>) : (props) => renderInputToolbar(props)}
renderSend = {renderSend}
renderTime = {()=><View></View>}
renderAvatar={() => null}
placeholder='Write a message'
alwaysShowSend
inverted
/>
function renderInputToolbar(props) {
return (
<InputToolbar {...props} containerStyle={styles.input} />
);
}
input: {
borderRadius: 30,
backgroundColor: colorScheme.lightTeal,
marginLeft: 15,
marginRight: 15,
}
I can't seem to add a marginTop without because it makes my bar grow in height.

I believe you want to use a custom renderInputToolbar:
...
renderInputToolbar={noinput ? () => (<View style={{flex:1, backgroundColor: 'white'}}></View>) : (props) => (
<InputToolbar
renderActions={() => renderActions(props}
renderComposer={() => renderComposer(props)}
renderSend={() => renderSend(props)}
containerStyle={{ ...containerStylesGoHere }}
/>
)}

Related

Search from list in React Native

I just wanna know how can I make search function in react native. I have a very big list of text(in local js file) and also Text input space. I want to make possible when users type something they can find what they looking for from list below. Here is my code and screenshot of App. I'm new in programming so please use easy terms =) app screenshot
project datebase sample
import React from 'react';
import { SafeAreaView, View, FlatList, StyleSheet, Text, StatusBar, TextInput } from 'react-native';
import {DATA} from "../Data/AbrData";
const Item = ({ title }) => (
<View style={styles.item}>
<Text style={styles.title}>{title}</Text>
</View>
);
const SearchScreen = ({navigator}) => {
const renderItem = ({ item }) => (
<Item title={item.title} />
);
return (
<SafeAreaView style={styles.container}>
<TextInput
style={{
height: 50,
borderColor: '#919191',
borderWidth: 1,
margin: 10,
paddingLeft: 15,
borderRadius:10
}}
placeholder="Axtaris..."
/>
<FlatList
data={DATA}
renderItem={renderItem}
keyExtractor={item => item.id}
/>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: StatusBar.currentHeight || 0,
marginBottom:75,
},
item: {
backgroundColor: '#ededed',
padding: 20,
marginVertical: 2,
marginHorizontal: 10,
borderRadius: 20,
},
title: {
fontSize: 20,
},
});
export default SearchScreen;
Really Fast this is what I came up with.
import React, {useState, useEffect} from 'react';
import {
SafeAreaView,
StatusBar,
StyleSheet,
Text,
View,
FlatList,
TextInput,
} from 'react-native';
const App = () => {
const DATA = [{title: 'lorumn ispum'}, {title: 'lorumn ispum'}];
const [searchText, onChangeSearch] = useState('');
const [filteredData, setFilteredData] = useState([]);
useEffect(() => {
const filtered = DATA.filter(item =>
item.title.toLowerCase().includes(searchText.toLowerCase()),
);
if (searchText === '') {
return setFilteredData(DATA);
}
setFilteredData(filtered);
}, [searchText]);
const Item = ({title}) => (
<View style={styles.item}>
<Text style={styles.title}>{title}</Text>
</View>
);
const renderItem = ({item}) => <Item title={item.title} />;
return (
<SafeAreaView style={styles.container}>
<TextInput
style={{
height: 50,
borderColor: '#919191',
borderWidth: 1,
margin: 10,
paddingLeft: 15,
borderRadius: 10,
}}
onChangeText={newText => onChangeSearch(newText)}
placeholder="Axtaris..."
/>
<FlatList
data={filteredData}
renderItem={renderItem}
keyExtractor={(item, index) => item.key}
/>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: StatusBar.currentHeight || 0,
marginBottom: 75,
},
item: {
backgroundColor: '#ededed',
padding: 20,
marginVertical: 2,
marginHorizontal: 10,
borderRadius: 20,
},
title: {
fontSize: 20,
},
});
export default App;
I suggest watching this video! I learned how to simply filter a list from this video. Its plain js but the idea is the same.
https://www.youtube.com/watch?v=TlP5WIxVirU&ab_channel=WebDevSimplified
If you look at the repo of that video it boils down to the following:
searchInput.addEventListener("input", e => {
const value = e.target.value.toLowerCase()
users.forEach(user => {
const isVisible =
user.name.toLowerCase().includes(value) ||
user.email.toLowerCase().includes(value)
user.element.classList.toggle("hide", !isVisible)
})
})
Everytime the input changes (someone type something in the search field), the event listener is fired and converts the fields to lower case and compares it to the value your looking for. If the text contains the value it unhides it from the list. it does this for every entry in your dataset and thus filters the dataset to what you are looking for.

react native `TouchableOpacity` in 'absolute' view can not be clickable on android

I'v try to make a SlectBox with react native.
To make that dropdown menu can be floated, I gava an absolute position to wrapper View, then make a clickable component with TouchableOpacity inside that View. It works well on Ios and Web, but not on android. There were many solutions on google like reordering component or give a zIndex to WrapperView or use Pressable etc.., but I could not find proper solution for my case.
Belows are my whole code. and You can test this code here.
Thank you in advance.
import {
Animated,
Easing,
Platform,
StyleProp,
TextStyle,
TouchableOpacity,
View,
ViewStyle,
} from 'react-native';
import {DoobooTheme, light, useTheme} from '../theme';
import React, {FC, ReactElement, useEffect, useRef, useState} from 'react';
import {Icon} from '../Icon';
import {Typography} from '../Typography';
import styled from '#emotion/native';
import {withTheme} from '#emotion/react';
const Title = styled.View`
width: 200px;
height: 30px;
border-width: 1px;
flex-direction: row;
justify-content: center;
align-items: center;
`;
const Item = styled.View`
height: 30px;
width: 200px;
border-bottom-width: 1px;
border-left-width: 1px;
border-right-width: 1px;
justify-content: center;
align-items: center;
`;
type Styles = {
titleContainer?: StyleProp<ViewStyle>;
titleText?: StyleProp<TextStyle>;
rightElementContainer?: StyleProp<ViewStyle>;
itemContainer?: StyleProp<ViewStyle>;
itemText?: StyleProp<TextStyle>;
};
interface ItemCompProps {
value: string;
order: number;
styles?: Styles;
setIsOpened: (value: boolean) => void;
itemActiveOpacity: number;
onPress?: (i: number) => void;
}
const ItemComp: FC<ItemCompProps> = ({
value,
order,
styles,
setIsOpened,
itemActiveOpacity,
onPress,
}) => {
const {theme} = useTheme();
const handlePress = (): void => {
onPress?.(order);
setIsOpened(false);
};
return (
<TouchableOpacity onPress={handlePress} activeOpacity={itemActiveOpacity}>
<Item
style={[
{
borderColor: theme.primary,
backgroundColor: theme.textContrast,
},
styles?.itemContainer,
]}>
<Typography.Body2 style={styles?.itemText}>{value}</Typography.Body2>
</Item>
</TouchableOpacity>
);
};
interface Props {
data: string[];
onPress?: (i: number) => void;
selectedIndex?: number;
theme?: DoobooTheme;
style?: StyleProp<ViewStyle>;
styles?: Styles;
rotateDuration?: number;
titleActiveOpacity?: number;
itemActiveOpacity?: number;
isRotate?: boolean;
rightElement?: ReactElement | null;
}
const Component: FC<Props> = ({
data,
onPress,
selectedIndex = 0,
style,
styles,
rotateDuration = 200,
titleActiveOpacity = 1,
itemActiveOpacity = 1,
isRotate: shouldRotate = true,
rightElement = <Icon name="chevron-down-light" />,
}) => {
const {theme} = useTheme();
const [isOpened, setIsOpened] = useState(false);
const rotateAnimValue = useRef(new Animated.Value(0)).current;
useEffect(() => {
const toValue = isOpened ? 1 : 0;
if (!shouldRotate) rotateAnimValue.setValue(toValue);
Animated.timing(rotateAnimValue, {
toValue,
duration: rotateDuration,
easing: Easing.linear,
useNativeDriver: Platform.OS !== 'web' ? true : false,
}).start();
}, [isOpened, rotateAnimValue, rotateDuration, shouldRotate]);
return (
<View style={[style]}>
<TouchableOpacity
onPress={() => setIsOpened((prev) => !prev)}
activeOpacity={titleActiveOpacity}>
<Title
style={[
{
borderColor: theme.primary,
backgroundColor: theme.textContrast,
},
styles?.titleContainer,
]}>
<Typography.Body2 style={styles?.titleText} testID="selected-value">
{data[selectedIndex]}
</Typography.Body2>
{rightElement ? (
<Animated.View
style={[
{
position: 'absolute',
right: 10,
transform: [
{
rotate: rotateAnimValue.interpolate({
inputRange: [0, 1],
outputRange: ['0deg', '180deg'],
}),
},
],
},
styles?.rightElementContainer,
]}>
{rightElement}
</Animated.View>
) : null}
</Title>
</TouchableOpacity>
<View>
<View style={{position: 'absolute'}}>
{isOpened &&
data.map((datum, key) => (
<ItemComp
key={key}
order={key}
value={datum}
styles={styles}
setIsOpened={setIsOpened}
onPress={onPress}
itemActiveOpacity={itemActiveOpacity}
/>
))}
</View>
</View>
</View>
);
};
Component.defaultProps = {theme: light};
export const SelectBox = withTheme(Component);
My solution
I resolved this problem with react-native-gesture-handler. :)
Install react-native-gesture-handler, then using TouchableOpacity from that.
Try to render out the component you want to be on top of stack below the component you want to bring below it
How I solve this issue:
I was implementing custom dynamic toaster using context to use it globally and wasn't able to access touchable opacity due to absolute positioning but i realized i was rendering my Toaster component before my main Stack Navigator which was bringing my toaster below navigation layer so i rendered it after stack navigator and it worked
BEFORE:
<ToasterContext.Provider value={{toasts:this.state.toastState, showToaster: this.showToaster,closeToaster: this.closeToaster }}>
<Provider store={store.store}>
<PersistGate loading={null} persistor={store.persistor}>
{toastState.length > 0
&& toastState.length <= 3
&& toastState.map((t, i) => {
return(
<DynamicToast i={i} key={i} t={t} position={"bottom"} duration={4000} closeToaster={this.closeToaster} />
)
}
)}
<NetworkConnectionModal/>
<AppContainer /> // I was rendering before my AppContainer
</PersistGate>
</Provider>
</ToasterContext.Provider>
AFTER: (Resolved my problem)
<ToasterContext.Provider value={{toasts:this.state.toastState, showToaster: this.showToaster,closeToaster: this.closeToaster }}>
<Provider store={store.store}>
<PersistGate loading={null} persistor={store.persistor}>
<NetworkConnectionModal/>
<AppContainer />
{toastState.length > 0
&& toastState.length <= 3
&& toastState.map((t, i) => {
return(
<DynamicToast i={i} key={i} t={t} position={"bottom"} duration={4000} closeToaster={this.closeToaster} />
)
}
)}
</PersistGate>
</Provider>
</ToasterContext.Provider>
Most of this is because the element is hidden behind other elements after absolute positioning.
Just like the picture in PPT is set to the bottom, but in some cases in HTML, you can still see your element. In this case, we need to set this element to the top.
Open the developer tool, select your element, add a Z-index to the element style of this element, and increase from 2 to see which value can just select your element. After confirmation, add a style to the project file.
z-index: 2,//add this to your component style

How to provide live alerts to multiple phones with React Native

I coded an app that will create a modal that gives the option to alert reception that a customer is coming. However, when running the app on two phones, all changes are local. Why is that? I want to be able to "Alert Reception" and have reception receive a notification of the customer and be able to click More Info and see all the details about it.
We scan a customer QR code, and allow the security guard to validate and then alert reception and send the info to them.
Any ideas? We are using AWS and React Native. I would like to alert everyone and then be able to have the reception see the customer is coming and get the info.
import { StyleSheet, Text, View, Image, Button, Modal, Platform, ScrollView } from 'react-native';
import { BarCodeScanner } from 'expo-barcode-scanner';
import Constants from 'expo-constants';
import * as Notifications from 'expo-notifications';
import { Audio, Video } from 'expo-av';
//For push notifications
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldShowAlert: true,
shouldPlaySound: true,
shouldSetBadge: false,
}),
});
export default function App() {
//QR Scanner
const [hasPermission, setHasPermission] = useState(null);
const [scanned, setScanned] = useState(false);
const [newData, setNewData] = useState('');
//Modal Views
const [homeScreenVisible, setHomeScreenVisible] = useState(true);
const [customerModalVisible, setCustomerModalVisible] = useState(false);
const [customerModalDetailedVisible, setCustomerModalDetailedVisible] = useState(false);
const [qrScannerVisible, setQRScannerVisible] = useState(false);
//Push notifications
const [expoPushToken, setExpoPushToken] = useState('');
const [notification, setNotification] = useState(false);
const notificationListener = useRef();
const responseListener = useRef();
//useEffects are rendered upon app start. We use the [] to make sure they are only rendered once. If you want them to update, add in the array / state var and upon update the useEffect will run again.
//For Bar Code Scanner
useEffect(() => {
(async () => {
const { status } = await BarCodeScanner.requestPermissionsAsync();
setHasPermission(status === 'granted');
})();
}, []);
//For Push Notifications
useEffect(() => {
registerForPushNotificationsAsync().then(token => setExpoPushToken(token));
// This listener is fired whenever a notification is received while the app is foregrounded
notificationListener.current = Notifications.addNotificationReceivedListener(notification => {
setNotification(notification);
});
// This listener is fired whenever a user taps on or interacts with a notification (works when app is foregrounded, backgrounded, or killed)
responseListener.current = Notifications.addNotificationResponseReceivedListener(response => {
console.log(response);
console.log('Someone clicked on the push notification')
});
return () => {
Notifications.removeNotificationSubscription(notificationListener.current);
Notifications.removeNotificationSubscription(responseListener.current);
};
}, []);
//Bar Code scanner function, reads the data (which is a aws s3 endpoint served through cloudfront), then I run a fetch on the url (aka data), and then turn the string response into a json. Then I set newData equal to the JSON object via React Hooks. Then I turn the QR scanner visible off, and then open the customer modal.
const handleBarCodeScanned = ({ type, data }) => {
setScanned(true);
console.log(data) // Should be the url JSON endpoint
fetch(data)
.then(response => response.json())
.then(response => {
console.log(response)
setNewData(response)
});
setQRScannerVisible(false);
setCustomerModalVisible(true);
// const playbackObject = new Audio.Sound();
};
if (hasPermission === null) {
return <Text>Requesting for camera permission</Text>;
}
if (hasPermission === false) {
return <Text>No access to camera</Text>;
}
// We are returning a View with multiple JS {} fragments that turn off and on depending on state. There is an issue with setScanned(false) that sometimes the scanner is not set to false and it will not rescan. If you run into that problem, try adding setScanned(false).
return (
<ScrollView style={{flex: 1, backgroundColor: 'black'}}>
<View id="view" style={styles.container}>
{homeScreenVisible &&
<>
<Image
source={{
uri: "https://d1s68zh8fdz4eb.cloudfront.net/logo.png"
}}
style={{
height: 500,
width: '100%',
// borderWidth: 5,
// borderColor: '#fff',
marginTop: 30,
marginBottom: 20
}}
/>
<Button title="Scan QR Code" style={styles.moreInfo} onPress={() => {
setScanned(false)
setHomeScreenVisible(false)
setQRScannerVisible(true)
}} />
</>
}
{qrScannerVisible &&
<>
<Image
source={{
uri: "https://d1s68zh8fdz4eb.cloudfront.net/logo.png"
}}
style={{
height: 100,
width: 100,
borderWidth: 5,
marginBottom: 60
}}
/>
<BarCodeScanner
onBarCodeScanned={scanned ? undefined : handleBarCodeScanned}
// style={StyleSheet.absoluteFillObject}
style={{width: 300, height: 300, borderWidth: 5, borderColor: '#fff'}}
//If you want to switch to a absolute fill object, add the target area on the screen for scanning and try to add a sound.
// If you want to use the front facing or rear facing, include type={'front'} or put 'back'
/>
<Text style={{color: '#fff', fontSize: 30, marginTop: 30, marginBottom: 30}}>Scan QR Code</Text>
<Button title="Home" onPress={() => {
setHomeScreenVisible(true)
setQRScannerVisible(false)
setScanned(false)
}} />
</>
}
{/* Used for re scanning things. It is commented out because someoen can always go back to home and rescan. However, if you want to reintroduce a rescan button, you can do it with the below code.*/}
{/* {scanned && <Button title={'Tap to Scan Again'} onPress={() => {
setScanned(false)
}} />}
*/}
{customerModalVisible &&
<Modal style={styles.modal}>
<View style={styles.modalView}>
<Image
source={{
uri: "https://d1s68zh8fdz4eb.cloudfront.net/logo.png"
}}
style={{
height: 100,
width: 100,
borderWidth: 5,
marginBottom: 60
}}
/>
<View style={styles.modalInside}>
<Image
style={{
height: 300,
width: 300,
marginBottom: 20,
borderWidth: 5,
borderColor: 'gold'
}}
source={{
uri: newData.photo,
}}
/>
<Text style={styles.modalTextName}>{newData.name}</Text>
<Text style={styles.modalTextSecondary}>Favorite Drink: {newData.favoriteDrink}</Text>
<Text style={styles.modalTextSecondary}>Lead Contact: Leah</Text>
</View>
<Button title="Alert Reception" style={styles.closeButton} onPress={async () => {
await sendPushNotification(expoPushToken);
alert('Reception has been notified.')
}} />
<Button title="More Info" style={styles.moreInfo} onPress={() => {
// PushCustomerStatus();
setCustomerModalDetailedVisible(true)
setCustomerModalVisible(false)
setScanned(false)
setQRScannerVisible(false)
// Add modal # 2 or page navigation here
}} />
<Button title="Close" style={styles.closeButton} onPress={() => {
setHomeScreenVisible(true)
setCustomerModalVisible(false)
setScanned(false)
setQRScannerVisible(false)
}} />
</View>
</Modal>}
{customerModalDetailedVisible &&
<>
<Image
source={{
uri: "https://d1s68zh8fdz4eb.cloudfront.net/logo.png"
}}
style={{
height: 100,
width: 100,
// borderWidth: 5,
// borderColor: '#fff'
}}
/>
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'space-around',
width: '95%',
borderWidth: 5,
borderColor: 'gold',
}}>
{/* <Text>Your expo push token: {expoPushToken}</Text> */}
<View style={{ alignItems: 'flex-start', justifyContent: 'center', backgroundColor: '#fff', flex: 1, width: '100%', padding: 15}}>
<Image
style={{
height: 300,
width: 300,
marginBottom: 20,
// borderWidth: 5,
// borderColor: 'gold'
}}
source={{
uri: newData.photo,
}}
/>
<Text>Customer: {newData.name}</Text>
<Text>Arm Length: {newData.armLength}</Text>
<Text>Address: {newData.address}</Text>
<Text>Phone: {newData.phone}</Text>
<Text>Email: {newData.email}</Text>
<Text>Favorite Drink: {newData.favoriteDrink}</Text>
<Text>Height: {newData.height}</Text>
<Text>Inseam: {newData.inseam}</Text>
<Text>Neck Length: {newData.neckLength}</Text>
<Text>Customer: {newData.name}</Text>
<Text>Arm Length: {newData.armLength}</Text>
<Text>Address: {newData.address}</Text>
<Text>Phone: {newData.phone}</Text>
<Text>Email: {newData.email}</Text>
<Text>Favorite Drink: {newData.favoriteDrink}</Text>
<Text>Height: {newData.height}</Text>
<Text>Inseam: {newData.inseam}</Text>
<Text>Neck Length: {newData.neckLength}</Text>
<Text>Customer: {newData.name}</Text>
<Text>Arm Length: {newData.armLength}</Text>
<Text>Address: {newData.address}</Text>
<Text>Phone: {newData.phone}</Text>
<Text>Email: {newData.email}</Text>
<Text>Favorite Drink: {newData.favoriteDrink}</Text>
<Text>Height: {newData.height}</Text>
<Text>Inseam: {newData.inseam}</Text>
<Text>Neck Length: {newData.neckLength}</Text>
<Text>Customer: {newData.name}</Text>
<Text>Arm Length: {newData.armLength}</Text>
<Text>Address: {newData.address}</Text>
<Text>Phone: {newData.phone}</Text>
<Text>Email: {newData.email}</Text>
<Text>Favorite Drink: {newData.favoriteDrink}</Text>
<Text>Height: {newData.height}</Text>
<Text>Inseam: {newData.inseam}</Text>
<Text>Neck Length: {newData.neckLength}</Text>
{/* I can return it as an object above and use dot notation or do something similar below but use a string */}
{/* <Text>Data: {notification && JSON.stringify(notification.request.content.data)}</Text> */}
<Button
title="Press to Send Notification"
onPress={async () => {
await sendPushNotification(expoPushToken);
}}
/>
<Button
title="Home"
onPress={() => {
setHomeScreenVisible(true)
setScanned(false)
setCustomerModalDetailedVisible(false)
setQRScannerVisible(false)
}}
/>
</View>
</View>
</>
}
</View>
</ScrollView>
);
}
// Can use this function below, OR use Expo's Push Notification Tool-> https://expo.io/notifications
async function sendPushNotification(expoPushToken) {
const message = {
to: expoPushToken,
sound: 'default',
title: 'Customer Arriving!',
body: 'Please greet them at the door.',
};
await fetch('https://exp.host/--/api/v2/push/send', {
method: 'POST',
headers: {
Accept: 'application/json',
'Accept-encoding': 'gzip, deflate',
'Content-Type': 'application/json',
},
body: JSON.stringify(message),
});
}
async function registerForPushNotificationsAsync() {
let token;
if (Constants.isDevice) {
const { status: existingStatus } = await Notifications.getPermissionsAsync();
let finalStatus = existingStatus;
if (existingStatus !== 'granted') {
const { status } = await Notifications.requestPermissionsAsync();
finalStatus = status;
}
if (finalStatus !== 'granted') {
alert('Failed to get push token for push notification!');
return;
}
token = (await Notifications.getExpoPushTokenAsync()).data;
console.log(token);
} else {
alert('Must use physical device for Push Notifications');
}
if (Platform.OS === 'android') {
Notifications.setNotificationChannelAsync('default', {
name: 'default',
importance: Notifications.AndroidImportance.MAX,
vibrationPattern: [0, 250, 250, 250],
lightColor: '#FF231F7C',
});
}
return token;
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
justifyContent: 'flex-start',
alignItems: 'center',
backgroundColor: 'black',
paddingTop: 60,
},
modal: {
// marginTop: 100,
},
modalView: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'black'
},
modalInside: {
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 20
},
modalTextName: {
fontSize: 20,
fontWeight: 'bold',
marginBottom: 5,
color: 'white'
},
modalTextSecondary: {
color: '#fff',
marginBottom: 5,
},
closeButton: {
marginTop: 100,
},
moreInfo: {
marginTop: 100,
}
});
By live alerts, I assume you mean text notifications. One way to push out text notifications using AWS is using the Simple Notification Service. Because you are using a React app, use the AWS SDK for JavaScript. Using the SDK, you can create app logic to fire off text notifications in response to certain events.
You can find examples here:
https://github.com/awsdocs/aws-doc-sdk-examples/tree/master/javascriptv3/example_code/sns/src

How do I change the color/icon of the default action button

Is it possible to change the icon or at least the color/style of the default action button?
I haven't found anything useable in the source code. I'm using the following code, which displays the default action button:
onPressActionButton={this.handleActionButtonPress}
I want to change the circle + button in the left bottom corner.
Define custom Action buttons inside:
<GiftedChat
...
renderActions={messages => this.micBtn(messages)}
...
/>
and then define the custom Button's appearance:
micBtn = (sendProps) => {
return (
<View flexDirection='row' onTouchStart={messages => this.micBtnPressed(sendProps.messages)}>
<TouchableOpacity style={styles.myStyle} activeOpacity={0.5}>
<Image
source={{
uri:
'https://img.icons8.com/material-rounded/50/000000/microphone.png',
}}
style={styles.MicIconStyle}
/>
</TouchableOpacity>
</View>
);
}
}
micBtnPressed(messages=[]){
//do something useful here
console.log("Current Inputbox content: ",messages)
}
Finally, define styles, for example:
myStyle: {
flexDirection: 'row',
alignItems: 'center',
//backgroundColor: '#485a96',
borderWidth: 0.5,
borderColor: '#fff',
height: 40,
width: 35,
borderRadius: 5,
margin: 5,
},
MicIconStyle: {
padding: 5,
marginRight: 10,
height: 35,
width: 35,
resizeMode: 'contain',
},
A final comment, I believe that by defining a custom Action button, you are also giving up (overriding) the onPressActionButton={this.handleActionButtonPress} directive, which only works when you use the default, uncustomized, button. Therefore, that's why I call the action method 'micBtnPressed' from inside my custom object.

Dollar Format Regex in React Native

I'm trying to create a method in React Native that formats my input to dollar format.
onChangeNumberFormat = (text, input) => {
const obj = { ...this.state.data };
const value = text.replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,')
obj[input] = value;
this.setState({
data: obj
});
};
My input (I'm using Native Base):
<Input
value={Amount}
onChangeText={(text) => this.onChangeNumberFormat(text, 'RentalAmount')}
style={styles.valueText}
/>
When I enter 5000.00, it formats to 5,000.00 which is correct. However, if I delete the last 3 0 zeros, it becomes 5,00 instead of 500. How can I fix it? Also, is there a way to always put the '$' in the front and just accept numbers in the Input?
Thanks
To format currency you can use one of these libraries:
currency.js
dinero.js
accounting.js
wallet.js
Otherwise, you can do something like this:
const format = amount => {
return Number(amount)
.toFixed(2)
.replace(/\d(?=(\d{3})+\.)/g, '$&,');
};
Check out the demo https://snack.expo.io/#abranhe/currency-formatting
import React, { useState } from 'react';
import { Text, View, TextInput, StyleSheet } from 'react-native';
export default () => {
const [money, setMoney] = useState(0);
const format = amount => {
return Number(amount)
.toFixed(2)
.replace(/\d(?=(\d{3})+\.)/g, '$&,');
};
return (
<View style={styles.container}>
<Text style={styles.paragraph}>$ {format(money)}</Text>
<TextInput
value={money}
onChangeText={money => setMoney(money)}
style={styles.input}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
},
paragraph: {
margin: 24,
fontSize: 18,
textAlign: 'center',
},
input: {
height: 30,
borderColor: 'black',
borderWidth: 1,
},
});