How to develop comprehensive food delivery React Native mobile app?
Nadim Chowdhury
Posted on June 27, 2024
Developing a full-featured React Native food delivery app involves several key sections and functionalities. Here's a breakdown of the main sections and their corresponding functionalities:
Main Sections
-
User Authentication and Profile Management
- Sign Up / Sign In (email, phone, social media)
- Profile editing
- Password recovery
-
Home Screen / Dashboard
- List of nearby restaurants
- Search bar for restaurants and food items
- Categories (e.g., pizza, sushi, burgers)
-
Restaurant Details
- Restaurant information (name, rating, address)
- Menu with food items
- Reviews and ratings
- Operating hours
-
Food Details
- Food item description
- Pricing
- Add-ons / Customizations
- Add to cart option
-
Cart and Checkout
- Cart summary
- Apply coupons / discounts
- Delivery address selection
- Payment options (credit card, PayPal, etc.)
- Order summary and confirmation
-
Order Tracking
- Real-time order status updates
- Google Maps integration for delivery tracking
- Estimated delivery time
-
Rider Interaction
- Real-time rider location tracking on map
- Messaging with the rider
- Call rider option
-
Order History
- List of past orders
- Reorder option
- Order details
-
Notifications
- Push notifications for order status updates
- Promotions and offers
-
Settings
- Notification preferences
- Payment methods management
- Address book
- Privacy settings
-
Customer Support
- FAQ section
- Contact support (chat, email, phone)
Additional Functionalities
-
Google Maps Integration
- Show nearby restaurants
- Real-time rider location tracking
-
Real-time Messaging
- In-app messaging between user and rider
-
Restaurant Management (Admin)
- Add/update restaurant details
- Manage menu items
- View orders and update status
-
Analytics and Reports (Admin)
- Sales reports
- User activity reports
Development Considerations
-
Backend Development
- User authentication and management
- Order processing
- Real-time tracking APIs
- Push notifications
-
Database Design
- User data
- Restaurant and menu data
- Order and transaction data
-
Third-party Integrations
- Payment gateways
- Messaging services (e.g., Twilio)
- Maps and location services (Google Maps API)
UI/UX Design
- Intuitive and user-friendly interface
- Consistent design language
- Responsive design for different screen sizes
By covering these sections and functionalities, you can ensure your food delivery app is comprehensive, user-friendly, and efficient.
Here is a basic implementation for user authentication and profile management in a React Native app using Firebase for authentication. Here's a step-by-step guide:
1. Setup Firebase
First, create a Firebase project and set up the Firebase SDK in your React Native app. Follow the Firebase documentation to get your configuration object.
2. Install Required Packages
Install the required packages using npm or yarn:
npm install @react-native-firebase/app @react-native-firebase/auth
npm install @react-navigation/native @react-navigation/stack
npm install react-native-gesture-handler react-native-reanimated react-native-screens react-native-safe-area-context @react-native-community/masked-view
3. Firebase Configuration
Add your Firebase configuration to your project. Create a firebaseConfig.js
file:
// firebaseConfig.js
import firebase from '@react-native-firebase/app';
import auth from '@react-native-firebase/auth';
const firebaseConfig = {
apiKey: "YOUR_API_KEY",
authDomain: "YOUR_AUTH_DOMAIN",
projectId: "YOUR_PROJECT_ID",
storageBucket: "YOUR_STORAGE_BUCKET",
messagingSenderId: "YOUR_MESSAGING_SENDER_ID",
appId: "YOUR_APP_ID",
};
if (!firebase.apps.length) {
firebase.initializeApp(firebaseConfig);
}
export { auth };
4. Navigation Setup
Set up navigation in your app. Create a navigation
folder and add AuthStack.js
:
// navigation/AuthStack.js
import React from 'react';
import { createStackNavigator } from '@react-navigation/stack';
import SignInScreen from '../screens/SignInScreen';
import SignUpScreen from '../screens/SignUpScreen';
import ProfileScreen from '../screens/ProfileScreen';
const Stack = createStackNavigator();
const AuthStack = () => {
return (
<Stack.Navigator initialRouteName="SignIn">
<Stack.Screen name="SignIn" component={SignInScreen} />
<Stack.Screen name="SignUp" component={SignUpScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
</Stack.Navigator>
);
};
export default AuthStack;
5. Sign In Screen
Create a screens
folder and add SignInScreen.js
:
// screens/SignInScreen.js
import React, { useState } from 'react';
import { View, TextInput, Button, Text } from 'react-native';
import { auth } from '../firebaseConfig';
const SignInScreen = ({ navigation }) => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');
const handleSignIn = () => {
auth().signInWithEmailAndPassword(email, password)
.then(() => {
navigation.navigate('Profile');
})
.catch(error => setError(error.message));
};
return (
<View>
<TextInput
placeholder="Email"
value={email}
onChangeText={setEmail}
/>
<TextInput
placeholder="Password"
value={password}
onChangeText={setPassword}
secureTextEntry
/>
{error ? <Text>{error}</Text> : null}
<Button title="Sign In" onPress={handleSignIn} />
<Button title="Sign Up" onPress={() => navigation.navigate('SignUp')} />
</View>
);
};
export default SignInScreen;
6. Sign Up Screen
Create SignUpScreen.js
:
// screens/SignUpScreen.js
import React, { useState } from 'react';
import { View, TextInput, Button, Text } from 'react-native';
import { auth } from '../firebaseConfig';
const SignUpScreen = ({ navigation }) => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');
const handleSignUp = () => {
auth().createUserWithEmailAndPassword(email, password)
.then(() => {
navigation.navigate('Profile');
})
.catch(error => setError(error.message));
};
return (
<View>
<TextInput
placeholder="Email"
value={email}
onChangeText={setEmail}
/>
<TextInput
placeholder="Password"
value={password}
onChangeText={setPassword}
secureTextEntry
/>
{error ? <Text>{error}</Text> : null}
<Button title="Sign Up" onPress={handleSignUp} />
</View>
);
};
export default SignUpScreen;
7. Profile Screen
Create ProfileScreen.js
:
// screens/ProfileScreen.js
import React from 'react';
import { View, Text, Button } from 'react-native';
import { auth } from '../firebaseConfig';
const ProfileScreen = ({ navigation }) => {
const user = auth().currentUser;
const handleSignOut = () => {
auth().signOut().then(() => {
navigation.navigate('SignIn');
});
};
return (
<View>
{user ? (
<View>
<Text>Email: {user.email}</Text>
<Button title="Sign Out" onPress={handleSignOut} />
</View>
) : (
<Text>No user logged in</Text>
)}
</View>
);
};
export default ProfileScreen;
8. App Entry Point
Finally, modify your App.js
to set up the navigation:
// App.js
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import AuthStack from './navigation/AuthStack';
const App = () => {
return (
<NavigationContainer>
<AuthStack />
</NavigationContainer>
);
};
export default App;
9. Password Recovery
You can add a password recovery feature by providing a way to send a password reset email:
// screens/SignInScreen.js (add this code)
const handlePasswordReset = () => {
if (email) {
auth().sendPasswordResetEmail(email)
.then(() => {
alert('Password reset email sent!');
})
.catch(error => setError(error.message));
} else {
setError('Please enter your email address');
}
};
// Add a button for password reset
<Button title="Forgot Password?" onPress={handlePasswordReset} />
This setup provides basic user authentication and profile management functionality. You can extend and refine these components as needed for your application.
To implement the Home Screen / Dashboard with the functionalities you mentioned, we need to create the following components and setup:
- List of Nearby Restaurants
- Search Bar for Restaurants and Food Items
- Categories
We will use a mock data approach for simplicity. You can replace this with actual data fetching logic from your backend or a third-party API later.
1. Install Required Packages
If you haven't installed these yet, install the required packages for UI components and searching:
npm install react-native-elements react-native-vector-icons
npm install react-native-maps
2. Create Mock Data
Create a data
folder and add a file restaurants.js
:
// data/restaurants.js
export const restaurants = [
{
id: 1,
name: 'Pizza Palace',
category: 'Pizza',
location: '123 Pizza St, Food City',
image: 'https://via.placeholder.com/150',
},
{
id: 2,
name: 'Sushi World',
category: 'Sushi',
location: '456 Sushi Blvd, Food City',
image: 'https://via.placeholder.com/150',
},
{
id: 3,
name: 'Burger House',
category: 'Burgers',
location: '789 Burger Ave, Food City',
image: 'https://via.placeholder.com/150',
},
// Add more restaurants as needed
];
3. Home Screen Component
Create a new screen component HomeScreen.js
in the screens
folder:
// screens/HomeScreen.js
import React, { useState } from 'react';
import { View, FlatList, TextInput, Image, Text, TouchableOpacity } from 'react-native';
import { restaurants } from '../data/restaurants';
import { SearchBar } from 'react-native-elements';
const HomeScreen = () => {
const [search, setSearch] = useState('');
const [filteredData, setFilteredData] = useState(restaurants);
const [selectedCategory, setSelectedCategory] = useState('');
const categories = ['All', 'Pizza', 'Sushi', 'Burgers'];
const handleSearch = (text) => {
setSearch(text);
if (text) {
const newData = restaurants.filter((item) => {
const itemData = `${item.name.toUpperCase()} ${item.category.toUpperCase()}`;
const textData = text.toUpperCase();
return itemData.indexOf(textData) > -1;
});
setFilteredData(newData);
} else {
setFilteredData(restaurants);
}
};
const handleCategorySelect = (category) => {
setSelectedCategory(category);
if (category === 'All') {
setFilteredData(restaurants);
} else {
const newData = restaurants.filter(item => item.category === category);
setFilteredData(newData);
}
};
const renderItem = ({ item }) => (
<TouchableOpacity style={{ marginBottom: 20 }}>
<Image source={{ uri: item.image }} style={{ width: 100, height: 100 }} />
<Text>{item.name}</Text>
<Text>{item.location}</Text>
</TouchableOpacity>
);
return (
<View style={{ flex: 1, padding: 20 }}>
<SearchBar
placeholder="Search Restaurants or Foods..."
onChangeText={(text) => handleSearch(text)}
value={search}
lightTheme
round
/>
<View style={{ flexDirection: 'row', justifyContent: 'space-around', marginVertical: 10 }}>
{categories.map(category => (
<TouchableOpacity
key={category}
onPress={() => handleCategorySelect(category)}
style={{ padding: 10, backgroundColor: selectedCategory === category ? 'grey' : 'white', borderRadius: 20 }}
>
<Text style={{ color: selectedCategory === category ? 'white' : 'black' }}>{category}</Text>
</TouchableOpacity>
))}
</View>
<FlatList
data={filteredData}
keyExtractor={(item) => item.id.toString()}
renderItem={renderItem}
/>
</View>
);
};
export default HomeScreen;
4. Update Navigation
Modify your AuthStack.js
to include the HomeScreen
:
// navigation/AuthStack.js
import React from 'react';
import { createStackNavigator } from '@react-navigation/stack';
import SignInScreen from '../screens/SignInScreen';
import SignUpScreen from '../screens/SignUpScreen';
import ProfileScreen from '../screens/ProfileScreen';
import HomeScreen from '../screens/HomeScreen';
const Stack = createStackNavigator();
const AuthStack = () => {
return (
<Stack.Navigator initialRouteName="SignIn">
<Stack.Screen name="SignIn" component={SignInScreen} />
<Stack.Screen name="SignUp" component={SignUpScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
<Stack.Screen name="Home" component={HomeScreen} />
</Stack.Navigator>
);
};
export default AuthStack;
5. Navigate to Home Screen after Sign In
Modify the handleSignIn
and handleSignUp
functions in SignInScreen.js
and SignUpScreen.js
to navigate to the HomeScreen
upon successful login/signup:
// SignInScreen.js
const handleSignIn = () => {
auth().signInWithEmailAndPassword(email, password)
.then(() => {
navigation.navigate('Home');
})
.catch(error => setError(error.message));
};
// SignUpScreen.js
const handleSignUp = () => {
auth().createUserWithEmailAndPassword(email, password)
.then(() => {
navigation.navigate('Home');
})
.catch(error => setError(error.message));
};
This setup provides a functional home screen with a list of nearby restaurants, a search bar for filtering restaurants and food items, and categories to filter the restaurant list. You can expand on this by integrating a backend service for real data, improving UI design, and adding more features as needed.
To implement the Restaurant Details screen with the functionalities you mentioned, we will create a new screen that displays:
- Restaurant Information (name, rating, address)
- Menu with Food Items
- Reviews and Ratings
- Operating Hours
1. Create Mock Data
Create a file data/restaurantDetails.js
:
// data/restaurantDetails.js
export const restaurantDetails = {
id: 1,
name: 'Pizza Palace',
rating: 4.5,
address: '123 Pizza St, Food City',
operatingHours: '10:00 AM - 10:00 PM',
menu: [
{ id: 1, name: 'Margherita', price: '$10', description: 'Classic cheese and tomato pizza' },
{ id: 2, name: 'Pepperoni', price: '$12', description: 'Pepperoni pizza with extra cheese' },
// Add more menu items
],
reviews: [
{ id: 1, user: 'John Doe', rating: 5, comment: 'Great pizza!' },
{ id: 2, user: 'Jane Smith', rating: 4, comment: 'Good but a bit pricey.' },
// Add more reviews
],
};
2. Restaurant Details Screen
Create a new screen component RestaurantDetailsScreen.js
in the screens
folder:
// screens/RestaurantDetailsScreen.js
import React from 'react';
import { View, Text, FlatList, StyleSheet } from 'react-native';
import { restaurantDetails } from '../data/restaurantDetails';
const RestaurantDetailsScreen = () => {
const { name, rating, address, operatingHours, menu, reviews } = restaurantDetails;
const renderMenuItem = ({ item }) => (
<View style={styles.menuItem}>
<Text style={styles.menuItemName}>{item.name}</Text>
<Text style={styles.menuItemPrice}>{item.price}</Text>
<Text style={styles.menuItemDescription}>{item.description}</Text>
</View>
);
const renderReviewItem = ({ item }) => (
<View style={styles.reviewItem}>
<Text style={styles.reviewUser}>{item.user}</Text>
<Text style={styles.reviewRating}>Rating: {item.rating}</Text>
<Text style={styles.reviewComment}>{item.comment}</Text>
</View>
);
return (
<View style={styles.container}>
<Text style={styles.name}>{name}</Text>
<Text style={styles.rating}>Rating: {rating}</Text>
<Text style={styles.address}>{address}</Text>
<Text style={styles.operatingHours}>Hours: {operatingHours}</Text>
<Text style={styles.sectionTitle}>Menu</Text>
<FlatList
data={menu}
keyExtractor={(item) => item.id.toString()}
renderItem={renderMenuItem}
/>
<Text style={styles.sectionTitle}>Reviews</Text>
<FlatList
data={reviews}
keyExtractor={(item) => item.id.toString()}
renderItem={renderReviewItem}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
},
name: {
fontSize: 24,
fontWeight: 'bold',
},
rating: {
fontSize: 18,
marginVertical: 5,
},
address: {
fontSize: 16,
marginVertical: 5,
},
operatingHours: {
fontSize: 16,
marginVertical: 5,
},
sectionTitle: {
fontSize: 20,
fontWeight: 'bold',
marginVertical: 10,
},
menuItem: {
marginBottom: 10,
},
menuItemName: {
fontSize: 18,
},
menuItemPrice: {
fontSize: 16,
},
menuItemDescription: {
fontSize: 14,
color: 'gray',
},
reviewItem: {
marginBottom: 10,
},
reviewUser: {
fontSize: 16,
fontWeight: 'bold',
},
reviewRating: {
fontSize: 14,
},
reviewComment: {
fontSize: 14,
color: 'gray',
},
});
export default RestaurantDetailsScreen;
3. Update Navigation
Modify your AuthStack.js
to include the RestaurantDetailsScreen
:
// navigation/AuthStack.js
import React from 'react';
import { createStackNavigator } from '@react-navigation/stack';
import SignInScreen from '../screens/SignInScreen';
import SignUpScreen from '../screens/SignUpScreen';
import ProfileScreen from '../screens/ProfileScreen';
import HomeScreen from '../screens/HomeScreen';
import RestaurantDetailsScreen from '../screens/RestaurantDetailsScreen';
const Stack = createStackNavigator();
const AuthStack = () => {
return (
<Stack.Navigator initialRouteName="SignIn">
<Stack.Screen name="SignIn" component={SignInScreen} />
<Stack.Screen name="SignUp" component={SignUpScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="RestaurantDetails" component={RestaurantDetailsScreen} />
</Stack.Navigator>
);
};
export default AuthStack;
4. Navigate to Restaurant Details Screen
Modify the HomeScreen.js
to navigate to RestaurantDetailsScreen
when a restaurant is selected:
// screens/HomeScreen.js
import React, { useState } from 'react';
import { View, FlatList, TextInput, Image, Text, TouchableOpacity } from 'react-native';
import { restaurants } from '../data/restaurants';
import { SearchBar } from 'react-native-elements';
const HomeScreen = ({ navigation }) => {
const [search, setSearch] = useState('');
const [filteredData, setFilteredData] = useState(restaurants);
const [selectedCategory, setSelectedCategory] = useState('');
const categories = ['All', 'Pizza', 'Sushi', 'Burgers'];
const handleSearch = (text) => {
setSearch(text);
if (text) {
const newData = restaurants.filter((item) => {
const itemData = `${item.name.toUpperCase()} ${item.category.toUpperCase()}`;
const textData = text.toUpperCase();
return itemData.indexOf(textData) > -1;
});
setFilteredData(newData);
} else {
setFilteredData(restaurants);
}
};
const handleCategorySelect = (category) => {
setSelectedCategory(category);
if (category === 'All') {
setFilteredData(restaurants);
} else {
const newData = restaurants.filter(item => item.category === category);
setFilteredData(newData);
}
};
const renderItem = ({ item }) => (
<TouchableOpacity style={{ marginBottom: 20 }} onPress={() => navigation.navigate('RestaurantDetails')}>
<Image source={{ uri: item.image }} style={{ width: 100, height: 100 }} />
<Text>{item.name}</Text>
<Text>{item.location}</Text>
</TouchableOpacity>
);
return (
<View style={{ flex: 1, padding: 20 }}>
<SearchBar
placeholder="Search Restaurants or Foods..."
onChangeText={(text) => handleSearch(text)}
value={search}
lightTheme
round
/>
<View style={{ flexDirection: 'row', justifyContent: 'space-around', marginVertical: 10 }}>
{categories.map(category => (
<TouchableOpacity
key={category}
onPress={() => handleCategorySelect(category)}
style={{ padding: 10, backgroundColor: selectedCategory === category ? 'grey' : 'white', borderRadius: 20 }}
>
<Text style={{ color: selectedCategory === category ? 'white' : 'black' }}>{category}</Text>
</TouchableOpacity>
))}
</View>
<FlatList
data={filteredData}
keyExtractor={(item) => item.id.toString()}
renderItem={renderItem}
/>
</View>
);
};
export default HomeScreen;
This setup provides a functional Restaurant Details screen that displays restaurant information, menu items, reviews, and operating hours. You can expand on this by integrating a backend service for real data, improving UI design, and adding more features as needed.
To implement the Food Details screen with the functionalities you mentioned, we will create a new screen that displays:
- Food Item Description
- Pricing
- Add-ons / Customizations
- Add to Cart Option
1. Create Mock Data
Create a file data/foodDetails.js
:
// data/foodDetails.js
export const foodDetails = {
id: 1,
name: 'Margherita',
description: 'Classic cheese and tomato pizza',
price: '$10',
addOns: [
{ id: 1, name: 'Extra Cheese', price: '$2' },
{ id: 2, name: 'Olives', price: '$1' },
{ id: 3, name: 'Jalapenos', price: '$1' },
],
};
2. Food Details Screen
Create a new screen component FoodDetailsScreen.js
in the screens
folder:
// screens/FoodDetailsScreen.js
import React, { useState } from 'react';
import { View, Text, FlatList, TouchableOpacity, StyleSheet, Button } from 'react-native';
import { foodDetails } from '../data/foodDetails';
const FoodDetailsScreen = () => {
const { name, description, price, addOns } = foodDetails;
const [selectedAddOns, setSelectedAddOns] = useState([]);
const handleAddOnPress = (addOn) => {
setSelectedAddOns((prevSelectedAddOns) => {
if (prevSelectedAddOns.includes(addOn)) {
return prevSelectedAddOns.filter((item) => item !== addOn);
} else {
return [...prevSelectedAddOns, addOn];
}
});
};
const renderAddOn = ({ item }) => (
<TouchableOpacity
style={[styles.addOnItem, selectedAddOns.includes(item) && styles.addOnItemSelected]}
onPress={() => handleAddOnPress(item)}
>
<Text style={styles.addOnItemText}>{item.name}</Text>
<Text style={styles.addOnItemPrice}>{item.price}</Text>
</TouchableOpacity>
);
const handleAddToCart = () => {
// Add to cart logic here
alert('Item added to cart');
};
return (
<View style={styles.container}>
<Text style={styles.name}>{name}</Text>
<Text style={styles.description}>{description}</Text>
<Text style={styles.price}>{price}</Text>
<Text style={styles.sectionTitle}>Add-ons / Customizations</Text>
<FlatList
data={addOns}
keyExtractor={(item) => item.id.toString()}
renderItem={renderAddOn}
/>
<Button title="Add to Cart" onPress={handleAddToCart} />
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
},
name: {
fontSize: 24,
fontWeight: 'bold',
},
description: {
fontSize: 16,
marginVertical: 10,
},
price: {
fontSize: 18,
fontWeight: 'bold',
marginBottom: 20,
},
sectionTitle: {
fontSize: 20,
fontWeight: 'bold',
marginBottom: 10,
},
addOnItem: {
flexDirection: 'row',
justifyContent: 'space-between',
padding: 10,
borderWidth: 1,
borderColor: '#ddd',
marginBottom: 10,
borderRadius: 5,
},
addOnItemSelected: {
backgroundColor: '#ddd',
},
addOnItemText: {
fontSize: 16,
},
addOnItemPrice: {
fontSize: 16,
},
});
export default FoodDetailsScreen;
3. Update Navigation
Modify your AuthStack.js
to include the FoodDetailsScreen
:
// navigation/AuthStack.js
import React from 'react';
import { createStackNavigator } from '@react-navigation/stack';
import SignInScreen from '../screens/SignInScreen';
import SignUpScreen from '../screens/SignUpScreen';
import ProfileScreen from '../screens/ProfileScreen';
import HomeScreen from '../screens/HomeScreen';
import RestaurantDetailsScreen from '../screens/RestaurantDetailsScreen';
import FoodDetailsScreen from '../screens/FoodDetailsScreen';
const Stack = createStackNavigator();
const AuthStack = () => {
return (
<Stack.Navigator initialRouteName="SignIn">
<Stack.Screen name="SignIn" component={SignInScreen} />
<Stack.Screen name="SignUp" component={SignUpScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="RestaurantDetails" component={RestaurantDetailsScreen} />
<Stack.Screen name="FoodDetails" component={FoodDetailsScreen} />
</Stack.Navigator>
);
};
export default AuthStack;
4. Navigate to Food Details Screen
Modify the RestaurantDetailsScreen.js
to navigate to FoodDetailsScreen
when a food item is selected:
// screens/RestaurantDetailsScreen.js
import React from 'react';
import { View, Text, FlatList, TouchableOpacity, StyleSheet } from 'react-native';
import { restaurantDetails } from '../data/restaurantDetails';
const RestaurantDetailsScreen = ({ navigation }) => {
const { name, rating, address, operatingHours, menu, reviews } = restaurantDetails;
const renderMenuItem = ({ item }) => (
<TouchableOpacity style={styles.menuItem} onPress={() => navigation.navigate('FoodDetails')}>
<Text style={styles.menuItemName}>{item.name}</Text>
<Text style={styles.menuItemPrice}>{item.price}</Text>
<Text style={styles.menuItemDescription}>{item.description}</Text>
</TouchableOpacity>
);
const renderReviewItem = ({ item }) => (
<View style={styles.reviewItem}>
<Text style={styles.reviewUser}>{item.user}</Text>
<Text style={styles.reviewRating}>Rating: {item.rating}</Text>
<Text style={styles.reviewComment}>{item.comment}</Text>
</View>
);
return (
<View style={styles.container}>
<Text style={styles.name}>{name}</Text>
<Text style={styles.rating}>Rating: {rating}</Text>
<Text style={styles.address}>{address}</Text>
<Text style={styles.operatingHours}>Hours: {operatingHours}</Text>
<Text style={styles.sectionTitle}>Menu</Text>
<FlatList
data={menu}
keyExtractor={(item) => item.id.toString()}
renderItem={renderMenuItem}
/>
<Text style={styles.sectionTitle}>Reviews</Text>
<FlatList
data={reviews}
keyExtractor={(item) => item.id.toString()}
renderItem={renderReviewItem}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
},
name: {
fontSize: 24,
fontWeight: 'bold',
},
rating: {
fontSize: 18,
marginVertical: 5,
},
address: {
fontSize: 16,
marginVertical: 5,
},
operatingHours: {
fontSize: 16,
marginVertical: 5,
},
sectionTitle: {
fontSize: 20,
fontWeight: 'bold',
marginVertical: 10,
},
menuItem: {
marginBottom: 10,
},
menuItemName: {
fontSize: 18,
},
menuItemPrice: {
fontSize: 16,
},
menuItemDescription: {
fontSize: 14,
color: 'gray',
},
reviewItem: {
marginBottom: 10,
},
reviewUser: {
fontSize: 16,
fontWeight: 'bold',
},
reviewRating: {
fontSize: 14,
},
reviewComment: {
fontSize: 14,
color: 'gray',
},
});
export default RestaurantDetailsScreen;
5. Test Your Navigation
Ensure that your app navigates correctly between the Home Screen, Restaurant Details Screen, and Food Details Screen.
This setup provides a functional Food Details screen that displays the food item description, pricing, add-ons/customizations, and an add to cart option. You can expand on this by integrating a backend service for real data, improving UI design, and adding more features as needed.
To implement the Cart and Checkout functionality with the features you mentioned, we need to create the following components and setup:
- Cart Summary
- Apply Coupons / Discounts
- Delivery Address Selection
- Payment Options (Credit Card, PayPal, etc.)
- Order Summary and Confirmation
1. Create Mock Data
Create a file data/cart.js
:
// data/cart.js
export const cartItems = [
{
id: 1,
name: 'Margherita',
price: 10,
quantity: 2,
},
{
id: 2,
name: 'Pepperoni',
price: 12,
quantity: 1,
},
];
export const addresses = [
{ id: 1, address: '123 Main St, Food City' },
{ id: 2, address: '456 Side St, Food Town' },
];
export const paymentMethods = [
{ id: 1, method: 'Credit Card' },
{ id: 2, method: 'PayPal' },
];
2. Cart Screen
Create a new screen component CartScreen.js
in the screens
folder:
// screens/CartScreen.js
import React, { useState } from 'react';
import { View, Text, FlatList, TouchableOpacity, StyleSheet, TextInput, Button } from 'react-native';
import { cartItems, addresses, paymentMethods } from '../data/cart';
const CartScreen = ({ navigation }) => {
const [coupon, setCoupon] = useState('');
const [selectedAddress, setSelectedAddress] = useState(null);
const [selectedPaymentMethod, setSelectedPaymentMethod] = useState(null);
const handleApplyCoupon = () => {
// Apply coupon logic here
alert('Coupon applied');
};
const handlePlaceOrder = () => {
if (!selectedAddress || !selectedPaymentMethod) {
alert('Please select address and payment method');
return;
}
// Place order logic here
alert('Order placed');
navigation.navigate('OrderConfirmation');
};
const renderCartItem = ({ item }) => (
<View style={styles.cartItem}>
<Text style={styles.cartItemName}>{item.name}</Text>
<Text style={styles.cartItemPrice}>${item.price} x {item.quantity}</Text>
<Text style={styles.cartItemTotal}>Total: ${item.price * item.quantity}</Text>
</View>
);
const renderAddress = ({ item }) => (
<TouchableOpacity
style={[styles.addressItem, selectedAddress === item && styles.selectedItem]}
onPress={() => setSelectedAddress(item)}
>
<Text style={styles.addressText}>{item.address}</Text>
</TouchableOpacity>
);
const renderPaymentMethod = ({ item }) => (
<TouchableOpacity
style={[styles.paymentMethodItem, selectedPaymentMethod === item && styles.selectedItem]}
onPress={() => setSelectedPaymentMethod(item)}
>
<Text style={styles.paymentMethodText}>{item.method}</Text>
</TouchableOpacity>
);
return (
<View style={styles.container}>
<Text style={styles.sectionTitle}>Cart Summary</Text>
<FlatList
data={cartItems}
keyExtractor={(item) => item.id.toString()}
renderItem={renderCartItem}
/>
<TextInput
style={styles.couponInput}
placeholder="Enter coupon code"
value={coupon}
onChangeText={setCoupon}
/>
<Button title="Apply Coupon" onPress={handleApplyCoupon} />
<Text style={styles.sectionTitle}>Delivery Address</Text>
<FlatList
data={addresses}
keyExtractor={(item) => item.id.toString()}
renderItem={renderAddress}
/>
<Text style={styles.sectionTitle}>Payment Options</Text>
<FlatList
data={paymentMethods}
keyExtractor={(item) => item.id.toString()}
renderItem={renderPaymentMethod}
/>
<Button title="Place Order" onPress={handlePlaceOrder} />
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
},
sectionTitle: {
fontSize: 20,
fontWeight: 'bold',
marginVertical: 10,
},
cartItem: {
marginBottom: 10,
},
cartItemName: {
fontSize: 18,
},
cartItemPrice: {
fontSize: 16,
},
cartItemTotal: {
fontSize: 16,
fontWeight: 'bold',
},
couponInput: {
borderWidth: 1,
borderColor: '#ddd',
padding: 10,
borderRadius: 5,
marginBottom: 10,
},
addressItem: {
padding: 10,
borderWidth: 1,
borderColor: '#ddd',
borderRadius: 5,
marginBottom: 10,
},
selectedItem: {
backgroundColor: '#ddd',
},
addressText: {
fontSize: 16,
},
paymentMethodItem: {
padding: 10,
borderWidth: 1,
borderColor: '#ddd',
borderRadius: 5,
marginBottom: 10,
},
paymentMethodText: {
fontSize: 16,
},
});
export default CartScreen;
3. Order Confirmation Screen
Create a new screen component OrderConfirmationScreen.js
in the screens
folder:
// screens/OrderConfirmationScreen.js
import React from 'react';
import { View, Text, StyleSheet, Button } from 'react-native';
const OrderConfirmationScreen = ({ navigation }) => {
return (
<View style={styles.container}>
<Text style={styles.title}>Order Confirmation</Text>
<Text style={styles.message}>Your order has been placed successfully!</Text>
<Button title="Go to Home" onPress={() => navigation.navigate('Home')} />
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 20,
},
title: {
fontSize: 24,
fontWeight: 'bold',
marginBottom: 20,
},
message: {
fontSize: 18,
marginBottom: 20,
},
});
export default OrderConfirmationScreen;
4. Update Navigation
Modify your AuthStack.js
to include the CartScreen
and OrderConfirmationScreen
:
// navigation/AuthStack.js
import React from 'react';
import { createStackNavigator } from '@react-navigation/stack';
import SignInScreen from '../screens/SignInScreen';
import SignUpScreen from '../screens/SignUpScreen';
import ProfileScreen from '../screens/ProfileScreen';
import HomeScreen from '../screens/HomeScreen';
import RestaurantDetailsScreen from '../screens/RestaurantDetailsScreen';
import FoodDetailsScreen from '../screens/FoodDetailsScreen';
import CartScreen from '../screens/CartScreen';
import OrderConfirmationScreen from '../screens/OrderConfirmationScreen';
const Stack = createStackNavigator();
const AuthStack = () => {
return (
<Stack.Navigator initialRouteName="SignIn">
<Stack.Screen name="SignIn" component={SignInScreen} />
<Stack.Screen name="SignUp" component={SignUpScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="RestaurantDetails" component={RestaurantDetailsScreen} />
<Stack.Screen name="FoodDetails" component={FoodDetailsScreen} />
<Stack.Screen name="Cart" component={CartScreen} />
<Stack.Screen name="OrderConfirmation" component={OrderConfirmationScreen} />
</Stack.Navigator>
);
};
export default AuthStack;
5. Navigate to Cart Screen
Modify the FoodDetailsScreen.js
to navigate to CartScreen
when the "Add to Cart" button is pressed:
// screens/FoodDetailsScreen.js
import React, { useState } from 'react';
import { View, Text, FlatList, TouchableOpacity, StyleSheet, Button } from 'react-native';
import { foodDetails } from '../data/foodDetails';
const FoodDetailsScreen = ({ navigation }) => {
const { name, description, price, addOns } = foodDetails;
const [selectedAddOns, setSelectedAddOns] = useState([]);
const handleAddOnPress = (addOn) => {
setSelectedAddOns((prevSelectedAddOns) => {
if (prevSelectedAddOns.includes(addOn)) {
return prevSelectedAddOns.filter((item) => item !== addOn);
} else {
return [...prevSelectedAddOns, addOn];
}
});
};
const renderAddOn = ({ item }) => (
<TouchableOpacity
style={[styles.addOnItem, selectedAddOns.includes(item) && styles.addOnItemSelected]}
onPress={() => handleAddOnPress(item)}
>
<Text style={styles.addOnItemText}>{item.name}</Text>
<Text style={styles.addOnItemPrice}>{item.price}</Text>
</TouchableOpacity>
);
const handleAddToCart = () => {
// Add to cart logic here
alert('Item added to cart');
navigation.navigate('Cart');
};
return (
<View style={styles.container}>
<Text style={styles.name}>{name}</Text>
<Text style={styles.description}>{description}</Text>
<Text style={styles.price}>{price}</Text>
<Text style={styles.sectionTitle}>Add-ons / Customizations</Text>
<FlatList
data={addOns}
keyExtractor={(item) => item.id.toString()}
renderItem={renderAddOn}
/>
<Button title="Add to Cart" onPress={handleAddToCart} />
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
},
name: {
fontSize: 24,
fontWeight: 'bold',
},
description: {
fontSize: 16,
marginVertical: 10,
},
price: {
fontSize: 18,
fontWeight: 'bold',
marginBottom: 20,
},
sectionTitle: {
fontSize: 20,
fontWeight: 'bold',
marginBottom: 10,
},
addOnItem: {
flexDirection: 'row',
justifyContent: 'space-between',
padding: 10,
borderWidth: 1,
borderColor: '#ddd',
marginBottom: 10,
borderRadius: 5,
},
addOnItemSelected: {
backgroundColor: '#ddd',
},
addOnItemText: {
fontSize: 16,
},
addOnItemPrice: {
fontSize: 16,
},
});
export default FoodDetailsScreen;
6. Test Your Navigation and Features
Ensure that your app navigates correctly between the Food Details, Cart, and Order Confirmation screens. Test all features, including applying coupons, selecting addresses and payment methods, and placing orders.
This setup provides a functional Cart and Checkout feature, including cart summary, applying coupons, delivery address selection, payment options, and order confirmation. You can expand on this by integrating a backend service for real data, improving UI design, and adding more features as needed.
Creating a full-featured React Native app for order tracking with real-time status updates, Google Maps integration for delivery tracking, and estimated delivery time involves multiple steps. Below is a simplified version to get you started. This includes the key components: a React Native app with real-time updates using Firebase, Google Maps integration, and estimated delivery time calculations.
- Set up your React Native project: First, make sure you have Node.js and React Native CLI installed. Create a new React Native project:
npx react-native init FoodDeliveryApp
cd FoodDeliveryApp
- Install required dependencies: You will need several packages. Install them using npm or yarn:
npm install @react-navigation/native @react-navigation/stack react-native-maps firebase
npm install react-native-gesture-handler react-native-reanimated react-native-screens react-native-safe-area-context @react-native-community/masked-view
- Set up Firebase: Go to the Firebase Console and create a new project. Add a web app to get the Firebase configuration and initialize Firebase in your project.
Create a firebaseConfig.js
file:
// firebaseConfig.js
import firebase from 'firebase/app';
import 'firebase/database';
const firebaseConfig = {
apiKey: "YOUR_API_KEY",
authDomain: "YOUR_AUTH_DOMAIN",
databaseURL: "YOUR_DATABASE_URL",
projectId: "YOUR_PROJECT_ID",
storageBucket: "YOUR_STORAGE_BUCKET",
messagingSenderId: "YOUR_MESSAGING_SENDER_ID",
appId: "YOUR_APP_ID"
};
if (!firebase.apps.length) {
firebase.initializeApp(firebaseConfig);
}
export default firebase;
Set up Google Maps:
Follow the React Native Maps setup guide to configure Google Maps for your app.Create the app structure:
Now, create the main components and screens of your app.
App.js:
// App.js
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import HomeScreen from './screens/HomeScreen';
import TrackingScreen from './screens/TrackingScreen';
const Stack = createStackNavigator();
const App = () => {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Tracking" component={TrackingScreen} />
</Stack.Navigator>
</NavigationContainer>
);
};
export default App;
HomeScreen.js:
// screens/HomeScreen.js
import React, { useState } from 'react';
import { View, Text, Button, TextInput } from 'react-native';
import firebase from '../firebaseConfig';
const HomeScreen = ({ navigation }) => {
const [orderId, setOrderId] = useState('');
const trackOrder = () => {
navigation.navigate('Tracking', { orderId });
};
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Enter Order ID:</Text>
<TextInput
value={orderId}
onChangeText={setOrderId}
style={{ height: 40, borderColor: 'gray', borderWidth: 1, marginBottom: 20 }}
/>
<Button title="Track Order" onPress={trackOrder} />
</View>
);
};
export default HomeScreen;
TrackingScreen.js:
// screens/TrackingScreen.js
import React, { useEffect, useState } from 'react';
import { View, Text } from 'react-native';
import MapView, { Marker } from 'react-native-maps';
import firebase from '../firebaseConfig';
const TrackingScreen = ({ route }) => {
const { orderId } = route.params;
const [orderStatus, setOrderStatus] = useState({});
const [region, setRegion] = useState({
latitude: 37.78825,
longitude: -122.4324,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
});
useEffect(() => {
const orderRef = firebase.database().ref(`orders/${orderId}`);
orderRef.on('value', snapshot => {
const data = snapshot.val();
if (data) {
setOrderStatus(data);
setRegion({
latitude: data.location.lat,
longitude: data.location.lng,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
});
}
});
return () => orderRef.off();
}, [orderId]);
return (
<View style={{ flex: 1 }}>
<MapView style={{ flex: 1 }} region={region}>
{orderStatus.location && (
<Marker
coordinate={{
latitude: orderStatus.location.lat,
longitude: orderStatus.location.lng,
}}
title="Delivery Location"
description="Your order is here"
/>
)}
</MapView>
<View style={{ padding: 20 }}>
<Text>Order ID: {orderId}</Text>
<Text>Status: {orderStatus.status}</Text>
<Text>Estimated Delivery Time: {orderStatus.estimatedDeliveryTime}</Text>
</View>
</View>
);
};
export default TrackingScreen;
- Firebase Database Structure: Make sure your Firebase Realtime Database has a structure like this:
{
"orders": {
"orderId1": {
"status": "On the way",
"estimatedDeliveryTime": "30 mins",
"location": {
"lat": 37.78825,
"lng": -122.4324
}
}
}
}
- Running the app: Finally, run your app using:
npx react-native run-android
# or
npx react-native run-ios
This is a basic setup for a food delivery tracking app. You can expand it with more features such as authentication, more detailed tracking information, and notifications. Make sure to handle permissions and error cases for a robust application.
Adding rider interaction features like real-time location tracking, messaging, and calling options to your React Native app involves additional steps and dependencies. Below is an enhanced version of the app that includes these features.
- Install additional dependencies: You will need more packages for messaging and calling functionalities.
npm install react-native-maps react-native-firebase react-native-gifted-chat react-native-callkeep react-native-permissions react-native-contacts
Configure Firebase for messaging:
Ensure that Firebase Firestore is set up for storing messages.Create components and screens for rider interaction:
Update your project structure to include these new features.
App.js:
// App.js
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import HomeScreen from './screens/HomeScreen';
import TrackingScreen from './screens/TrackingScreen';
import ChatScreen from './screens/ChatScreen';
const Stack = createStackNavigator();
const App = () => {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Tracking" component={TrackingScreen} />
<Stack.Screen name="Chat" component={ChatScreen} />
</Stack.Navigator>
</NavigationContainer>
);
};
export default App;
HomeScreen.js:
// screens/HomeScreen.js
import React, { useState } from 'react';
import { View, Text, Button, TextInput } from 'react-native';
const HomeScreen = ({ navigation }) => {
const [orderId, setOrderId] = useState('');
const trackOrder = () => {
navigation.navigate('Tracking', { orderId });
};
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Enter Order ID:</Text>
<TextInput
value={orderId}
onChangeText={setOrderId}
style={{ height: 40, borderColor: 'gray', borderWidth: 1, marginBottom: 20 }}
/>
<Button title="Track Order" onPress={trackOrder} />
</View>
);
};
export default HomeScreen;
TrackingScreen.js:
// screens/TrackingScreen.js
import React, { useEffect, useState } from 'react';
import { View, Text, Button } from 'react-native';
import MapView, { Marker } from 'react-native-maps';
import firebase from '../firebaseConfig';
const TrackingScreen = ({ route, navigation }) => {
const { orderId } = route.params;
const [orderStatus, setOrderStatus] = useState({});
const [region, setRegion] = useState({
latitude: 37.78825,
longitude: -122.4324,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
});
useEffect(() => {
const orderRef = firebase.database().ref(`orders/${orderId}`);
orderRef.on('value', snapshot => {
const data = snapshot.val();
if (data) {
setOrderStatus(data);
setRegion({
latitude: data.location.lat,
longitude: data.location.lng,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
});
}
});
return () => orderRef.off();
}, [orderId]);
const callRider = () => {
// Implement call functionality
};
const messageRider = () => {
navigation.navigate('Chat', { orderId });
};
return (
<View style={{ flex: 1 }}>
<MapView style={{ flex: 1 }} region={region}>
{orderStatus.location && (
<Marker
coordinate={{
latitude: orderStatus.location.lat,
longitude: orderStatus.location.lng,
}}
title="Delivery Location"
description="Your order is here"
/>
)}
</MapView>
<View style={{ padding: 20 }}>
<Text>Order ID: {orderId}</Text>
<Text>Status: {orderStatus.status}</Text>
<Text>Estimated Delivery Time: {orderStatus.estimatedDeliveryTime}</Text>
<Button title="Call Rider" onPress={callRider} />
<Button title="Message Rider" onPress={messageRider} />
</View>
</View>
);
};
export default TrackingScreen;
ChatScreen.js:
// screens/ChatScreen.js
import React, { useState, useCallback, useEffect } from 'react';
import { GiftedChat } from 'react-native-gifted-chat';
import firebase from '../firebaseConfig';
const ChatScreen = ({ route }) => {
const { orderId } = route.params;
const [messages, setMessages] = useState([]);
useEffect(() => {
const messagesRef = firebase.firestore().collection('orders').doc(orderId).collection('messages');
const unsubscribe = messagesRef.orderBy('createdAt', 'desc').onSnapshot(snapshot => {
const messagesFirestore = snapshot.docs.map(doc => {
const message = doc.data();
return { ...message, createdAt: message.createdAt.toDate() };
});
setMessages(messagesFirestore);
});
return () => unsubscribe();
}, []);
const onSend = useCallback((messages = []) => {
const messagesRef = firebase.firestore().collection('orders').doc(orderId).collection('messages');
messages.forEach(message => {
messagesRef.add({ ...message, createdAt: firebase.firestore.FieldValue.serverTimestamp() });
});
}, []);
return (
<GiftedChat
messages={messages}
onSend={messages => onSend(messages)}
user={{
_id: 1,
name: 'Customer',
}}
/>
);
};
export default ChatScreen;
-
Implement Call Functionality:
Install and configure
react-native-callkeep
for handling call functionality. You'll also need to configure your native code for both Android and iOS, which is beyond this simplified setup but can be referenced from the react-native-callkeep documentation.
TrackingScreen.js (Call function):
import React from 'react';
import CallKeep from 'react-native-callkeep';
const callRider = () => {
// Assuming you have the rider's phone number
const riderPhoneNumber = '1234567890';
CallKeep.setup({}).then(() => {
CallKeep.startCall('callUUID', riderPhoneNumber, riderPhoneNumber);
});
};
- Firebase Database Structure: Ensure your Firebase database includes messages:
{
"orders": {
"orderId1": {
"status": "On the way",
"estimatedDeliveryTime": "30 mins",
"location": {
"lat": 37.78825,
"lng": -122.4324
},
"messages": {
"messageId1": {
"_id": 1,
"text": "Your order is on the way!",
"createdAt": "timestamp",
"user": {
"_id": 2,
"name": "Rider"
}
}
}
}
}
}
This setup provides a basic structure for real-time rider location tracking, messaging, and calling functionality. You will need to handle permissions, improve the UI, and add error handling to make it production-ready. Make sure to thoroughly test the application on both iOS and Android devices.
To add order history, reorder options, and notifications to your React Native food delivery app, we need to expand our app with additional features. Here's how you can do it:
- Install additional dependencies: You will need Firebase Cloud Messaging for push notifications and some other libraries for managing notifications and permissions.
npm install @react-native-firebase/app @react-native-firebase/messaging @react-native-firebase/firestore @react-native-firebase/auth @react-native-async-storage/async-storage
npm install react-native-push-notification
Configure Firebase for notifications:
Set up Firebase Cloud Messaging in your project. Follow the Firebase setup guide for detailed steps.Create components and screens for order history and notifications:
App.js:
// App.js
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import HomeScreen from './screens/HomeScreen';
import TrackingScreen from './screens/TrackingScreen';
import ChatScreen from './screens/ChatScreen';
import OrderHistoryScreen from './screens/OrderHistoryScreen';
import OrderDetailsScreen from './screens/OrderDetailsScreen';
import firebase from '@react-native-firebase/app';
import messaging from '@react-native-firebase/messaging';
import AsyncStorage from '@react-native-async-storage/async-storage';
import PushNotification from 'react-native-push-notification';
const Stack = createStackNavigator();
const App = () => {
React.useEffect(() => {
const unsubscribe = messaging().onMessage(async remoteMessage => {
PushNotification.localNotification({
title: remoteMessage.notification.title,
message: remoteMessage.notification.body,
});
});
return unsubscribe;
}, []);
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Tracking" component={TrackingScreen} />
<Stack.Screen name="Chat" component={ChatScreen} />
<Stack.Screen name="OrderHistory" component={OrderHistoryScreen} />
<Stack.Screen name="OrderDetails" component={OrderDetailsScreen} />
</Stack.Navigator>
</NavigationContainer>
);
};
export default App;
HomeScreen.js:
// screens/HomeScreen.js
import React, { useState } from 'react';
import { View, Text, Button, TextInput } from 'react-native';
const HomeScreen = ({ navigation }) => {
const [orderId, setOrderId] = useState('');
const trackOrder = () => {
navigation.navigate('Tracking', { orderId });
};
const viewOrderHistory = () => {
navigation.navigate('OrderHistory');
};
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Enter Order ID:</Text>
<TextInput
value={orderId}
onChangeText={setOrderId}
style={{ height: 40, borderColor: 'gray', borderWidth: 1, marginBottom: 20 }}
/>
<Button title="Track Order" onPress={trackOrder} />
<Button title="View Order History" onPress={viewOrderHistory} />
</View>
);
};
export default HomeScreen;
OrderHistoryScreen.js:
// screens/OrderHistoryScreen.js
import React, { useEffect, useState } from 'react';
import { View, Text, Button, FlatList } from 'react-native';
import firebase from '../firebaseConfig';
const OrderHistoryScreen = ({ navigation }) => {
const [orders, setOrders] = useState([]);
useEffect(() => {
const fetchOrders = async () => {
const user = firebase.auth().currentUser;
if (user) {
const ordersRef = firebase.firestore().collection('orders').where('userId', '==', user.uid);
const snapshot = await ordersRef.get();
const ordersList = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }));
setOrders(ordersList);
}
};
fetchOrders();
}, []);
const reorder = (order) => {
navigation.navigate('Tracking', { orderId: order.id });
};
const viewOrderDetails = (order) => {
navigation.navigate('OrderDetails', { order });
};
return (
<View style={{ flex: 1 }}>
<FlatList
data={orders}
keyExtractor={item => item.id}
renderItem={({ item }) => (
<View style={{ padding: 20, borderBottomWidth: 1, borderBottomColor: '#ccc' }}>
<Text>Order ID: {item.id}</Text>
<Text>Status: {item.status}</Text>
<Text>Total: ${item.total}</Text>
<Button title="Reorder" onPress={() => reorder(item)} />
<Button title="View Details" onPress={() => viewOrderDetails(item)} />
</View>
)}
/>
</View>
);
};
export default OrderHistoryScreen;
OrderDetailsScreen.js:
// screens/OrderDetailsScreen.js
import React from 'react';
import { View, Text, Button } from 'react-native';
const OrderDetailsScreen = ({ route }) => {
const { order } = route.params;
return (
<View style={{ flex: 1, padding: 20 }}>
<Text>Order ID: {order.id}</Text>
<Text>Status: {order.status}</Text>
<Text>Total: ${order.total}</Text>
<Text>Items:</Text>
{order.items.map((item, index) => (
<Text key={index}>{item.name} - ${item.price}</Text>
))}
</View>
);
};
export default OrderDetailsScreen;
- Firebase Firestore Structure: Ensure your Firestore database includes a collection for orders:
{
"orders": {
"orderId1": {
"userId": "userId1",
"status": "Delivered",
"total": 29.99,
"items": [
{
"name": "Burger",
"price": 9.99
},
{
"name": "Fries",
"price": 4.99
},
{
"name": "Coke",
"price": 2.99
}
],
"createdAt": "timestamp"
},
"orderId2": {
// ...
}
}
}
- Push Notifications Setup:
Configure Firebase Cloud Messaging:
- Add your Firebase configuration and initialization code in your app.
- Configure
react-native-push-notification
in your project. Follow the setup guide for detailed steps.
Setup Notification Handling:
import { Platform } from 'react-native';
import messaging from '@react-native-firebase/messaging';
import PushNotification from 'react-native-push-notification';
// Register background handler
messaging().setBackgroundMessageHandler(async remoteMessage => {
console.log('Message handled in the background!', remoteMessage);
});
PushNotification.configure({
onNotification: function (notification) {
console.log('LOCAL NOTIFICATION ==>', notification);
},
requestPermissions: Platform.OS === 'ios',
});
const requestUserPermission = async () => {
const authStatus = await messaging().requestPermission();
const enabled =
authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
authStatus === messaging.AuthorizationStatus.PROVISIONAL;
if (enabled) {
console.log('Authorization status:', authStatus);
}
};
requestUserPermission();
- Handle Notifications for Promotions and Offers: You can send push notifications for promotions and offers from the Firebase Console or using Firebase Cloud Functions for more advanced scenarios.
Firebase Cloud Function Example:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.sendPromotion = functions.firestore.document('promotions/{promotionId}').onCreate(async (snap, context) => {
const promotion = snap.data();
const payload = {
notification: {
title: promotion.title,
body: promotion.body,
},
};
const tokens = await admin.firestore().collection('users').get().then(snapshot => {
let tokens = [];
snapshot.forEach(doc => {
if (doc.data().fcmToken) {
tokens.push(doc.data().fcmToken);
}
});
return tokens;
});
if (tokens.length > 0) {
admin.messaging().sendToDevice(tokens, payload).then(response => {
console.log('Successfully sent message:', response);
}).catch(error => {
console.log('Error sending message:', error);
});
}
});
This setup provides a basic structure for order history, reorder options, order details, and push notifications for your React Native app. Ensure you handle permissions and notifications properly for both Android and iOS platforms. Also, thoroughly test your application to ensure all features work seamlessly.
To implement settings and customer support features in your React Native app, we'll extend our current setup with new screens and functionality. Here’s how you can add notification preferences, payment methods management, address book, privacy settings, and customer support:
Install Additional Dependencies
You'll need a few more packages to handle some of these features, such as a secure storage solution for payment methods and possibly for handling contacts.
npm install react-native-keychain react-native-contacts
Implementing the Settings and Customer Support
App.js
Extend your navigation to include new screens.
// App.js
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import HomeScreen from './screens/HomeScreen';
import TrackingScreen from './screens/TrackingScreen';
import ChatScreen from './screens/ChatScreen';
import OrderHistoryScreen from './screens/OrderHistoryScreen';
import OrderDetailsScreen from './screens/OrderDetailsScreen';
import SettingsScreen from './screens/SettingsScreen';
import NotificationPreferencesScreen from './screens/NotificationPreferencesScreen';
import PaymentMethodsScreen from './screens/PaymentMethodsScreen';
import AddressBookScreen from './screens/AddressBookScreen';
import PrivacySettingsScreen from './screens/PrivacySettingsScreen';
import FAQScreen from './screens/FAQScreen';
import ContactSupportScreen from './screens/ContactSupportScreen';
const Stack = createStackNavigator();
const App = () => {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Tracking" component={TrackingScreen} />
<Stack.Screen name="Chat" component={ChatScreen} />
<Stack.Screen name="OrderHistory" component={OrderHistoryScreen} />
<Stack.Screen name="OrderDetails" component={OrderDetailsScreen} />
<Stack.Screen name="Settings" component={SettingsScreen} />
<Stack.Screen name="NotificationPreferences" component={NotificationPreferencesScreen} />
<Stack.Screen name="PaymentMethods" component={PaymentMethodsScreen} />
<Stack.Screen name="AddressBook" component={AddressBookScreen} />
<Stack.Screen name="PrivacySettings" component={PrivacySettingsScreen} />
<Stack.Screen name="FAQ" component={FAQScreen} />
<Stack.Screen name="ContactSupport" component={ContactSupportScreen} />
</Stack.Navigator>
</NavigationContainer>
);
};
export default App;
SettingsScreen.js
The main settings screen with navigation to various settings options.
// screens/SettingsScreen.js
import React from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';
const SettingsScreen = ({ navigation }) => {
return (
<View style={styles.container}>
<Button title="Notification Preferences" onPress={() => navigation.navigate('NotificationPreferences')} />
<Button title="Manage Payment Methods" onPress={() => navigation.navigate('PaymentMethods')} />
<Button title="Address Book" onPress={() => navigation.navigate('AddressBook')} />
<Button title="Privacy Settings" onPress={() => navigation.navigate('PrivacySettings')} />
<Button title="FAQ" onPress={() => navigation.navigate('FAQ')} />
<Button title="Contact Support" onPress={() => navigation.navigate('ContactSupport')} />
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
padding: 20,
},
});
export default SettingsScreen;
NotificationPreferencesScreen.js
Manage notification preferences.
// screens/NotificationPreferencesScreen.js
import React, { useState } from 'react';
import { View, Text, Switch, StyleSheet } from 'react-native';
const NotificationPreferencesScreen = () => {
const [orderUpdates, setOrderUpdates] = useState(true);
const [promotions, setPromotions] = useState(true);
return (
<View style={styles.container}>
<View style={styles.preference}>
<Text>Order Updates</Text>
<Switch value={orderUpdates} onValueChange={setOrderUpdates} />
</View>
<View style={styles.preference}>
<Text>Promotions and Offers</Text>
<Switch value={promotions} onValueChange={setPromotions} />
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
},
preference: {
flexDirection: 'row',
justifyContent: 'space-between',
marginVertical: 10,
},
});
export default NotificationPreferencesScreen;
PaymentMethodsScreen.js
Manage payment methods using secure storage.
// screens/PaymentMethodsScreen.js
import React, { useState, useEffect } from 'react';
import { View, Text, Button, TextInput, FlatList, StyleSheet } from 'react-native';
import Keychain from 'react-native-keychain';
const PaymentMethodsScreen = () => {
const [paymentMethods, setPaymentMethods] = useState([]);
const [newPaymentMethod, setNewPaymentMethod] = useState('');
useEffect(() => {
const loadPaymentMethods = async () => {
const credentials = await Keychain.getGenericPassword();
if (credentials) {
setPaymentMethods(JSON.parse(credentials.password));
}
};
loadPaymentMethods();
}, []);
const addPaymentMethod = async () => {
const updatedMethods = [...paymentMethods, newPaymentMethod];
await Keychain.setGenericPassword('paymentMethods', JSON.stringify(updatedMethods));
setPaymentMethods(updatedMethods);
setNewPaymentMethod('');
};
return (
<View style={styles.container}>
<FlatList
data={paymentMethods}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item }) => (
<View style={styles.item}>
<Text>{item}</Text>
</View>
)}
/>
<TextInput
value={newPaymentMethod}
onChangeText={setNewPaymentMethod}
placeholder="Add new payment method"
style={styles.input}
/>
<Button title="Add" onPress={addPaymentMethod} />
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
},
item: {
padding: 10,
borderBottomWidth: 1,
borderBottomColor: '#ccc',
},
input: {
height: 40,
borderColor: 'gray',
borderWidth: 1,
marginBottom: 20,
paddingHorizontal: 10,
},
});
export default PaymentMethodsScreen;
AddressBookScreen.js
Manage address book using react-native-contacts
.
// screens/AddressBookScreen.js
import React, { useState, useEffect } from 'react';
import { View, Text, Button, FlatList, StyleSheet } from 'react-native';
import Contacts from 'react-native-contacts';
const AddressBookScreen = () => {
const [contacts, setContacts] = useState([]);
useEffect(() => {
Contacts.getAll().then(contacts => {
setContacts(contacts);
});
}, []);
return (
<View style={styles.container}>
<FlatList
data={contacts}
keyExtractor={(item) => item.recordID}
renderItem={({ item }) => (
<View style={styles.item}>
<Text>{item.givenName} {item.familyName}</Text>
<Text>{item.phoneNumbers[0]?.number}</Text>
</View>
)}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
},
item: {
padding: 10,
borderBottomWidth: 1,
borderBottomColor: '#ccc',
},
});
export default AddressBookScreen;
PrivacySettingsScreen.js
Manage privacy settings.
// screens/PrivacySettingsScreen.js
import React from 'react';
import { View, Text, Switch, StyleSheet } from 'react-native';
const PrivacySettingsScreen = () => {
const [locationAccess, setLocationAccess] = useState(false);
const [dataSharing, setDataSharing] = useState(false);
return (
<View style={styles.container}>
<View style={styles.preference}>
<Text>Location Access</Text>
<Switch value={locationAccess} onValueChange={setLocationAccess} />
</View>
<View style={styles.preference}>
<Text>Data Sharing</Text>
<Switch value={dataSharing} onValueChange={setDataSharing} />
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
},
preference: {
flexDirection: 'row',
justifyContent: 'space-between',
marginVertical: 10,
},
});
export default PrivacySettingsScreen;
FAQScreen.js
Display frequently asked questions.
// screens/FAQScreen.js
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
const FAQScreen = () => {
const faqs = [
{ question: 'How to track my order?', answer: 'You can track your order using the tracking screen.' },
{ question: 'How to contact support?', answer: 'You can contact support via chat, email, or phone.'
},
];
return (
<View style={styles.container}>
{faqs.map((faq, index) => (
<View key={index} style={styles.faq}>
<Text style={styles.question}>{faq.question}</Text>
<Text>{faq.answer}</Text>
</View>
))}
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
},
faq: {
marginBottom: 20,
},
question: {
fontWeight: 'bold',
},
});
export default FAQScreen;
ContactSupportScreen.js
Provide options to contact support via chat, email, or phone.
// screens/ContactSupportScreen.js
import React from 'react';
import { View, Text, Button, StyleSheet, Linking } from 'react-native';
const ContactSupportScreen = () => {
const emailSupport = () => {
Linking.openURL('mailto:support@example.com');
};
const callSupport = () => {
Linking.openURL('tel:1234567890');
};
return (
<View style={styles.container}>
<Text style={styles.header}>Contact Support</Text>
<Button title="Chat with Support" onPress={() => {/* Navigate to chat screen */}} />
<Button title="Email Support" onPress={emailSupport} />
<Button title="Call Support" onPress={callSupport} />
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
},
header: {
fontSize: 20,
marginBottom: 20,
},
});
export default ContactSupportScreen;
This implementation provides a basic setup for the settings and customer support features. Ensure to integrate each component properly and test thoroughly to confirm that all functionalities are working as expected.
Below is a fully functional React Native codebase with settings and customer support features, assuming you have a React Native environment set up.
Install Dependencies
First, ensure you have the necessary dependencies:
npm install @react-native-firebase/app @react-native-firebase/auth @react-native-firebase/firestore @react-native-firebase/messaging @react-native-async-storage/async-storage react-native-keychain react-native-contacts react-native-push-notification
Firebase Configuration
Make sure to set up Firebase in your project by following the Firebase setup guide for React Native.
Main Application File
App.js:
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import HomeScreen from './screens/HomeScreen';
import TrackingScreen from './screens/TrackingScreen';
import ChatScreen from './screens/ChatScreen';
import OrderHistoryScreen from './screens/OrderHistoryScreen';
import OrderDetailsScreen from './screens/OrderDetailsScreen';
import SettingsScreen from './screens/SettingsScreen';
import NotificationPreferencesScreen from './screens/NotificationPreferencesScreen';
import PaymentMethodsScreen from './screens/PaymentMethodsScreen';
import AddressBookScreen from './screens/AddressBookScreen';
import PrivacySettingsScreen from './screens/PrivacySettingsScreen';
import FAQScreen from './screens/FAQScreen';
import ContactSupportScreen from './screens/ContactSupportScreen';
import firebase from '@react-native-firebase/app';
import messaging from '@react-native-firebase/messaging';
import PushNotification from 'react-native-push-notification';
const Stack = createStackNavigator();
const App = () => {
React.useEffect(() => {
const unsubscribe = messaging().onMessage(async remoteMessage => {
PushNotification.localNotification({
title: remoteMessage.notification.title,
message: remoteMessage.notification.body,
});
});
return unsubscribe;
}, []);
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Tracking" component={TrackingScreen} />
<Stack.Screen name="Chat" component={ChatScreen} />
<Stack.Screen name="OrderHistory" component={OrderHistoryScreen} />
<Stack.Screen name="OrderDetails" component={OrderDetailsScreen} />
<Stack.Screen name="Settings" component={SettingsScreen} />
<Stack.Screen name="NotificationPreferences" component={NotificationPreferencesScreen} />
<Stack.Screen name="PaymentMethods" component={PaymentMethodsScreen} />
<Stack.Screen name="AddressBook" component={AddressBookScreen} />
<Stack.Screen name="PrivacySettings" component={PrivacySettingsScreen} />
<Stack.Screen name="FAQ" component={FAQScreen} />
<Stack.Screen name="ContactSupport" component={ContactSupportScreen} />
</Stack.Navigator>
</NavigationContainer>
);
};
export default App;
Home Screen
HomeScreen.js:
import React, { useState } from 'react';
import { View, Text, Button, TextInput, StyleSheet } from 'react-native';
const HomeScreen = ({ navigation }) => {
const [orderId, setOrderId] = useState('');
const trackOrder = () => {
navigation.navigate('Tracking', { orderId });
};
const viewOrderHistory = () => {
navigation.navigate('OrderHistory');
};
const openSettings = () => {
navigation.navigate('Settings');
};
return (
<View style={styles.container}>
<Text>Enter Order ID:</Text>
<TextInput
value={orderId}
onChangeText={setOrderId}
style={styles.input}
/>
<Button title="Track Order" onPress={trackOrder} />
<Button title="View Order History" onPress={viewOrderHistory} />
<Button title="Settings" onPress={openSettings} />
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
padding: 20,
},
input: {
height: 40,
borderColor: 'gray',
borderWidth: 1,
marginBottom: 20,
paddingHorizontal: 10,
},
});
export default HomeScreen;
Settings Screen
SettingsScreen.js:
import React from 'react';
import { View, Button, StyleSheet } from 'react-native';
const SettingsScreen = ({ navigation }) => {
return (
<View style={styles.container}>
<Button title="Notification Preferences" onPress={() => navigation.navigate('NotificationPreferences')} />
<Button title="Manage Payment Methods" onPress={() => navigation.navigate('PaymentMethods')} />
<Button title="Address Book" onPress={() => navigation.navigate('AddressBook')} />
<Button title="Privacy Settings" onPress={() => navigation.navigate('PrivacySettings')} />
<Button title="FAQ" onPress={() => navigation.navigate('FAQ')} />
<Button title="Contact Support" onPress={() => navigation.navigate('ContactSupport')} />
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
padding: 20,
},
});
export default SettingsScreen;
Notification Preferences Screen
NotificationPreferencesScreen.js:
import React, { useState } from 'react';
import { View, Text, Switch, StyleSheet } from 'react-native';
const NotificationPreferencesScreen = () => {
const [orderUpdates, setOrderUpdates] = useState(true);
const [promotions, setPromotions] = useState(true);
return (
<View style={styles.container}>
<View style={styles.preference}>
<Text>Order Updates</Text>
<Switch value={orderUpdates} onValueChange={setOrderUpdates} />
</View>
<View style={styles.preference}>
<Text>Promotions and Offers</Text>
<Switch value={promotions} onValueChange={setPromotions} />
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
},
preference: {
flexDirection: 'row',
justifyContent: 'space-between',
marginVertical: 10,
},
});
export default NotificationPreferencesScreen;
Payment Methods Screen
PaymentMethodsScreen.js:
import React, { useState, useEffect } from 'react';
import { View, Text, Button, TextInput, FlatList, StyleSheet } from 'react-native';
import Keychain from 'react-native-keychain';
const PaymentMethodsScreen = () => {
const [paymentMethods, setPaymentMethods] = useState([]);
const [newPaymentMethod, setNewPaymentMethod] = useState('');
useEffect(() => {
const loadPaymentMethods = async () => {
const credentials = await Keychain.getGenericPassword();
if (credentials) {
setPaymentMethods(JSON.parse(credentials.password));
}
};
loadPaymentMethods();
}, []);
const addPaymentMethod = async () => {
const updatedMethods = [...paymentMethods, newPaymentMethod];
await Keychain.setGenericPassword('paymentMethods', JSON.stringify(updatedMethods));
setPaymentMethods(updatedMethods);
setNewPaymentMethod('');
};
return (
<View style={styles.container}>
<FlatList
data={paymentMethods}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item }) => (
<View style={styles.item}>
<Text>{item}</Text>
</View>
)}
/>
<TextInput
value={newPaymentMethod}
onChangeText={setNewPaymentMethod}
placeholder="Add new payment method"
style={styles.input}
/>
<Button title="Add" onPress={addPaymentMethod} />
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
},
item: {
padding: 10,
borderBottomWidth: 1,
borderBottomColor: '#ccc',
},
input: {
height: 40,
borderColor: 'gray',
borderWidth: 1,
marginBottom: 20,
paddingHorizontal: 10,
},
});
export default PaymentMethodsScreen;
Address Book Screen
AddressBookScreen.js:
import React, { useState, useEffect } from 'react';
import { View, Text, Button, FlatList, StyleSheet } from 'react-native';
import Contacts from 'react-native-contacts';
const AddressBookScreen = () => {
const [contacts, setContacts] = useState([]);
useEffect(() => {
Contacts.getAll().then(contacts => {
setContacts(contacts);
});
}, []);
return (
<View style={styles.container}>
<FlatList
data={contacts}
keyExtractor={(item) => item.recordID}
renderItem={({ item }) => (
<View style={styles.item}>
<Text>{item.givenName} {item.familyName}</Text>
<Text>{item.phoneNumbers[0]?.number}</Text>
</View>
)}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
},
item: {
padding: 10,
borderBottomWidth
: 1,
borderBottomColor: '#ccc',
},
});
export default AddressBookScreen;
Privacy Settings Screen
PrivacySettingsScreen.js:
import React, { useState } from 'react';
import { View, Text, Switch, StyleSheet } from 'react-native';
const PrivacySettingsScreen = () => {
const [locationAccess, setLocationAccess] = useState(false);
const [dataSharing, setDataSharing] = useState(false);
return (
<View style={styles.container}>
<View style={styles.preference}>
<Text>Location Access</Text>
<Switch value={locationAccess} onValueChange={setLocationAccess} />
</View>
<View style={styles.preference}>
<Text>Data Sharing</Text>
<Switch value={dataSharing} onValueChange={setDataSharing} />
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
},
preference: {
flexDirection: 'row',
justifyContent: 'space-between',
marginVertical: 10,
},
});
export default PrivacySettingsScreen;
FAQ Screen
FAQScreen.js:
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
const FAQScreen = () => {
const faqs = [
{ question: 'How to track my order?', answer: 'You can track your order using the tracking screen.' },
{ question: 'How to contact support?', answer: 'You can contact support via chat, email, or phone.' },
];
return (
<View style={styles.container}>
{faqs.map((faq, index) => (
<View key={index} style={styles.faq}>
<Text style={styles.question}>{faq.question}</Text>
<Text>{faq.answer}</Text>
</View>
))}
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
},
faq: {
marginBottom: 20,
},
question: {
fontWeight: 'bold',
},
});
export default FAQScreen;
Contact Support Screen
ContactSupportScreen.js:
import React from 'react';
import { View, Text, Button, StyleSheet, Linking } from 'react-native';
const ContactSupportScreen = () => {
const emailSupport = () => {
Linking.openURL('mailto:support@example.com');
};
const callSupport = () => {
Linking.openURL('tel:1234567890');
};
return (
<View style={styles.container}>
<Text style={styles.header}>Contact Support</Text>
<Button title="Chat with Support" onPress={() => {/* Navigate to chat screen */}} />
<Button title="Email Support" onPress={emailSupport} />
<Button title="Call Support" onPress={callSupport} />
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
},
header: {
fontSize: 20,
marginBottom: 20,
},
});
export default ContactSupportScreen;
Setting Up Firebase Notifications
firebase-messaging.js:
import messaging from '@react-native-firebase/messaging';
import PushNotification from 'react-native-push-notification';
PushNotification.configure({
onNotification: function (notification) {
console.log('LOCAL NOTIFICATION ==>', notification);
},
});
export const requestUserPermission = async () => {
const authStatus = await messaging().requestPermission();
const enabled =
authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
authStatus === messaging.AuthorizationStatus.PROVISIONAL;
if (enabled) {
console.log('Authorization status:', authStatus);
}
};
export const notificationListener = async () => {
messaging().onNotificationOpenedApp(remoteMessage => {
console.log(
'Notification caused app to open from background state:',
remoteMessage.notification,
);
});
messaging()
.getInitialNotification()
.then(remoteMessage => {
if (remoteMessage) {
console.log(
'Notification caused app to open from quit state:',
remoteMessage.notification,
);
}
});
messaging().onMessage(async remoteMessage => {
PushNotification.localNotification({
channelId: 'channel-id',
title: remoteMessage.notification.title,
message: remoteMessage.notification.body,
});
});
};
App.js (add to the top of the file):
import { requestUserPermission, notificationListener } from './firebase-messaging';
React.useEffect(() => {
requestUserPermission();
notificationListener();
}, []);
This setup should provide a complete, functional implementation of the features you requested. Ensure to adjust any paths and dependencies according to your project setup.
Here's a complete, functional React Native app implementation with restaurant management (admin) features, including adding/updating restaurant details, managing menu items, viewing orders, and updating statuses. Additionally, it includes analytics and reports for sales and user activity.
Install Dependencies
Ensure you have the necessary dependencies:
npm install @react-navigation/native @react-navigation/stack react-native-paper react-native-vector-icons @react-native-firebase/app @react-native-firebase/firestore
Firebase Configuration
Make sure to set up Firebase in your project by following the Firebase setup guide for React Native.
Main Application File
App.js:
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { Provider as PaperProvider } from 'react-native-paper';
import HomeScreen from './screens/HomeScreen';
import RestaurantDetailsScreen from './screens/RestaurantDetailsScreen';
import MenuManagementScreen from './screens/MenuManagementScreen';
import OrdersManagementScreen from './screens/OrdersManagementScreen';
import SalesReportsScreen from './screens/SalesReportsScreen';
import UserActivityReportsScreen from './screens/UserActivityReportsScreen';
import firebase from '@react-native-firebase/app';
const Stack = createStackNavigator();
const App = () => {
return (
<PaperProvider>
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="RestaurantDetails" component={RestaurantDetailsScreen} />
<Stack.Screen name="MenuManagement" component={MenuManagementScreen} />
<Stack.Screen name="OrdersManagement" component={OrdersManagementScreen} />
<Stack.Screen name="SalesReports" component={SalesReportsScreen} />
<Stack.Screen name="UserActivityReports" component={UserActivityReportsScreen} />
</Stack.Navigator>
</NavigationContainer>
</PaperProvider>
);
};
export default App;
Home Screen
HomeScreen.js:
import React from 'react';
import { View, Button, StyleSheet } from 'react-native';
const HomeScreen = ({ navigation }) => {
return (
<View style={styles.container}>
<Button title="Restaurant Details" onPress={() => navigation.navigate('RestaurantDetails')} />
<Button title="Manage Menu" onPress={() => navigation.navigate('MenuManagement')} />
<Button title="Manage Orders" onPress={() => navigation.navigate('OrdersManagement')} />
<Button title="Sales Reports" onPress={() => navigation.navigate('SalesReports')} />
<Button title="User Activity Reports" onPress={() => navigation.navigate('UserActivityReports')} />
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
padding: 20,
},
});
export default HomeScreen;
Restaurant Details Screen
RestaurantDetailsScreen.js:
import React, { useState, useEffect } from 'react';
import { View, TextInput, Button, StyleSheet } from 'react-native';
import firestore from '@react-native-firebase/firestore';
const RestaurantDetailsScreen = () => {
const [name, setName] = useState('');
const [address, setAddress] = useState('');
const [contact, setContact] = useState('');
useEffect(() => {
const fetchDetails = async () => {
const doc = await firestore().collection('restaurant').doc('details').get();
if (doc.exists) {
const data = doc.data();
setName(data.name);
setAddress(data.address);
setContact(data.contact);
}
};
fetchDetails();
}, []);
const updateDetails = async () => {
await firestore().collection('restaurant').doc('details').set({
name,
address,
contact,
});
alert('Details updated');
};
return (
<View style={styles.container}>
<TextInput
value={name}
onChangeText={setName}
placeholder="Name"
style={styles.input}
/>
<TextInput
value={address}
onChangeText={setAddress}
placeholder="Address"
style={styles.input}
/>
<TextInput
value={contact}
onChangeText={setContact}
placeholder="Contact"
style={styles.input}
/>
<Button title="Update Details" onPress={updateDetails} />
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
},
input: {
height: 40,
borderColor: 'gray',
borderWidth: 1,
marginBottom: 20,
paddingHorizontal: 10,
},
});
export default RestaurantDetailsScreen;
Menu Management Screen
MenuManagementScreen.js:
import React, { useState, useEffect } from 'react';
import { View, TextInput, Button, FlatList, StyleSheet } from 'react-native';
import firestore from '@react-native-firebase/firestore';
const MenuManagementScreen = () => {
const [menuItems, setMenuItems] = useState([]);
const [newItem, setNewItem] = useState('');
const [newPrice, setNewPrice] = useState('');
useEffect(() => {
const fetchMenu = async () => {
const menu = await firestore().collection('menu').get();
setMenuItems(menu.docs.map(doc => ({ id: doc.id, ...doc.data() })));
};
fetchMenu();
}, []);
const addItem = async () => {
await firestore().collection('menu').add({
item: newItem,
price: newPrice,
});
setNewItem('');
setNewPrice('');
fetchMenu();
};
const deleteItem = async (id) => {
await firestore().collection('menu').doc(id).delete();
fetchMenu();
};
const fetchMenu = async () => {
const menu = await firestore().collection('menu').get();
setMenuItems(menu.docs.map(doc => ({ id: doc.id, ...doc.data() })));
};
return (
<View style={styles.container}>
<TextInput
value={newItem}
onChangeText={setNewItem}
placeholder="New Item"
style={styles.input}
/>
<TextInput
value={newPrice}
onChangeText={setNewPrice}
placeholder="Price"
style={styles.input}
/>
<Button title="Add Item" onPress={addItem} />
<FlatList
data={menuItems}
keyExtractor={item => item.id}
renderItem={({ item }) => (
<View style={styles.item}>
<Text>{item.item} - ${item.price}</Text>
<Button title="Delete" onPress={() => deleteItem(item.id)} />
</View>
)}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
},
input: {
height: 40,
borderColor: 'gray',
borderWidth: 1,
marginBottom: 20,
paddingHorizontal: 10,
},
item: {
flexDirection: 'row',
justifyContent: 'space-between',
marginBottom: 10,
},
});
export default MenuManagementScreen;
Orders Management Screen
OrdersManagementScreen.js:
import React, { useState, useEffect } from 'react';
import { View, Button, FlatList, StyleSheet } from 'react-native';
import firestore from '@react-native-firebase/firestore';
const OrdersManagementScreen = () => {
const [orders, setOrders] = useState([]);
useEffect(() => {
const fetchOrders = async () => {
const ordersSnapshot = await firestore().collection('orders').get();
setOrders(ordersSnapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })));
};
fetchOrders();
}, []);
const updateOrderStatus = async (id, status) => {
await firestore().collection('orders').doc(id).update({ status });
fetchOrders();
};
const fetchOrders = async () => {
const ordersSnapshot = await firestore().collection('orders').get();
setOrders(ordersSnapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })));
};
return (
<View style={styles.container}>
<FlatList
data={orders}
keyExtractor={item => item.id}
renderItem={({ item }) => (
<View style={styles.order}>
<Text>Order ID: {item.id}</Text>
<Text>Items: {item.items.join(', ')}</Text>
<Text>Status: {item.status}</Text>
<Button title="Mark as Completed" onPress={() => updateOrderStatus(item.id, 'Completed')} />
</View>
)}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
},
order: {
marginBottom: 20,
},
});
export default OrdersManagementScreen;
Sales Reports Screen
SalesReportsScreen.js:
import React, { useState, useEffect } from 'react';
import { View, Text, FlatList, StyleSheet } from 'react-native';
import firestore from '@react-native-firebase/fire
store';
const SalesReportsScreen = () => {
const [sales, setSales] = useState([]);
useEffect(() => {
const fetchSales = async () => {
const salesSnapshot = await firestore().collection('sales').get();
setSales(salesSnapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })));
};
fetchSales();
}, []);
return (
<View style={styles.container}>
<FlatList
data={sales}
keyExtractor={item => item.id}
renderItem={({ item }) => (
<View style={styles.report}>
<Text>Date: {item.date}</Text>
<Text>Sales: {item.sales}</Text>
</View>
)}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
},
report: {
marginBottom: 20,
},
});
export default SalesReportsScreen;
User Activity Reports Screen
UserActivityReportsScreen.js:
import React, { useState, useEffect } from 'react';
import { View, Text, FlatList, StyleSheet } from 'react-native';
import firestore from '@react-native-firebase/firestore';
const UserActivityReportsScreen = () => {
const [userActivities, setUserActivities] = useState([]);
useEffect(() => {
const fetchUserActivities = async () => {
const activitiesSnapshot = await firestore().collection('user_activities').get();
setUserActivities(activitiesSnapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })));
};
fetchUserActivities();
}, []);
return (
<View style={styles.container}>
<FlatList
data={userActivities}
keyExtractor={item => item.id}
renderItem={({ item }) => (
<View style={styles.report}>
<Text>User: {item.userId}</Text>
<Text>Activity: {item.activity}</Text>
<Text>Date: {item.date}</Text>
</View>
)}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
},
report: {
marginBottom: 20,
},
});
export default UserActivityReportsScreen;
Firebase Firestore Rules
Ensure your Firestore has the appropriate rules to allow reading and writing to the collections used in this application.
Conclusion
This setup provides a complete, functional implementation of the requested admin features, including restaurant management, menu management, order management, and analytics for sales and user activities. Make sure to adjust any paths and dependencies according to your project setup and Firebase configuration.
If you enjoy my content and would like to support my work, you can buy me a coffee. Your support is greatly appreciated!
Disclaimer: This content is generated by AI.
Posted on June 27, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 29, 2024