im relative new to react native and firebase and it would be awesome if anyone could help me with this problem. currently when im adding new posts to my firebase collection i display all post with a flatlist and it works fine. but is it possible to get only the currentLatitude and currentLongitude for my markers? my target is to generate a new marker for each post.
Events = []
this.firestore.collection("Events").get().then(snapshot => {
snapshot.forEach(doc => {
Events.push(doc.data())
})
})
render() {
return (
<SafeAreaView style={{ flex: 1 }}>
<View style={{ flex: 1 }}>
<MapView
provider={PROVIDER_GOOGLE}
mapType='hybrid'
showsUserLocation style={{flex: 1}}>
<MapView.Marker
coordinate={{latitude: //currentLatitude,
longitude: //currntLongitude}}
title={("Test")}
description={("Test")}
/>
</MapView>
</View>
</SafeAreaView>
);
}
}
#DevAS thanks for your patience.. this was made from 3 different .js files.. but I don't now how to get it just into the map.js.
The final result should look something like this:
enter image description here
Everything except for the lat/lng cords are supposed to be in the callout-window.
Item.js:
import { Ionicons } from '#expo/vector-icons';
import React from 'react';
import { Image, StyleSheet, Text, View } from 'react-native';
import Fire from '../screens/Fire'
const profileImageSize = 36;
const padding = 12;
export default class Item extends React.Component {
state = {
user: {}
};
componentDidMount() {
const user = this.props.uid || Fire.shared.uid;
this.unsubscribe = Fire.shared.firestore
.collection("users")
.doc(user)
.onSnapshot(doc => {
this.setState({ user: doc.data() });
});
if (!this.props.imageWidth) {
// Get the size of the web image
Image.getSize(this.props.image, (width, height) => {
this.setState({ width, height });
});
}
}
componentWillUnmount() {
this.unsubscribe();
}
render() {
const { title, address, name, imageWidth, imageHeight, image, currentLatitude, currentLongitude } = this.props;
// Reduce the name to something
const imgW = imageWidth || this.state.width;
const imgH = imageHeight || this.state.height;
const aspect = imgW / imgH || 1;
return (
<View>
<Header image={{ uri: this.state.user.avatar }} name={this.state.user.name} />
<Image
resizeMode="contain"
style={{
backgroundColor: "#D8D8D8",
width: "100%",
aspectRatio: aspect
}}
source={{ uri: image }}
/>
<Metadata
name={this.state.user.name}
address={address}
title={title}
currentLongitude={currentLongitude}
currentLatitude={currentLatitude}
/>
</View>
);
}
}
const Metadata = ({ name, address, title, currentLongitude, currentLatitude}) => (
<View style={styles.padding}>
<IconBar />
<Text style={styles.text}>{name}</Text>
<Text style={styles.subtitle}>{address}</Text>
<Text style={styles.subtitle}>{title}</Text>
<Text style={styles.subtitle}>Lat: {currentLatitude}</Text>
<Text style={styles.subtitle}>Lng: {currentLongitude}</Text>
</View>
);
const Header = ({ name, image }) => (
<View style={[styles.row, styles.padding]}>
<View style={styles.row}>
<Image style={styles.avatar} source={image} />
<Text style={styles.text}>{name}</Text>
</View>
<Icon name="ios-more" />
</View>
);
const Icon = ({ name }) => (
<Ionicons style={{ marginRight: 8 }} name={name} size={26} color="black" />
);
const IconBar = () => (
<View style={styles.row}>
<View style={styles.row}>
<Icon name="ios-heart-empty" />
<Icon name="ios-chatbubbles" />
<Icon name="ios-send"/>
</View>
<Icon name="ios-bookmark" />
</View>
);
const styles = StyleSheet.create({
text: { fontWeight: "600" },
subtitle: {
opacity: 0.8
},
row: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center"
},
padding: {
padding
},
avatar: {
aspectRatio: 1,
backgroundColor: "#D8D8D8",
borderWidth: StyleSheet.hairlineWidth,
borderColor: "#979797",
borderRadius: profileImageSize / 2,
width: profileImageSize,
height: profileImageSize,
resizeMode: "cover",
marginRight: padding
}
});
List.js
import React from 'react';
import { FlatList } from 'react-native';
import Footer from './Footer';
import Item from './Item';
class List extends React.Component {
renderItem = ({ item }) => <Item {...item} />;
keyExtractor = item => item.key;
render() {
const { onPressFooter, ...props } = this.props;
return (
<FlatList
keyExtractor={this.keyExtractor}
ListFooterComponent={footerProps => (
<Footer {...footerProps} onPress={onPressFooter} />
)}
renderItem={this.renderItem}
{...props}
/>
);
}
}
export default List;
FeedScreen.js
import firebase from "firebase";
import React, { Component } from "react";
import { LayoutAnimation, RefreshControl } from "react-native";
import List from "../components/List";
import Fire from "./Fire";
// Set the default number of images to load for each pagination.
const PAGE_SIZE = 5;
console.disableYellowBox = true;
export default class FeedScreen extends Component {
state = {
loading: false,
data: {}
};
componentDidMount() {
// Check if we are signed in...
if (Fire.shared.uid) {
// If we are, then we can get the first 5 posts
this.makeRemoteRequest();
} else {
// If we aren't then we should just start observing changes. This will be called when the user signs in
firebase.auth().onAuthStateChanged(user => {
if (user) {
this.makeRemoteRequest();
}
});
}
}
// Append the item to our states `data` prop
addPosts = posts => {
this.setState(previousState => {
let data = {
...previousState.data,
...posts
};
return {
data,
// Sort the data by timestamp
posts: Object.values(data).sort((a, b) => a.timestamp < b.timestamp)
};
});
};
// Call our database and ask for a subset of the user posts
makeRemoteRequest = async lastKey => {
// If we are currently getting posts, then bail out..
if (this.state.loading) {
return;
}
this.setState({ loading: true });
// The data prop will be an array of posts, the cursor will be used for pagination.
const { data, cursor } = await Fire.shared.getPaged({
size: PAGE_SIZE,
start: lastKey
});
this.lastKnownKey = cursor;
// Iteratively add posts
let posts = {};
for (let child of data) {
posts[child.key] = child;
}
this.addPosts(posts);
// Finish loading, this will stop the refreshing animation.
this.setState({ loading: false });
};
// Because we want to get the most recent items, don't pass the cursor back.
// This will make the data base pull the most recent items.
_onRefresh = () => this.makeRemoteRequest();
// If we press the "Load More..." footer then get the next page of posts
onPressFooter = () => this.makeRemoteRequest(this.lastKnownKey);
render() {
// Let's make everything purrty by calling this method which animates layout changes.
LayoutAnimation.easeInEaseOut();
return (
<List
refreshControl={
<RefreshControl
refreshing={this.state.loading}
onRefresh={this._onRefresh}
/>
}
onPressFooter={this.onPressFooter}
data={this.state.posts}
/>
);
}
}
Related
I'm testing a component called ForgotPasswordComponent in React Native with Jest. The code for the component is seen here:
import { StyleSheet, View, ToastAndroid, Dimensions } from 'react-native'
import React, {useState} from 'react'
import {Button, Headline, Text, TextInput} from 'react-native-paper';
import { getAuth, sendPasswordResetEmail } from "firebase/auth";
import { useNavigation } from '#react-navigation/native';
import { ScaledSheet } from 'react-native-size-matters';
const {height, width} = Dimensions.get('window')
export default function ForgotPasswordComponent() {
const [email, setEmail] = useState('');
const auth = getAuth();
const navigation = useNavigation();
const forgotPassword = () => {
sendPasswordResetEmail(auth, email)
.then(() => {
ToastAndroid.show('Reset password mail sent successfully!', ToastAndroid.LONG);
})
.catch(() => {
ToastAndroid.show('Error: Please check your entered e-mail!', ToastAndroid.LONG)
});
}
return (
<View style={styles.container}>
<View>
<Button style={styles.buttonBack} uppercase={false} onPress={() => {navigation.navigate("Login")}}>
<Text style={styles.buttonTextGoBack}>Go back</Text>
</Button>
</View>
<View>
<Headline style={styles.headline}>Forgot your password? No problem!</Headline>
</View>
<View>
<Text style={styles.inputText}>Email:</Text>
<TextInput style={styles.input} placeholder="Enter your email" value={email} onChangeText={text => setEmail(text)}></TextInput>
</View>
<View>
<Button style={styles.buttonResetPassword} mode="contained" uppercase={false} onPress={forgotPassword}>
<Text style={styles.buttonTextResetPassword}>Reset password</Text>
</Button>
</View>
</View>
)
}
const styles = ScaledSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
marginBottom: '200#s'
},
headline: {
fontSize: '18#s',
marginTop: '60#s',
padding: '20#s',
},
inputText: {
paddingLeft: '14#s',
paddingTop: '6#s',
fontSize: '14#s'
},
input: {
padding: '10#s',
margin: '15#s',
width: width * 0.8,
height: height * 0.03,
fontSize: '14#s'
},
buttonResetPassword: {
width: width * 0.5,
},
buttonBack: {
paddingRight: '260#s',
width: width * 1.1,
},
buttonTextResetPassword: {
color: 'white',
fontSize: '14#s'
},
buttonTextGoBack: {
fontSize: '14#s'
}
})
As it is seen, it uses two functions from Firebase and the component have very little functionality.
Here is the testcases that I have wrote so far:
import React from 'react';
import renderer from 'react-test-renderer'
import ForgotPasswordComponent from '../components/ForgotPassword/ForgotPasswordComponent';
import { NavigationContainer } from '#react-navigation/native';
import { fireEvent, render } from '#testing-library/react-native';
import { Button, TextInput } from 'react-native-paper';
jest.useFakeTimers()
jest.mock('react-native/Libraries/Animated/NativeAnimatedHelper');
const mockGetAuth = jest.fn()
const mockSendPassword = jest.fn(() => {
return Promise.resolve(true)
})
jest.mock('firebase/auth', () => {
return {
getAuth: () => mockGetAuth,
sendPasswordResetEmail: () => mockSendPassword
}
})
//Testing that navigation is working
describe("Navigation working", () => {
it("calls useNavigation and navigates", () => {
const mockedNavigate = jest.fn();
jest.mock('#react-navigation/native', () => (
{ useNavigation: () => ({ navigate: mockedNavigate }) }));
const onPress = jest.fn(mockedNavigate);
const {getByText} = render(
<Button onPress={onPress}>Go Back</Button>,
);
fireEvent.press(getByText('Go Back'));
expect(mockedNavigate).toBeCalledTimes(1);
})
})
//Testing buttons and inputfield are working
describe('Buttons and input on press working', () => {
it('Go back onpress is called', () => {
const onPress = jest.fn();
const {getByText} = render(
<Button onPress={onPress}>Go Back</Button>,
);
fireEvent.press(getByText('Go Back'));
expect(onPress).toBeCalledTimes(1);
});
it('Reset onpress is called', () => {
const onPress = jest.fn();
const {getByText} = render(
<Button onPress={onPress}>Reset password</Button>,
)
fireEvent.press(getByText('Reset password'));
expect(onPress).toBeCalledTimes(1);
})
it('Email onChange is called', () => {
const onChangeTextMock = jest.fn();
const {getByPlaceholderText} = render(
<TextInput placeholder="Enter your email" onChangeText={onChangeTextMock}/>
);
fireEvent.changeText(getByPlaceholderText("Enter your email"), "test#gmail.com");
expect(onChangeTextMock).toBeCalled();
})
});
//Snapshot testing
test('renders forgotPasswordComponent correctly 1', () => {
const tree = renderer.create(
<NavigationContainer>
<ForgotPasswordComponent/>
</NavigationContainer>)
.toJSON();
expect(tree).toMatchSnapshot();
});
All the testcases runs succesfully, but when I inspect the code coverage I don't understand why my onPress function on line 30 and onChangeText function on line 39 are red. It is like they are not getting tested at all despite I have made testcases for them.
Besides are there any solution of how I can test the Firebase function sendPasswordResetEmail is called when the button is pressed and it shows the succesfully toast-message?
I imported a SearchBar from react-native-elements and I want to be able to search my articles by title. So the field I should be able to pull and search from Cloud Firestore is called 'title'. I'm not sure how to do that.
import React, { Component } from "react";
import { StyleSheet, View, FlatList } from "react-native";
import { AppleCard } from "react-native-apple-card-views";
import firebase from "../../Firebase";
import { SearchBar } from 'react-native-elements';
import { ScrollView } from "react-native-gesture-handler";
export default class Discover extends Component {
constructor(props) {
super();
this.ref = firebase.firestore().collection("articles").where("publish", "==", true);
this.unsubscribe = null;
this.state = {
articles: [],
search: '',
};
}
onCollectionUpdate = (querySnapshot) => {
const articles = [];
querySnapshot.forEach((doc) => {
const { title, subtitle, imageUrlPath } = doc.data();
articles.push({
key: doc.id,
doc, // DocumentSnapshot
title,
subtitle,
imageUrlPath,
});
});
this.setState({
articles,
});
};
componentDidMount() {
this.unsubscribe = this.ref.onSnapshot(this.onCollectionUpdate);
}
updateSearch = (search) => {
this.setState({ search });
};
renderItem = ({ item }) => {
return (
<View>
<View style={styles.card}>
<AppleCard
largeTitle={item.title}
smallTitle=""
footnoteText={item.subtitle}
resizeMode="cover"
source={{uri:item.imageUrlPath}}
onPress={() => {
this.props.navigation.navigate("Content", {
articlekey: `${JSON.stringify(item.key)}`,
});
}}
/>
</View>
</View>
);
};
render() {
const { search } = this.state;
return (
<ScrollView>
<SearchBar
placeholder="Search here..."
onChangeText={this.updateSearch}
value={search}
platform='ios'
/>
<View style={styles.discover}>
<FlatList data={this.state.articles} renderItem={this.renderItem} />
</View>
</ScrollView>
);
}
}
const styles = StyleSheet.create({
discover: {
flex: 1,
backgroundColor: "#FBFCFC",
alignItems: "center",
justifyContent: "center",
},
card: {
padding: 15,
},
});
Here I have use Redux to manage state value but is not working..
And i have two arrays to hold the state values but it is not showing any record i don't know why it is not working..
notesReducer.js
import remove from 'lodash.remove'
// Action Types
export const ADD_NOTE = 'ADD_NOTE'
export const DELETE_NOTE = 'DELETE_NOTE'
export const ADD_NUMBER = 'ADD_NUMBER'
export const DELETE_NUMBER = 'DELETE_NUMBER'
// Action Creators
let noteID = 0
let numberID = 0
export function addnote(note) {
return {
type: ADD_NOTE,
id: noteID++,
note
}
}
export function deletenote(id) {
return {
type: DELETE_NOTE,
payload: id
}
}
export function addnumber(number) {
return {
type: ADD_NUMBER,
id: numberID++,
number
}
}
export function deletenumber(id) {
return {
type: DELETE_NUMBER,
payload: id
}
}
// reducer
const INITIAL_STATE = {
note: [], // for holds notes
number: [] // for holds numbers
};
function notesReducer(state = INITIAL_STATE, action) {
switch (action.type) {
case ADD_NOTE:
return {
...state,
note: [
...state.note,
{
id: action.id,
note: action.note
}
]
};
case DELETE_NOTE:
const note = remove(state.note, obj => obj.id != action.payload);
return {...state, note};
case ADD_NUMBER:
return {
...state,
number: [
...state.number,
{
id: action.id,
number: action.number
}
]
};
case DELETE_NUMBER:
const number = remove(state.number, obj => obj.id != action.payload);
return {...state, number}
default:
return state
}
}
export default notesReducer
And single Store
store.js
import { createStore } from 'redux'
import notesReducer from './notesApp'
const store = createStore(notesReducer)
export default store
ViewNotes.js
import React from 'react'
import { Button, StyleSheet, View, FlatList } from 'react-native'
import { Text, FAB, List } from 'react-native-paper'
import { useSelector, useDispatch } from 'react-redux'
import { addnote, deletenote } from '../redux/notesApp'
import { Ionicons } from "react-native-vector-icons";
import Header from '../components/Header'
function ViewNotes({ navigation }) {
const notes = useSelector(state => state)
const dispatch = useDispatch()
const addNote = note => dispatch(addnote(note))
const deleteNote = id => dispatch(deletenote(id))
return (
<>
<Header titleText='White List' />
<View style={styles.container}>
<Button title="Go back" onPress={() => navigation.goBack()} />
{notes.length === 0 ? (
<View style={styles.titleContainer}>
<Text style={styles.title}>You do not have any notes</Text>
</View>
) : (
<FlatList
data={notes}
renderItem={({ item }) => (
<List.Item
title={item.note.noteTitle}
description={item.note.noteValue}
right={props => <List.Icon {...props} icon="close" />}
descriptionNumberOfLines={1}
titleStyle={styles.listTitle}
onPress={() => deleteNote(item.id)}
/>
)}
keyExtractor={item => item.id.toString()}
/>
)}
<FAB
style={styles.fab}
small
icon='plus'
label='Add new number'
onPress={() =>
navigation.navigate('AddNotes', {
addNote
})
}
/>
</View>
</>
)
}
ViewNotes.navigationOptions = {
title : 'Always Allows Calls'
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
paddingHorizontal: 10,
paddingVertical: 20
},
titleContainer: {
alignItems: 'center',
justifyContent: 'center',
flex: 1
},
title: {
fontSize: 20
},
fab: {
position: 'absolute',
margin: 20,
right: 0,
bottom: 10
},
listTitle: {
fontSize: 20
}
})
export default ViewNotes
AddNote.js
import React, { useState } from 'react'
import { View, StyleSheet } from 'react-native'
import { IconButton, TextInput, FAB } from 'react-native-paper'
import Header from '../components/Header'
function AddNote({ navigation }) {
const [noteTitle, setNoteTitle] = useState('')
const [noteValue, setNoteValue] = useState('')
function onSaveNote() {
navigation.state.params.addNote({ noteTitle, noteValue })
navigation.goBack()
}
return (
<>
<Header titleText='Add a new number' />
<IconButton
icon='close'
size={25}
color='white'
onPress={() => navigation.goBack()}
style={styles.iconButton}
/>
<View style={styles.container}>
<TextInput
label='Add Title Here'
value={noteTitle}
mode='outlined'
onChangeText={setNoteTitle}
style={styles.title}
/>
<TextInput
label='Add Note Here'
value={noteValue}
onChangeText={setNoteValue}
mode='flat'
multiline={true}
style={styles.text}
scrollEnabled={true}
returnKeyType='done'
blurOnSubmit={true}
/>
<FAB
style={styles.fab}
small
icon='check'
disabled={noteTitle == '' ? true : false}
onPress={() => onSaveNote()}
/>
</View>
</>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
paddingHorizontal: 20,
paddingVertical: 20
},
iconButton: {
backgroundColor: 'rgba(46, 113, 102, 0.8)',
position: 'absolute',
right: 0,
top: 40,
margin: 10
},
title: {
fontSize: 24,
marginBottom: 20
},
text: {
height: 300,
fontSize: 16
},
fab: {
position: 'absolute',
margin: 20,
right: 0,
bottom: 0
}
})
export default AddNote
It is not Showing any record So How i fixed it..
Please Help me..
Change useSelector(state => state) to :
useSelector(state => state.note)
Because your store is like {note: [], number: []}
Im trying to get all my Firebase Docs/Posts into React-Native-Maps Markers and show them on a map(like AirBnB for example) but couldn't found out the wright way till now..
all my functions are working fine with a flatlist as you can see in the screenshot but how can I get the data into the markers? Ive tried to get the data + renderItem function from the Flatlist tag and put it into the MapView tag but it didn't work because of the open brace/funtion.
Im fairly new in JS/RN.. so im maybe not really able to understand all of the technical terminology. I would be very thankful if someone has a solution for that.. im struggling for several weeks with this issue.
Fire.js function:
export async function getMarker(markerRetreived) {
var marker = [];
var snapshot = await firebase.firestore()
.collection('Events')
.orderBy('createdAt')
.get()
snapshot.forEach((doc) => {
const markerItem = doc.data();
markerItem.id = doc.id;
marker.push(markerItem);
});
markerRetreived(marker);
}
Working Flatlist (map.js):
class FocusOnMarkers extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
marker: []
}
}
onMarkerReceived = (marker) => {
this.setState(prevState => ({
marker: prevState.marker = marker
}));
}
componentDidMount() {
getMarker(this.onMarkerReceived);
}
render() {
return (
<SafeAreaView style={styles.container}>
<FlatList style={styles.container}
data={this.state.marker}
renderItem={({ item }) => {
return (
<ListItem
containerStyle={styles.listItem}
title={`lat: ${item.geopoint.latitude}`}
subtitle={`lng: ${item.geopoint.longitude}`}
titleStyle={styles.titleStyle}
subtitleStyle={styles.subtitleStyle}
leftAvatar={{
size: 'large',
rounded: false,
source: item.image && { uri: item.image }
}}
/>
)
}
}
/>
</SafeAreaView>
)
}
}
React-Native-Map:
render() {
return (
<SafeAreaView style={{ flex: 1 }}>
<View style={{ flex: 1 }}>
<MapView
provider={PROVIDER_GOOGLE}
mapType='hybrid'
showsUserLocation style={{flex: 1}}>
<MapView.Marker
data={this.state.marker}
coordinate={{latitude: this.state.geopoint.latitude,
longitude:this.state.geopoint.longitude}}
title={("Test")}
description={("Test")}
/>
</MapView>
</View>
</SafeAreaView>
);
}
}
I just wanna let you now that I solved the problem by myself.
just changed a line of code in my map.js =>
render() {
return (
<SafeAreaView style={{ flex: 1 }}>
<View style={{ flex: 1 }}>
<MapView
provider={PROVIDER_GOOGLE}
mapType='hybrid'
showsUserLocation style={{flex: 1}}>
{this.state.marker.map(item => (
<MapView.Marker
coordinate={{latitude: item.geopoint.latitude,
longitude: item.geopoint.longitude}}
title={("Test")}
description={("Test")}
/>
)}
</MapView>
</View>
</SafeAreaView>
);
}
}
I'm creating a react native app. now I want to view my App database tables.
I don't know how many tables are in my SQLite database.
I am new in react native development & SQLite please help. to solve this issue
You can solve this problem through the Table View command. It can also be used to view data for that table.
/*Screen to view all the table*/
import React from 'react';
import { FlatList, Text, View } from 'react-native';
import { openDatabase } from 'react-native-sqlite-storage';
var db = openDatabase({ name: 'UserDatabase.db' });
export default class ViewAllTable extends React.Component {
constructor(props) {
super(props);
this.state = {
FlatListItems: [],
};
db.transaction(tx => {
tx.executeSql('SHOW TABLES', [], (tx, results) => {
var temp = [];
for (let i = 0; i < results.rows.length; ++i) {
temp.push(results.rows.item(i));
}
this.setState({
FlatListItems: temp,
});
});
});
}
ListViewItemSeparator = () => {
return (
<View style={{ height: 0.2, width: '100%', backgroundColor: '#808080' }} />
);
};
render() {
return (
<View>
<FlatList
data={this.state.FlatListItems}
ItemSeparatorComponent={this.ListViewItemSeparator}
keyExtractor={(item, index) => index.toString()}
renderItem={({item, index }) => (
<View key={item[index]} style={{ backgroundColor: 'white', padding: 20 }}>
<Text>Table: {item[index]}</Text>
</View>
)}
/>
</View>
);
}
}