How to use react-native-flash-message with react-native-navigation - android

I am using Wix's react-native-navigation and I want to use react-native-flash-message. In the official document https://www.npmjs.com/package/react-native-flash-message, they have given we can use globally as well as locally but in my code, I am not getting where should I use it.
following is my code.
this is my app.js
import { Navigation } from "react-native-navigation";
import { Provider } from "react-redux";
import registerScreens from './components/Screens'
import Icon from 'react-native-vector-icons/FontAwesome';
import configureStore from "./store/configureStore";
const store = configureStore();
registerScreens(Provider, store);
// Start a App
Navigation.events().registerAppLaunchedListener(() => {
Promise.all([
Icon.getImageSource("bars", 30, 'black'),
Icon.getImageSource("share-alt", 30, 'black')
]).then(sources => {
Navigation.setRoot({
root: {
sideMenu: {
left: {
component: {
name: 'app.NavigationDrawer',
passProps: {
text: 'This is a left side menu screen'
}
}
},
center: {
stack: {
id: 'mainStack',
children: [
{
stack: {
id: 'tab1Stack',
children: [
{
component: {
name: 'app.Component'
}
}
],
options: {
topBar: {
background: {
color: '#50A7C2',
},
title: {
text: 'Namaz Timing',
fontSize: 20,
//color: 'white',
fontFamily: 'Ubuntu',
alignment: 'left'
},
leftButtons: [
{
id: 'buttonOne',
icon: sources[0]
}
],
rightButtons: [
{
id: 'buttonTwo',
icon: sources[1]
}
]
}
}
}
},
],
options: {
topBar: {
background: {
color: '#50A7C2',
}
},
}
}
}
}
}
});
});
});
And this is my function where I want to use it
import qs from 'qs';
import { AsyncStorage } from 'react-native';
export async function addMasjid(Name, Address, email, Timing1, Timing2, Timing3, Timing4, Timing5, Timing6, Timing7) {
const Data = await AsyncStorage.getItem('tokenData');
parsed = JSON.parse(Data)
var token = parsed.access_token;
return fetch(`URL`, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded',
},
body: qs.stringify({
'name': Name,
'address': Address,
'email': email,
'time_': Timing,
'time_': Timing,
'time_': Timing,
'time_': Timing,
'time_': Timing,
'time_': Timing,
'time_': Timing,
})
})
.then(res => res.json())
.catch(err => console.log(err))

Import the Flash Message component in your App.js and call it in the bottom.
App.js
import React from "react";
import { View } from "react-native";
import FlashMessage from "react-native-flash-message";
export default class App extends React.Component {
render() {
return (
<View style={{ flex: 1 }}>
// your entire code
<FlashMessage position="top" /> <--- at the bottom
</View>
);
}
}
Now, in your file where you wanna use it.
import { showMessage, hideMessage } from "react-native-flash-message";
Then, just use showMessage in the function you want to. Example:
const someFunc = () => {
showMessage({
message : 'some message',
type: 'success'
... other attributes
})
}

Related

React Native Navigation by Wix - bottomTabs not working

I'm trying to add bottomTabs to my React Native app but it doesn't show and doesn't throw any errors at me. When I compile it, the "Hello World" text shows up perfectly and the topBar even works as it should, but I just can't get the bottomTabs working.
The Code :
import React from 'react';
import {
Text,
View
} from 'react-native';
import { Navigation } from 'react-native-navigation';
import HomeScreen from './HomeScreen';
const SavedScreen = () => {
return(
<View>
<Text>Hello world!</Text>
</View>
);
}
Navigation.registerComponent('HomeScreen', () => HomeScreen);
Navigation.registerComponent('InfoScreen', () => InfoScreen);
Navigation.events().registerAppLaunchedListener(async () =>{
Navigation.setRoot({
root:{
bottomTabs: {
id: 'BOTTOM_TABS_LAYOUT',
children: [
{
stack: {
id: 'HOME_TAB',
children: [
{
component: {
id: 'HOME_SCREEN',
name: 'HomeScreen'
}
}
],
options: {
bottomTab: {
icon: require('../assets/images/home.png')
}
}
}
},
{
stack: {
id: 'SAVED_TAB',
children: [
{
component: {
id: 'SAVED_SCREEN',
name: 'SavedScreen'
}
}
],
options: {
bottomTab: {
icon: require('../assets/images/home.png')
}
}
}
}
]
}
}
})
})
export default SavedScreen;
I'm using React Native Navigation version 7.11.2

