Point of Sale app
Tags: react, reactjsdevelopment, css, api
Published: 2023-07-03 03:58:57

Hello again. Let's continue on our journey to becoming a web developer. On this post, we will explore React and many of its features and applications.

For this project, I have created a Point of Sale (POS) / e-commerce app. 

In this post, I will demonstrate the various components used in a React e-commerce application. Each component serves a specific purpose and contributes to the overall functionality of the application. I will discuss the useState and useEffect hooks, as well as the React Router, and provide an overview of how I have utilized them within each component.

App Component:
As the entry point for the application, I use the App component. It uses the React Router (BrowserRouter, Routes, and Route) to handle navigation and render different components based on the current URL. Additionally, it includes a NavBar component for navigation and manages the cartItems state using the useState hook.

```
function App() {
  const [cartItems, setCartItems] = useState([]);

  return (
    <Router>
      <div>
        <NavBar />
        <Routes>
          <Route path="/" element={<Home onAddItem={setCartItems} />} />
          <Route
            path="/cart"
            element={<Cart items={cartItems} onDeleteItem={setCartItems} />}
          />
          <Route path="/data" element={<Data />} />
        </Routes>
      </div>
    </Router>
```

NavBar Component:
To display a simple navigation bar with links to the home page and the data page, I utilize the NavBar component. It utilizes the Link component from React Router to enable seamless navigation between different pages.


![NavBar](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c9nzz94mqc4weplezbd7.png)

```
import React from 'react';
import { Link } from 'react-router-dom';

function NavBar() {
  return (
    <nav className='navbar'>
      <Link className='navbar-item' to="/">Home</Link>
      <span className='navbar-item'>|</span>
      <Link className='navbar-item' to="/data">Data</Link>
    </nav>
  );
}

export default NavBar;
```

Home Component:
Representing the home page of the e-commerce application, the Home component is responsible for fetching a list of items from a server using the useEffect hook. It then displays these items as item cards. Within this component, I manage the items and cartItems states using the useState hook. Furthermore, I have integrated a Cart component to showcase the items added to the cart. Additionally, I have implemented functions to handle adding items to the cart, removing items from the cart, and clearing the cart. Finally, after the items are added, increment and decrement buttons are rendered to give additional functionality to the cart, instead of rendering multiple of the same item.


![Home Component](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w1ps3bi6ukuvgby370sc.png)

```
useEffect(() => {
    fetchItems();
  }, []);

  const fetchItems = () => {
    fetch('http://localhost:3000/items')
      .then((response) => response.json())
      .then((data) => setItems(data))
      .catch((error) => console.log('Error fetching items:', error));
  };

  const handleAddToCart = (item) => {
    const existingItem = cartItems.find((cartItem) => cartItem.id === item.id);
    if (existingItem) {
      const updatedItems = cartItems.map((cartItem) =>
        cartItem.id === item.id ? { ...cartItem, quantity: cartItem.quantity + 1 } : cartItem
      );
      setCartItems(updatedItems);
      onAddItem(updatedItems);
    } else {
      setCartItems((prevItems) => [...prevItems, { ...item, quantity: 1 }]);
      onAddItem({ ...item, quantity: 1 });
    }
  };

  const handleDecrementItem = (item) => {
    if (item.quantity > 1) {
      const updatedItems = cartItems.map((cartItem) =>
        cartItem.id === item.id ? { ...cartItem, quantity: cartItem.quantity - 1 } : cartItem
      );
      setCartItems(updatedItems);
      onAddItem(updatedItems);
    } else {
      handleDeleteItem(item);
    }
  };

```


Cart Component:
In the Cart component, my focus is on displaying the items added to the cart. By receiving the items state and various callback functions from the Home component, I can effectively manage the cartItems state using the useState hook. Within this component, I render a list of cart items, providing buttons to increment and decrement item quantities, remove items from the cart, and clear the cart. Finally, I calculate the total price of the items in the cart and display it.


![Cart component](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t17p8p5zexbz1tefi4w1.png)

