How to develop comprehensive food delivery React Native mobile app?

nadim_ch0wdhury

Nadim Chowdhury

Posted on June 27, 2024

How to develop comprehensive food delivery React Native mobile app?

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

  1. User Authentication and Profile Management

    • Sign Up / Sign In (email, phone, social media)
    • Profile editing
    • Password recovery
  2. Home Screen / Dashboard

    • List of nearby restaurants
    • Search bar for restaurants and food items
    • Categories (e.g., pizza, sushi, burgers)
  3. Restaurant Details

    • Restaurant information (name, rating, address)
    • Menu with food items
    • Reviews and ratings
    • Operating hours
  4. Food Details

    • Food item description
    • Pricing
    • Add-ons / Customizations
    • Add to cart option
  5. Cart and Checkout

    • Cart summary
    • Apply coupons / discounts
    • Delivery address selection
    • Payment options (credit card, PayPal, etc.)
    • Order summary and confirmation
  6. Order Tracking

    • Real-time order status updates
    • Google Maps integration for delivery tracking
    • Estimated delivery time
  7. Rider Interaction

    • Real-time rider location tracking on map
    • Messaging with the rider
    • Call rider option
  8. Order History

    • List of past orders
    • Reorder option
    • Order details
  9. Notifications

    • Push notifications for order status updates
    • Promotions and offers
  10. Settings

    • Notification preferences
    • Payment methods management
    • Address book
    • Privacy settings
  11. 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
Enter fullscreen mode Exit fullscreen mode

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 };
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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} />
Enter fullscreen mode Exit fullscreen mode

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:

  1. List of Nearby Restaurants
  2. Search Bar for Restaurants and Food Items
  3. 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
Enter fullscreen mode Exit fullscreen mode

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
];
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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));
};
Enter fullscreen mode Exit fullscreen mode
// SignUpScreen.js
const handleSignUp = () => {
  auth().createUserWithEmailAndPassword(email, password)
    .then(() => {
      navigation.navigate('Home');
    })
    .catch(error => setError(error.message));
};
Enter fullscreen mode Exit fullscreen mode

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:

  1. Restaurant Information (name, rating, address)
  2. Menu with Food Items
  3. Reviews and Ratings
  4. 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
  ],
};
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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:

  1. Food Item Description
  2. Pricing
  3. Add-ons / Customizations
  4. 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' },
  ],
};
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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:

  1. Cart Summary
  2. Apply Coupons / Discounts
  3. Delivery Address Selection
  4. Payment Options (Credit Card, PayPal, etc.)
  5. 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' },
];
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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.

  1. 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
Enter fullscreen mode Exit fullscreen mode
  1. 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
Enter fullscreen mode Exit fullscreen mode
  1. 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;
Enter fullscreen mode Exit fullscreen mode
  1. Set up Google Maps:
    Follow the React Native Maps setup guide to configure Google Maps for your app.

  2. 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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode
  1. 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
         }
       }
     }
   }
Enter fullscreen mode Exit fullscreen mode
  1. Running the app: Finally, run your app using:
   npx react-native run-android
   # or
   npx react-native run-ios
Enter fullscreen mode Exit fullscreen mode

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.

  1. 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
Enter fullscreen mode Exit fullscreen mode
  1. Configure Firebase for messaging:
    Ensure that Firebase Firestore is set up for storing messages.

  2. 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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode
  1. 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);
     });
   };
Enter fullscreen mode Exit fullscreen mode
  1. 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"
             }
           }
         }
       }
     }
   }
Enter fullscreen mode Exit fullscreen mode

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:

  1. 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
Enter fullscreen mode Exit fullscreen mode
  1. Configure Firebase for notifications:
    Set up Firebase Cloud Messaging in your project. Follow the Firebase setup guide for detailed steps.

  2. 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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode
  1. 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": {
         // ...
       }
     }
   }
Enter fullscreen mode Exit fullscreen mode
  1. 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();
Enter fullscreen mode Exit fullscreen mode
  1. 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);
       });
     }
   });
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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,
    });
  });
};
Enter fullscreen mode Exit fullscreen mode

App.js (add to the top of the file):

import { requestUserPermission, notificationListener } from './firebase-messaging';

React.useEffect(() => {
  requestUserPermission();
  notificationListener();
}, []);
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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.

💖 💪 🙅 🚩
nadim_ch0wdhury
Nadim Chowdhury

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