React navigation not showing the right screen

I have created a navigation setup for my application that should start off with a welcome screen on the welcome screen you find two buttons, one for registering and the other for logging in.
When the user registers or logs in he get sent to other screens. I have created a stack navigator between the log in and register screen and put them in a loginFlow constant and another between the welcome screen and the loginFlow constant and the navigation between these screens works, but for some reason the welcome screen doesn't get shown first instead I get the sign up screen (register screen).
Why is that the case and how can i make the welcomeScreen get shown first
import React from "react";
import { View } from "react-native";
import WeclomeScreen from "./app/screens/WelcomeScreen";
import MainScreen from "./app/screens/MainScreen";
import AccountScreen from "./app/screens/AccountScreen";
import { Provider as AuthProvider } from "./app/context/AuthContext";
import { createMaterialBottomTabNavigator } from "react-navigation-material-bottom-tabs";
import SignupScreen from "./app/screens/SignupScreen";
import { createAppContainer, createSwitchNavigator } from "react-navigation";
import { createStackNavigator } from "react-navigation-stack";
import ResultShowScreen from "./app/screens/ResultShowScreen";
import ResolveAuthScreen from "./app/screens/ResolveAuthScreen";
import SigninScreen from "./app/screens/SigninScreen";
import ArticleSaveScreen from "./app/screens/ArticleSaveScreen";
import { setNavigator } from "./app/navigationRef";
const articleListFlow = createStackNavigator({
Main: MainScreen, // screen with diffrent articles categories
ResultsShow: ResultShowScreen, // article details screen
});
const loginFlow = createStackNavigator({
Signup: SignupScreen,
Signin: SigninScreen,
});
loginFlow.navigationOptions = () => {
return {
headerShown: false,
};
};
articleListFlow.navigationOptions = {
title: "News Feed",
tabBarIcon: ({ tintColor }) => (
<View>
<Icon style={[{ color: tintColor }]} size={25} name={"ios-cart"} />
</View>
),
activeColor: "#ffffff",
inactiveColor: "#ebaabd",
barStyle: { backgroundColor: "#d13560" },
};
const switchNavigator = createSwitchNavigator({
ResolveAuth: ResolveAuthScreen,
MainloginFlow: createStackNavigator({
WelcomeScreen: WeclomeScreen,
loginFlow: loginFlow,
}),
mainFlow: createMaterialBottomTabNavigator(
{
articleListFlow: articleListFlow,
ArticleSave: ArticleSaveScreen, // we dont need this one
Account: AccountScreen,
},
{
activeColor: "#ffffff",
inactiveColor: "#bda1f7",
barStyle: { backgroundColor: "#6948f4" },
}
),
});
const App = createAppContainer(switchNavigator);
export default () => {
return (
<AuthProvider>
<App
ref={(navigator) => {
setNavigator(navigator);
}}
/>
</AuthProvider>
);
};
here is the content of ResolveAuthscreen :
import React, { useEffect, useContext } from "react";
import { Context as AuthContext } from "../context/AuthContext";
const ResolveAuthScreen = () => {
const { tryLocalSignin } = useContext(AuthContext);
useEffect(() => {
tryLocalSignin();
}, []);
// not returning anything since just waiting to check the token
// will transition to signin or signup very quickly
return null;
};
export default ResolveAuthScreen;
As you have mentioned in your comments, you have an issue in your tryLocalSignin method. In that method, if there is no any token, you are navigating the user to the Signup screen. Instead of navigating to the Signup screen, navigate to the WelcomeScreen screen like:
const tryLocalSignin = (dispatch) => async () => {
const token = await AsyncStorage.getItem("token");
if (token) {
dispatch({ type: "signin", payload: token });
navigate("Main");
} else {
navigate("WelcomeScreen");
}
};

