RNFetchBlob is not working to upload image - firebase

I am trying to make a upload function for my Firebase Cloud Storage. I am using RNFetchBlob, along with react-native-image-picker. I can select photos, but it will not upload. All other Firebase functions works great and it is installed through React-Native-Firebase...
Nothing seems to happen after 'fs.readFile'.
import React, { Component } from 'react'
import {
StyleSheet,
Text,
View,
TouchableOpacity,
Platform,
Image,
ActivityIndicator
} from 'react-native'
import ImagePicker from 'react-native-image-picker'
import RNFetchBlob from 'rn-fetch-blob'
import firebase from 'react-native-firebase';
const storage = firebase.storage()
// Prepare Blob support
const Blob = RNFetchBlob.polyfill.Blob
const fs = RNFetchBlob.fs
window.XMLHttpRequest = RNFetchBlob.polyfill.XMLHttpRequest
window.Blob = Blob
const uploadImage = (uri, mime = 'application/octet-stream') => {
return new Promise((resolve, reject) => {
const uploadUri = Platform.OS === 'ios' ? uri.replace('file://', '') : uri
const sessionId = new Date().getTime()
let uploadBlob = null
const imageRef = storage.ref('images').child('${sessionId}')
fs.readFile(uploadUri, 'base64')
.then((data) => {
return Blob.build(data, { type: '${mime};BASE64' })
})
.then((blob) => {
uploadBlob = blob
return imageRef.put(blob, { contentType: mime })
})
.then(() => {
uploadBlob.close()
return imageRef.getDownloadURL()
})
.then((url) => {
resolve(url)
})
.catch((error) => {
reject(error)
})
})
}
class Demo extends Component {
constructor(props) {
super(props)
this.state = {}
}
_pickImage() {
this.setState({ uploadURL: '' })
ImagePicker.launchImageLibrary({}, response => {
uploadImage(response.uri)
.then(url => this.setState({ uploadURL: url }))
.catch(error => console.log(error))
})
}
render() {
return (
<View style={ styles.container }>
{
(() => {
switch (this.state.uploadURL) {
case null:
return null
case '':
return <ActivityIndicator />
default:
return (
<View>
<Image
source={{ uri: this.state.uploadURL }}
style={ styles.image }
/>
<Text>{ this.state.uploadURL } {this.state.uploadURL}</Text>
</View>
)
}
})()
}
<TouchableOpacity onPress={ () => this._pickImage() }>
<Text style={ styles.upload }>
Upload
</Text>
</TouchableOpacity>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
image: {
height: 200,
resizeMode: 'contain',
},
upload: {
textAlign: 'center',
color: '#333333',
padding: 10,
marginBottom: 5,
borderWidth: 1,
borderColor: 'gray'
},
})
export default Demo
I get this error in my console when selecting a photo:
filePath.replace is not a function. (In 'filePath.replace('file://',
'')', 'filePath.replace' is undefined)]

Just pass the image url directly to storage ref. You don't need to create a blob file anymore. I guess firebase handles it internally now.
Here an example i just tested together with react-native-image-crop-picker:
import firebase from 'react-native-firebase';
import ImagePicker from 'react-native-image-crop-picker';
export default class ImageUploadService {
static init() {}
static openPickerAndUploadImage() {
const uid = '12345';
ImagePicker.openPicker({
width: 300,
height: 300,
cropping: true,
mediaType: 'photo',
})
.then(image => {
const imagePath = image.path;
const imageRef = firebase
.storage()
.ref(uid)
.child('dp.jpg');
let mime = 'image/jpg';
imageRef
.put(imagePath, { contentType: mime })
.then(() => {
return imageRef.getDownloadURL();
})
.then(url => {
// You could now update your users avatar for example
//firebase.database().ref('users').child(uid).update({ ...userData})
console.log('URL', url);
});
})
.catch(error => {
console.log(error);
});
}
}
ImageUploadService.init();
Now just call ImageUploadService.openopenPickerAndUploadImage() in one of your components.
I am sure this will also work with react-native-image-picker too, just remove the blob parts in your code and pass the image url directly to your imageRef.put
==>
const uploadImage = (uri, mime = 'application/octet-stream') => {
return new Promise((resolve, reject) => {
const imagePath = uri;
const imageRef = firebase
.storage()
.ref('images')
.child('dp.jpg');
let mime = 'image/jpg';
imageRef
.put(imagePath, { contentType: mime })
.then(() => {
return imageRef.getDownloadURL();
})
.then(resolve)
.catch(reject);
});
};

Related

Messages displayed on one side only- react-native-gifted-chat

If 2 user is using the app, messages are being displayed on the left side of the screen. cannot differentiate between them
here my full code below
import React, { Component } from 'react';
import { Platform, StyleSheet, KeyboardAvoidingView, SafeAreaView, View, YellowBox, LogBox, AsyncStorage } from 'react-native';
import { GiftedChat, InputToolbar } from 'react-native-gifted-chat';
import FontAwesomeIcon from 'react-native-vector-icons/FontAwesome';
import AnimatedLoader from "react-native-animated-loader";
import firebaseSDK from "../../firebaseSDK";
import firebase from 'firebase';
LogBox.ignoreLogs(['Setting a timer']);
const customtInputToolbar = props => {
return (
<InputToolbar
{...props}
containerStyle={{
backgroundColor: "white",
borderTopColor: "#E8E8E8",
borderTopWidth: 1,
//padding: 8
}}
/>
);
};
export default class Chat extends Component {
constructor(props) {
super(props);
this.state = {
messages: [],
chatgenidres: '',
}
this.init()
this.checkAuth()
}
init = () => {
if (!firebase.apps.length) {
firebase.initializeApp({
apiKey: "apiKey",
authDomain: "authDomain",
databaseURL: "databaseURL",
projectId: "projectId",
storageBucket: "storageBucket",
messagingSenderId: "messagingSenderId",
appId: "appId",
measurementId: "measurementId"
})
}
};
checkAuth = () => {
firebase.auth().onAuthStateChanged(user => {
if (!user) {
firebase.auth().signInAnonymously();
}
})
}
send = messages => {
console.log(messages);
messages.forEach(item => {
const message = {
text: item.text,
timestamp: firebase.database.ServerValue.TIMESTAMP,
user: item.user
};
this.db.push(message);
});
};
parse = message => {
const { user, text, timestamp } = message.val();
const { key: _id } = message;
const createdAt = new Date(timestamp);
return {
_id,
createdAt,
text,
user
};
};
get = callback => {
this.db.on("child_added", snapshot => callback(this.parse(snapshot)));
};
off() {
this.db.off();
}
get db() {
console.log(this.state.chatgenidres)
return firebase.database().ref(this.state.chatgenidres)
};
get uid() {
return (firebase.auth().currentUser || {}).uid;
}
get user() {
return {
_id: this.uid,
chatfromusername: this.props.navigation.state.params.chatFromName,
chatfromuserid: this.props.navigation.state.params.chatFromId,
chattouserid: this.props.navigation.state.params.chatToId,
chattousername: this.props.navigation.state.params.chatToName,
}
}
componentDidMount() {
let genId = this.props.navigation.state.params.chatFromId + 'connectedto' + this.props.navigation.state.params.chatToId;
//AsyncStorage.setItem('chatgenid', genId);
AsyncStorage.getItem('chatgenid', (err, chatgenidres) => {
console.log(chatgenidres, 'from chat.js');
this.setState({ chatgenidres: chatgenidres });
this.get(message =>
this.setState(previous => ({
messages: GiftedChat.append(previous.messages, message)
}))
);
});
}
componentWillUnmount() {
this.off();
}
render() {
const chat = <GiftedChat
messages={this.state.messages}
onSend={this.send}
user={this.user}
style={styles.messageContainer}
renderInputToolbar={props => customtInputToolbar(props)}
/>;
if (Platform.OS === 'android') {
return (
<View style={styles.container} behavior="padding" keyboardVerticalOffset={30} enabled>
<View style={{ flexDirection: 'row', padding: 13, justifyContent: 'space-between', alignItems: 'center', backgroundColor: 'rgba(0,0,0,0.1)' }}>
<FontAwesomeIcon name="arrow-left" size={20} onPress={() => { this.props.navigation.goBack() }} color="#FFF" />
</View>
{chat}
</View>
)
}
return <SafeAreaView style={{ flex: 1 }}>{chat}</SafeAreaView>
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#5e5e5e'
},
messageContainer: {
color: 'red'
}
})
But when send one new message at that time message will display separately sender and receiver format. how to differentiate those messages. I use react-native-gifted-chat. but not working properly. I am using react-native-gifted-chat and firebase.