```

function Cart({ items, onDeleteItem, onClearItems, onAddItem, onDecrementItem }) {
  const handleRemoveItem = (index) => {
    onDeleteItem(index);
  };

  const handleDecrementItem = (item) => {
    onDecrementItem(item);
  }
  const handleClearItems = () => {
    onClearItems();
  };

  const handleAddItem = (item) => {
    onAddItem(item);
  };

  const calculateTotal = () => {
    const totalPrice = items.reduce((total, item) => total + item.price, 0);
    return totalPrice.toFixed(2);
  };

  return (
    <div className="cart-container">
      <div className="cart-items">
        {items.length === 0 ? (
          <p>Your cart is empty. Add items from the Item Selection.</p>
        ) : (
          <ul>
            {items.map((item, index) => (
              <li key={index}>
                <span>{item.name}</span>
                <div>
                  <button className="decrement-item" onClick={() => handleDecrementItem(item)}>
                    <FaMinus />
                  </button>
                  <span>{item.quantity}</span>
                  <button className="increment-item" onClick={() => handleAddItem(item)}>
                    <FaPlus />
                  </button>
                </div>
                <button className="delete-item" onClick={() => handleRemoveItem(index)}>
                  <FaTrash />
                </button>
              </li>
            ))}
          </ul>
        )}
        {items.length > 0 && (
          <button className="clear-button" onClick={handleClearItems}>
            Clear Cart
          </button>
        )}
        <div className="total">
          <span>Total: $ {calculateTotal()}</span>
        </div>
      </div>
    </div>
  );
}

```

Data Component:
The Data component acts as a page where users can both add and view items to the database. To achieve this functionality, I used controlled form inputs through the useState hook and fetch items from a server utilizing the useEffect hook. Additionally, I have incorporated a form to add items, featuring fields for name, type, picture URL, and price. When adding items, I utilize a POST request to the server, subsequently updating the allItems state. Lastly, I present a table of all items fetched from the server, allowing users to delete items individually using the delete button.


![Data component](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j31yuadbs5jrdv2lk4ti.png)

```
useEffect(() => {
    fetchItems();
  }, []);

  const fetchItems = () => {
    fetch('http://localhost:3000/items')
      .then((response) => response.json())
      .then((data) => setAllItems(data))
      .catch((error) => console.log('Error fetching items:', error));
  };

  const handleAddItem = (e) => {
    e.preventDefault();

    const newItem = {
      name: itemName,
      type: itemType,
      image: itemPicture,
      price: parseFloat(itemPrice),
    };

    fetch('http://localhost:3000/items', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(newItem),
    })
      .then((response) => {
        if (!response.ok) {
          throw new Error('Failed to add item');
        }
        return response.json();
      })
      .then((data) => {
        onAddItem(newItem);

        setItemName('');
        setItemType('');
        setItemPicture('');
        setItemPrice('');

        fetchItems();
      })
      .catch((error) => {
        console.log('Error adding item:', error);
      });
  };

  const handleDeleteItem = (id) => {
    fetch(`http://localhost:3000/items/${id}`, {
      method: 'DELETE',
    })
      .then((response) => {
        if (!response.ok) {
          throw new Error('Failed to delete item');
        }
        
        fetchItems();
      })
      .catch((error) => {
        console.log('Error deleting item:', error);
      });
  };

  return (
    <div className="data-section">
      <h2>Add Items</h2>
      <form onSubmit={handleAddItem}>
        <input
          type="text"
          placeholder="Item Name"
          value={itemName}
          onChange={(e) => setItemName(e.target.value)}
          required
        />
        <input
          type="text"
          placeholder="Item Type"
          value={itemType}
          onChange={(e) => setItemType(e.target.value)}
          required
        />
        <input
          type="url"
          placeholder="Item Picture (URL)"
          value={itemPicture}
          onChange={(e) => setItemPicture(e.target.value)}
          required
        />
        <input
          type="number"
          placeholder="Item Price"
          value={itemPrice}
          onChange={(e) => setItemPrice(e.target.value)}
          required
        />
        <button type="submit">Add</button>
      </form>

      <h2>All Items</h2>
      <table className="item-table">
        <thead>
          <tr>
            <th className="category">Item Name</th>
            <th className="category">Item Type</th>
            <th className="category">Price</th>
            <th className="category">Actions</th>
          </tr>
        </thead>
        <tbody>
          {allItems.map((item) => (
            <tr key={item.id}>
              <td>{item.name}</td>
              <td>{item.type}</td>
              <td>{item.price}</td>
              <td>
                <button onClick={() => handleDeleteItem(item.id)}>Delete</button>
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}
```

This application can be used as a Point of Sale(POS) or as an e-commerce site allowing users to order or receive orders. This app can be tailored to many types of businesses such as restaurants, mechanic shops, clothing shops, and online stores.

![Main app](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j8r7clqjft0bri71nih6.png)