drawerLockMode : 'locked-closed' not working directly with createStackNavigator

When I specify drawerLockMode direactly with createStackNavigator it is not working.
const drawerStack = createStackNavigator({
HomeScreen: { screen: HomeScreen },
}, {
headerMode: 'screen',
navigationOptions: {
drawerLockMode:'locked-closed'
}
})
But when I use drawerStack variable to define navigationOptions, it is working.
drawerStack.navigationOptions = ({ navigation }) => {
drawerLockMode = 'locked-closed';
return {
drawerLockMode,
};
};
Am I doing any mistake when I am directly using it inside createStackNavigator?
Update
As #bennygenel suggested, we need to user drawerLockMode in drawerNavigator instead of stackNavigator. Here is what i have done.
const drawerNavigator = createDrawerNavigator({
drawerStack: drawerStack
}, {
contentComponent: DrawerComponent,
navigationOpions:{
drawerLockMode:'locked-closed'
}
})
But it is not working in this way also. The only way it is working is by using the const variable created using createStackNavigator or createDrawerNavigator
Try the following code, it's working for me:
const UserHome_StackNavigator = StackNavigator({
userHm: {
screen: UserHome,
navigationOptions: ({ navigation }) => ({
title: 'User screen title',
headerStyle: {
backgroundColor: 'white',
},
headerTintColor: 'black'
}),
},
});
UserHome_StackNavigator.navigationOptions = ({ navigation }) => {
let drawerLockMode = 'locked-closed';
//logic here to change conditionaly, if needed
return {
drawerLockMode,
};
};
in case someone need this:
const drawerNavigator = createDrawerNavigator({
drawerStack: drawerStack
}, {
contentComponent: DrawerComponent,
navigationOpions: ({navigation}) => {
let routeName = navigation.state.routes[navigation.state.routes.length-1].routeName;
if(['Animation', 'Splash', 'Intro', 'Login', 'Signup'].indexOf(routeName)>=0){
return {
drawerLockMode: 'locked-closed'
}
}
return {}
}
})

Global in-app notifications