Rendering Firebase data into FlatList

I am using React Native, Rematch for Redux and Firebase Firestore. I am attempting to pull data from my Firebase database and populate it inside my FlatList. The problem is, it is not giving me any error and it giving me a blank white screen. I do not know where I am going wrong.
This is what my database looks like - list of activities
This is what my Rematch for Redux store looks like:
import firebase from 'firebase';
import db from '../config/firebase'
const activity = {
state: {},
reducers: {
activities(state, payload) {
return {
...state,
...payload
}
},
},
effects: {
async getActivities() {
try {
const response = await db.collection('activities').get()
//console.log(response.docs.map(doc => doc.data()))
return dispatch({ type: 'activity/activities', payload: response.docs.map(doc => doc.data()) })
} catch (err) {
alert(err)
}
},
}
}
export default activity
Here is the component where I am using the FlatList:
import * as React from 'react';
import {
Text,
TouchableOpacity,
View,
FlatList,
ImageBackground
}
from 'react-native';
import styles from '../styles'
import { connect } from 'react-redux';
import '#expo/vector-icons';
import 'redux';
class Activities extends React.Component {
state = {
movetoArray: [],
outputActivity: [],
};
async componentDidMount() {
const activities = await this.props.getActivities()
this.state.movetoArray = Object.values(activities)
this.state.outputActivity = Object.entries(this.state.movetoArray[1]).map(item => ({ ...item[1], key: item[0] }));
//this.state.arrayActivity = Object.entries(activities).map(item => ({...item[1], key: item[0]}));
console.log(this.state.outputActivity)
}
_renderItem = ({ item }) => (
<TouchableOpacity
onPress={() => this.props.navigation.navigate('activitiesMD',
{
title: item.name,
objectData: item.data
})}>
<ImageBackground source={item.image} style={styles.inputTiles} imageStyle={{ borderRadius: 10 }}>
<View style={styles.inputTileTextView}>
<Text style={[styles.inputTileText, { color: item.colour }]}>{item.name}</Text>
</View>
</ImageBackground>
</TouchableOpacity>
);
render() {
const { routeName } = this.props.navigation.state
return (
<View style={styles.container}>
<FlatList
data={this.state.outputActivity}
keyExtractor={item => item.id}
renderItem={this._renderItem}
/>
</View>
);
}
}
const mapState = (state) => ({
activity: state.activity,
})
const mapDispatch = (dispatch) => ({
getActivities: () => dispatch.activity.getActivities(),
})
export default connect(mapState, mapDispatch)(Activities)
I do not know why I am getting this outcome. Please help me :)
If you directly mutate state in React then the component won't re-render. Please use this.setState({ ... }) like so:
- this.state.movetoArray = Object.values(activities)
- this.state.outputActivity = Object.entries(this.state.movetoArray[1]).map(item => ({ ...item[1], key: item[0] }));
+ this.setState({ movetoArray: Object.values(activities), outputActivity: Object.entries(this.state.movetoArray[1]).map(item => ({ ...item[1], key: item[0] })) })

How to delete a image in firebase storage using the url of the image in react native?

How to delete a image in firebase storage using the url of the image in react native?
this is the structure of the data
list {
["https://firebasestorage.googleapis.com/v0/b/testes-109.appspot.com/o/photos%2FmdWs20BYhSdR4XIePdpBL9szC7i2%2F79337645-7aa6-4fa3-ab29-9dae6f41bc6?alt=media&token=a9cc2795-f118-485c-94b9-cdf0c083eb2a", "https://firebasestorage.googleapis.com/v0/b/testes-109.appspot.com/o/photos%2FmdWs20BYhSdR4XIePdpBL9szC7i2%2F79337645-7aa6-4fa3-ab29-9dabe6f41bc6?alt=media&token=a9cc2795-f118-48c-94b9-cdf0c83eb2a", ],
}
i tried this
<FlatList
data={list}
renderItem={({ item, index }) => {
return (
<View >
<TouchableOpacity onPress={() => this.deleteImage(item)} >
<Image source={{ uri: item }} style={{ width:100, height: 100 }} />
</TouchableOpacity >
</View>
)
}}
/>
deleteImage = (item) => {
alert(item)
var desertRef = item;
desertRef.delete()
.then(function() {
console.log('File deleted successfully')
}).catch(function(error) {
console.log('Uh-oh, an error occurred!')
});
}
but got this error
desertRef.delete is not a fuction. (in 'desertRef.delete()', 'desertRef.delete' is undefined
create storage object with your firebaseConfig
const app = initializeApp(firebaseConfig);
const storage = getStorage(app);
export default storage;
You need to use the following function to delete it from storage.
import { deleteObject, ref } from "firebase/storage";
import storage from "<your storage file path where you export it>";
export const deleteFromStorage = (file: string | undefined) => {
if (file) {
let pictureRef = ref(storage, file);
deleteObject(pictureRef)
.then(() => {
alert("Picture is deleted successfully!");
})
.catch((err) => {
console.log(err);
});
}
}

TypeError: undefined is not an object (evaluating 'const.join')

How to declare an array on a state variable
Im using react native expo and firebase all is up to date
export default class Profile extends Component {
state = {
ageRangeValues: this.props.user.ageRange,
distanceValue: [this.props.user.distance],
}
render() {
const {
ageRangeValues,
distanceValue,
} = this.state;
return (
<View>
<Slider
min={5}
max={100}
values={distanceValue}
onValuesChange={val => this.setState({ distanceValue: val })}
onValuesChangeFinish={val => this.updateUser('distance', val[0])}
/>
<Slider
min={18}
max={70}
values={ageRangeValues}
onValuesChange={val => this.setState({ ageRangeValues: val })}
onValuesChangeFinish={val => this.updateUser('ageRange', val)}
/>
</View>) }
I expect this to work fine but the ageRangeValue is undefined but the distanceValue in defined don't know why may be is because ageRangeValue takes ageRange and its an Array. If I declare areRangeValue: [19, 20], everything works, but if I left it the way it is all my values are undefined
and here is my preload
const firebaseConfig = {
apiKey: 'XXXXXXXXX',
databaseURL: 'XXXXX',
storageBucket: 'XXXXX',
};
firebase.initializeApp(firebaseConfig);
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
width: null,
height: null,
resizeMode: 'contain',
},
});
export default class Preload extends Component {
constructor() {
super();
this.loadApp();
// SVGAnimatedLengthList.loadApp();
}
authenticate = (token) => {
const provider = firebase.auth.FacebookAuthProvider
const credential = provider.credential(token);
return firebase.auth().signInWithCredential(credential);
};
_goHome = (user) => {
const resetAction = StackActions.reset({
index: 0,
actions: [NavigationActions.navigate({ routeName: 'Home', params: { user } })],
});
this.props.navigation.dispatch(resetAction);
};
loadApp = async () => {
//firebase.auth().signOut();
firebase.auth().onAuthStateChanged((auth) => {
if (auth) {
this.firebaseRef = firebase.database().ref('users');
this.firebaseRef.child(auth.uid).on('value', (snap) => {
const user = firebase.auth().currentUser;
if (user != null) {
this.firebaseRef.child(auth.uid).off('value');
this._goHome(user);
}
});
} else {
this.setState({ showSpinner: false });
this.props.navigation.navigate('Login');
}
});
}
render() {
return (
<ImageBackground source={require('./images/fondo.png')} style={styles.container}>
<ActivityIndicator />
</ImageBackground>
);
}
}
Try it with constructor
export default class Profile extends Component {
constructor(){
super();
this.state = {
ageRangeValues: this.props.user.ageRange,
distanceValue: [this.props.user.distance],
};
}
render() {
const { ageRangeValues, distanceValue } = this.state;
return (
<View>
<Slider
min={5}
max={100}
values={distanceValue}
onValuesChange={val => this.setState({ distanceValue: val })}
onValuesChangeFinish={val => this.updateUser('distance', val[0])}
/>
<Slider
min={18}
max={70}
values={ageRangeValues}
onValuesChange={val => this.setState({ ageRangeValues: val })}
onValuesChangeFinish={val => this.updateUser('ageRange', val)}
/>
</View>
);
}
Vencovsky was right on the previews page that pass the data
loadApp = async () => {
//firebase.auth().signOut();
firebase.auth().onAuthStateChanged((auth) => {
if (auth) {
this.firebaseRef = firebase.database().ref('users');
this.firebaseRef.child(auth.uid).on('value', (snap) => {
const user = firebase.auth().currentUser;
if (user != null) {
this.firebaseRef.child(auth.uid).off('value');
this._goHome(user);
}
});
} else {
this.setState({ showSpinner: false });
this.props.navigation.navigate('Login');
}
});
}
Changing const user = firebase.auth().currentUser; to const user = snap.val();
made the trick

View not updating state Redux, React, Firebase

I am using redux to store and fetch my data from Firebase. The data is stored successfully, however, the view MyActivities is not updated with the new data. Am I doing something wrong here ?
I need to rerender the whole application for the views to be updated with the new data stored in Firebase.
I didn't add all the code used in this example.
ActivitiesAction.js
import firebase from 'firebase';
import { Navigation } from 'react-native-navigation';
import {
ACTIVITIES_FETCH_SUCCESS,
ACTIVITIES_SEND_SUCCESS,
SUBACTIVITY_SEND_SUCCESS
} from './types';
export const activitiesFetch = () => {
return (dispatch) => {
firebase.database().ref('users_data/s80GnOQu22W4XLLYbuKUBC2BzkY2/').once('value')
.then((snapshot) => {
dispatch({
type: ACTIVITIES_FETCH_SUCCESS,
payload: snapshot.val()
});
});
};
};
export const activitiesSend = (activityDescription,
activityDate, category, notification, alarm) => {
const ref = firebase.database()
.ref('users_data/s80GnOQu22W4XLLYbuKUBC2BzkY2/activities/cheduled_activities');
const activity = ref.push();
const ref2 = firebase.database()
.ref('users_data/s80GnOQu22W4XLLYbuKUBC2BzkY2/activities/all_activities');
const activityList = ref2.push();
return (dispatch) => {
activity.set({
activityDescription,
activityDate,
category,
// time: this.state.time,
notification,
alarm
}).then(activityCreated => {
dispatch({ type: ACTIVITIES_SEND_SUCCESS, payload: activityCreated });
activityList.set({
activityDescription,
category
}).then(listActivity => {
dispatch({ type: SUBACTIVITY_SEND_SUCCESS, payload: listActivity });
});
});
};
};
ActivitiesReducer.js
import {
ACTIVITIES_FETCH_SUCCESS,
ACTIVITIES_SEND_SUCCESS,
SUBACTIVITY_SEND_SUCCESS
} from '../actions/types';
const INITIAL_STATE = { activitiesData: '', activityCreated: null, listActivity: null };
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case ACTIVITIES_FETCH_SUCCESS:
return { ...state, activitiesData: action.payload };
case ACTIVITIES_SEND_SUCCESS:
return { ...state, activityCreated: action.payload };
case SUBACTIVITY_SEND_SUCCESS:
return { ...state, listActivity: action.payload };
default:
return state;
}
};
MyActivities.js
import React, { Component } from 'react';
import { Container, Content, View } from 'native-base';
import { connect } from 'react-redux';
import _ from 'lodash';
import { activitiesFetch } from '../actions/ActivitiesAction';
import Activity from './Activity';
class MyActivities extends Component {
constructor(props) {
super(props);
}
componentWillMount() {
this.props.activitiesFetch();
}
componentWillReceiveProps(nextProps) {
this.setState({ activitiesData: nextProps });
console.log('next props:', nextProps);
}
componentWillUpdate(nextProps, nextState) {
console.log('next props:', nextProps);
}
renderActivities() {
// this.setState({ data: this.props.activitiesArray });
console.log('acti():', this.props.activitiesData);
const activitiesArray = _.values(this.props.activitiesData);
console.log('acti[]:', activitiesArray);
const list = _.values(activitiesArray[0]) || [];
const act = list.map((activities) => (activities));
console.log('acti[]:', act);
const activities = _.values(act[1]);
return (
activities.map((singleActivity, i) => (
<Activity
key={i}
Title={singleActivity.activityDescription}
Author={activitiesArray[1].full_name}
Time={singleActivity.time}
PeopleStats={'0'}
/>
))
);
}
render() {
return (
<Container>
{/* <HeaderActivities /> */}
<Content style={styles.Content}>
{/* <ScrollView style={{ flex: 1 }}> */}
<View style={styles.styleView}>
{this.renderActivities()}
</View>
{/* </ScrollView> */}
</Content>
</Container>
);
}
}
const mapStateToProps = state => {
return {
// activitiesArray: _.values(state.activitiesData)
activitiesData: state.activitiesData
};
};
const styles = {
Content: {
backgroundColor: '#F0F5F7',
},
styleView: {
flex: 1,
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'center',
alignItems: 'center',
// alignItems: 'flex-start',
// alignContent: 'flex-start'
},
ButtonActive: {
borderBottomColor: '#FF8600',
borderBottomWidth: 3,
paddingBottom: 3,
borderRadius: 0
}
};
export default connect(mapStateToProps, { activitiesFetch })(MyActivities);
Use the redux and react dev tools to check
did the expected action dispatch?
does the state change match your expectations?
do components have the props you expect them to have?

Resources