I wish to utilize an in-app notification system, aka a more attractive and less in your face' use of alerts to let the user know what actions are being done, especially when for instance a barcode has been detected but it needs to send that barcode to the server and the user needs to wait.
I have found this lib and have attempted to implement it; but as I am using React Navigation and I wish to render the item at the very top of the application, it gets cut off by React Native header
Is it possible to have a function I can create and reference whenever I want a global notification and it will render on the very top I would imagine it would need to render here:
import React from 'react';
import { createBottomTabNavigator,createStackNavigator } from 'react-navigation';
import SearchTab from './components/Tabs/SearchTab';
import HomeTab from './components/Tabs/HomeTab';
import ScannerTab from './components/Tabs/ScannerTab';
import SettingsTab from './components/Tabs/SettingsTab';
import Ionicons from 'react-native-vector-icons/Ionicons';
import StockModal from './components/Modals/StockModal';
const MainStack = createBottomTabNavigator(
{
Home: HomeTab,
Search: SearchTab,
Scanner: ScannerTab,
Settings: SettingsTab,
//Todo: Total overlay modals HERE
},
{
navigationOptions: ({ navigation }) => ({
tabBarIcon: ({ focused, tintColor }) => {
const { routeName } = navigation.state;
let iconName;
if (routeName === 'Home') {
iconName = `ios-information-circle${focused ? '' : '-outline'}`;
} else if (routeName === 'Settings') {
iconName = `ios-options${focused ? '' : '-outline'}`;
}else if (routeName === 'Scanner') {
iconName = `ios-barcode${focused ? '' : '-outline'}`;
}else if (routeName === 'Search') {
iconName = `ios-search${focused ? '' : '-outline'}`;
}
return <Ionicons name={iconName} size={25} color={tintColor} />;
},
}),
tabBarOptions: {
activeTintColor: 'tomato',
inactiveTintColor: 'gray',
},
}
);
export default RootStack = createStackNavigator(
{
Main: {
screen: MainStack,
},
QuickStockScreen: {
screen: StockModal,
},
},
{
mode: 'modal',
headerMode: 'none',
}
);
But even if that's possible, I am not sure how its possible to build a function that tells the notification to show; React Redux comes to mind but I don't wish to implement such a cumbersome system just for one feature and it was something I considered when creating his application and decided against.
The notification system in question (not very clear documentation or examples sadly) https://www.npmjs.com/package/react-native-in-app-notification
Here is the navigation lib I am using: https://reactnavigation.org/
What you want would be a component that is a the same level of the navigation (So it can display over it). In multiple projects, I use react-native-root-siblings to do so. It allows you to add UI over the app and so over the navigation.
An exemple how what I made with it. The dark layer and the box at the bottom are part of the Siblings Component.
https://gyazo.com/7ad3fc3fea767ea84243aaa493294670
The Siblings is used like the Alert of React-Native, so as a function (which is quite useful!)
messageMenu.js
import React, { Component } from 'react';
import RootSiblings from 'react-native-root-siblings';
import MessageMenuContainer from './MessageMenuContainer';
export default class Dialog extends Component {
static show = (props) => new RootSiblings(<MessageMenuContainer {...props} />);
static update = (menu, props) => {
if (menu instanceof RootSiblings) {
menu.update(<MessageMenuContainer {...props} />);
} else {
console.warn(`Dialog.update expected a \`RootSiblings\` instance as argument.\nBut got \`${typeof menu}\` instead.`);
}
}
static close = (menu) => {
if (menu instanceof RootSiblings) {
menu.destroy();
} else {
console.warn(`Dialog.destroy expected a \`RootSiblings\` instance as argument.\nBut got \`${typeof menu}\` instead.`);
}
}
render() {
return null;
}
}
export {
RootSiblings as Manager,
};
Where the MessageMenuContainer is your component to render at the top.
Component using the Root Siblings:
import React from 'react';
import PropTypes from 'prop-types';
import I18n from 'react-native-i18n';
import { BackHandler, Keyboard, Platform, TouchableOpacity } from 'react-native';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import DraftMenu from './messageMenu'; //HERE IS THE IMPORT YOU WANT
import { Metrics, Colors, Fonts } from '../../main/themes';
class DraftBackButton extends React.Component {
state = {
draftMenu: undefined,
}
componentDidMount() {
BackHandler.addEventListener('hardwareBackPress', this.handleBackAndroid);
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress', this.handleBackAndroid);
}
handleBackAndroid = () => {
this.handleBack();
return true;
}
handleBack = async () => {
Keyboard.dismiss();
await this.openDraftMenu();
}
openDraftMenu = async () => {
if (this.state.draftMenu) {
await DraftMenu.update(this.state.draftMenu, this.draftMenuProps());
} else {
const draftMenu = await DraftMenu.show(this.draftMenuProps());
this.setState({ draftMenu: draftMenu });
}
}
draftMenuProps = () => ({
options: [
{ title: I18n.t('message.deleteDraft'), onPress: this.deleteDraft, icon: 'trash' },
{ title: I18n.t('message.saveDraft'), onPress: this.saveOrUpdateDraft, icon: 'documents' },
{ title: I18n.t('cancel'), icon: 'close', style: { backgroundColor: Colors.tertiaryBackground } },
],
destroyMenuComponent: async () => {
DraftMenu.close(this.state.draftMenu);
await this.setState({ draftMenu: undefined });
},
withIcon: true,
})
saveOrUpdateDraft = async () => {
// SAVE OR UPDATE DRAFT. NOT IMPORTANT
}
saveDraft = async () => {
// SAVING THE DRAFT
}
updateDraft = async () => {
// UPDATING THE DRAFT
}
deleteDraft = async () => {
// DELETING THE DRAFT
}
render() {
return (
<TouchableOpacity
hitSlop={Metrics.touchable.largeHitSlop}
onPress={() => {
this.handleBack();
}}
>
<Text>BUTTON</Text>
</TouchableOpacity>
);
}
}
DraftBackButton.propTypes = {
// ALL THE PROPTYPES
};
function mapStateToProps(state, ownProps) {
//
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators({ fetchMessages }, dispatch),
};
}
export default connect(mapStateToProps, mapDispatchToProps)(DraftBackButton);
The best thing with this lib is that you can call the .show anywhere in your app and it will render at the very top!
Hope it's what you're looking for!
EDIT:
I updated the example of how to use the Root Siblings.
Here's the content of my MessageContainer which will be display on top of everything
import React from 'react';
import PropTypes from 'prop-types';
import { Animated, Dimensions, InteractionManager, StyleSheet, TouchableOpacity, View } from 'react-native';
import MessageMenuItem from './MessageMenuItem';
import { Colors } from '../../../main/themes';
const { width, height } = Dimensions.get('window');
const OPTION_HEIGHT = 55;
const OVERLAY_OPACITY = 0.5;
export default class DraftMenuContainer extends React.Component {
constructor(props) {
super(props);
this.state = {
animatedHeight: new Animated.Value(0),
animatedOpacity: new Animated.Value(0),
menuHeight: props.options.length * OPTION_HEIGHT,
};
}
componentDidMount() {
this.onOpen();
}
// Using Animated from react-native to make the animation (fade in/out of the dark layer and the dimensions of the actual content)
onOpen = async () => {
await this.state.animatedHeight.setValue(0);
await this.state.animatedOpacity.setValue(0);
Animated.parallel([
Animated.timing(this.state.animatedHeight, { toValue: this.state.menuHeight, duration: 200 }),
Animated.timing(this.state.animatedOpacity, { toValue: OVERLAY_OPACITY, duration: 200 }),
]).start();
}
onClose = async () => {
await this.state.animatedHeight.setValue(this.state.menuHeight);
await this.state.animatedOpacity.setValue(OVERLAY_OPACITY);
Animated.parallel([
Animated.timing(this.state.animatedHeight, { toValue: 0, duration: 200 }),
Animated.timing(this.state.animatedOpacity, { toValue: 0, duration: 200 }),
]).start(() => this.props.destroyMenuComponent()); // HERE IS IMPORTANT. Once you're done with the component, you need to destroy it. To do so, you need to set a props 'destroyMenuComponent' which is set at the creation of the initial view. See the other code what it actually do
}
render() {
return (
<View style={styles.menu}>
<Animated.View style={[styles.backgroundOverlay, { opacity: this.state.animatedOpacity }]}>
<TouchableOpacity
activeOpacity={1}
onPress={() => this.onClose()}
style={{ flex: 1 }}
/>
</Animated.View>
<Animated.View style={[styles.container, { height: this.state.animatedHeight }]}>
{this.props.options.map((option, index) => (
<MessageMenuItem
height={OPTION_HEIGHT}
icon={option.icon}
key={index}
onPress={async () => {
await this.onClose();
InteractionManager.runAfterInteractions(() => {
if (option.onPress) {
option.onPress();
}
});
}}
style={option.style}
title={option.title}
withIcon={this.props.withIcon}
/>
))}
</Animated.View>
</View>
);
}
}
DraftMenuContainer.propTypes = {
destroyMenuComponent: PropTypes.func.isRequired,
withIcon: PropTypes.bool,
options: PropTypes.arrayOf(PropTypes.shape({
icon: PropTypes.string.isRequired,
onPress: PropTypes.func,
title: PropTypes.string.isRequired,
})),
};

React-Native alternative to AlertIOS.prompt for android?

I am following a tutorial for react-native, however they are doing it for IOS, there is one part where they use AlertIOS.prompt like this
AlertIOS.prompt(
'Add New Item',
null,
[
{text: 'Cancel', onPress: () => console.log('Cancel Pressed'), style: 'cancel'},
{
text: 'Add',
onPress: (text) => {
this.itemsRef.push({ title: text })
}
},
],
'plain-text'
);
I am trying to remake this for android but cannot get it working, I did find this https://www.npmjs.com/package/react-native-prompt
import Prompt from 'react-native-prompt';
<Prompt
title="Say something"
placeholder="Start typing"
defaultValue="Hello"
visible={ this.state.promptVisible }
onCancel={ () => this.setState({
promptVisible: false,
message: "You cancelled"
}) }
onSubmit={ (value) => this.setState({
promptVisible: false,
message: `You said "${value}"`
}) }/>
However I cannot get this to work either, It is supposed to display the prompt when I press a button but nothing happens..
Here is the full original code with AlertIOS
'use strict';
import React, {Component} from 'react';
import ReactNative from 'react-native';
const firebase = require('firebase');
const StatusBar = require('./components/StatusBar');
const ActionButton = require('./components/ActionButton');
const ListItem = require('./components/ListItem');
const styles = require('./styles.js')
const {
AppRegistry,
ListView,
StyleSheet,
Text,
View,
TouchableHighlight,
AlertIOS,
} = ReactNative;
// Initialize Firebase
const firebaseConfig = {
apiKey: "AIzaSyA9y6Kv10CAl-QOnSkMehOyCUejwvKZ91E",
authDomain: "dontforget.firebaseapp.com",
databaseURL: "https://dontforget-bd066.firebaseio.com",
storageBucket: "dontforget-bd066.appspot.com",
};
const firebaseApp = firebase.initializeApp(firebaseConfig);
class dontforget extends Component {
constructor(props) {
super(props);
this.state = {
dataSource: new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2,
})
};
this.itemsRef = this.getRef().child('items');
}
getRef() {
return firebaseApp.database().ref();
}
listenForItems(itemsRef) {
itemsRef.on('value', (snap) => {
// get children as an array
var items = [];
snap.forEach((child) => {
items.push({
title: child.val().title,
_key: child.key
});
});
this.setState({
dataSource: this.state.dataSource.cloneWithRows(items)
});
});
}
componentDidMount() {
this.listenForItems(this.itemsRef);
}
render() {
return (
<View style={styles.container}>
<StatusBar title="Grocery List" />
<ListView
dataSource={this.state.dataSource}
renderRow={this._renderItem.bind(this)}
enableEmptySections={true}
style={styles.listview}/>
<ActionButton onPress={this._addItem.bind(this)} title="Add" />
</View>
)
}
_addItem() {
AlertIOS.prompt(
'Add New Item',
null,
[
{text: 'Cancel', onPress: () => console.log('Cancel Pressed'), style: 'cancel'},
{
text: 'Add',
onPress: (text) => {
this.itemsRef.push({ title: text })
}
},
],
'plain-text'
);
}
_renderItem(item) {
const onPress = () => {
AlertIOS.alert(
'Complete',
null,
[
{text: 'Complete', onPress: (text) => this.itemsRef.child(item._key).remove()},
{text: 'Cancel', onPress: (text) => console.log('Cancelled')}
]
);
};
return (
<ListItem item={item} onPress={onPress} />
);
}
}
AppRegistry.registerComponent('dontforget', () => dontforget);
Could anyone tell me how I could make this work for android?
I think you can use the following libraries : https://github.com/mmazzarolo/react-native-dialog
Example code to get user input are as follows (not in docs)
<Dialog.Container visible={true}>
<Dialog.Title>Account delete</Dialog.Title>
<Dialog.Description>
Do you want to delete this account? You cannot undo this action.
</Dialog.Description>
<Dialog.Input label="Cancel" onChangeText={(text) => this.setState({username : text})} />
<Dialog.Button label="Delete" onPress={() => {
console.log(this.state.username);
this.setState({promptUser : false});
}} />
</Dialog.Container>
These looks like a good alternative since its natively implemented
https://github.com/shimohq/react-native-prompt-android
Actually, you can use a cross-platform prompt component that works fine both on Android and Ios. The link is given below.
https://www.npmjs.com/package/react-native-prompt-crossplatform and its
repository
link is
https://github.com/Ramiah-Viknesh/react-native-prompt-crossplatform
I developed a small utility to solve this issue. It might be useful.
https://github.com/eleviven/react-native-alertbox

Categories

Resources