Sławomir Kwiatkowski

by: Sławomir Kwiatkowski

2025/01/05

Creating and editing a warehouse - React frontend for DRF API

Content description:
In this article, I'll show you how to create a new warehouse and edit an existing one using a front-end built in React (the back-end API was built in DRF).

First, I add the components of the pages responsible for creating a new warehouse and editing an existing one to the router in the main App.jsx component.

     
import WarehouseAddPage from "./pages/WarehouseAddPage"
import WarehouseEditPage from "./pages/WarehouseEditPage"
import { warehouseLoader } from "./components/Warehouse"

const router = createBrowserRouter(
  createRoutesFromElements(
    <Route path="/" element={<MainLayout/>}>
      <Route index element={<MainPage/>} />
      <Route path="/login/" element={<LoginPage/>} />
      <Route path="/logout" element={<LogoutPage/>} />
      <Route path="/register" element={<RegisterPage/>} />
      <Route path="/warehouses" element={<WarehousesPage/>} />
      <Route path="/warehouses/:id" element={<WarehousePage/>} loader={warehouseLoader} />
      <Route path="/add-warehouse" element={<WarehouseAddPage/>} />
      <Route path="/edit-warehouse/:id" element={<WarehouseEditPage/>} loader={warehouseLoader} />
      <Route path="*" element={<ErrorPage/>} />
    </Route>
  )
)

function App() {
  return (
    <RouterProvider router={router} /> 
  )
}

export default App

The WarehouseAddPage component calls the form component and additionally the legend variable is sent as a parameter.

     
import WarehouseForm from "../components/WarehouseForm"

function WarehouseAddPage() {
  return (
    
  )
}

export default WarehouseAddPage

The WarehouseEditPage component works in a similar way and additionally sends the warehouse id and data of that warehouse to the form component.

     
import WarehouseForm from "../components/WarehouseForm"
import { useParams, useLoaderData } from "react-router-dom"

function WarehouseEditPage() {
  const {id} = useParams() 
  const warehouse = useLoaderData()
  return (
    <>
        <WarehouseForm legend="Edit Warehouse" id={id} warehouse={warehouse}/>
    </>
  )
}

export default WarehouseEditPage

The form component is common to both page components. In case of editing, the form displays already existing warehouse data.

     
import { useState } from "react"
import { useNavigate, useLocation } from "react-router-dom"


function WarehouseForm({legend, id=null, warehouse=null}) {
    const navigate = useNavigate()
    const location = useLocation()
    const [warehouseName, setWarehouseName] = useState(warehouse? warehouse.warehouse_name: "")
    const [warehouseInfo, setWarehouseInfo] = useState(warehouse? warehouse.warehouse_info: "")

    const handleForm = async (e) => {
      e.preventDefault()
      try {
        const token = localStorage.getItem('accessToken')
        let res;
        if (id === null) {
          res = await fetch('/api/warehouses/', {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json',
              'Authorization': `Bearer ${token}`
            },
            body: JSON.stringify({"warehouse_name":warehouseName, "warehouse_info": warehouseInfo})
          })
        } else {
          res = await fetch(`/api/warehouses/${id}/`, {
            method: 'PUT',
            headers: {
              'Content-Type': 'application/json',
              'Authorization': `Bearer ${token}`
            },
            body: JSON.stringify({"warehouse_name":warehouseName, "warehouse_info": warehouseInfo})
          })
        }
        if (res.status==401) {
          const token = localStorage.getItem('refreshToken')
          const res = await fetch('/api/token/refresh/', {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json',
            },
            body: JSON.stringify({"refresh": token})
          })
          if (res.ok) {
            const data = await res.json()
            localStorage.setItem("accessToken", data["access"])
            handleForm()
            
          } else {
            navigate('/login', {state: {"from": location.pathname}})
          }
        }
        navigate(`/warehouses/`)
      } catch (err) {
        console.error(err)
      }
    }

  return (
    <form onSubmit={handleForm}>
      <legend>{legend}</legend>  
      <div>
        <label>Warehouse name:</label>
        <input
            type="text"
            value={warehouseName}
            onChange={(e) => setWarehouseName(e.target.value)}
            required
          />
      </div>
      <div>
        <label>Warehouse info:</label>
        <input
            type="text"
            value={warehouseInfo}
            onChange={(e) => setWarehouseInfo(e.target.value)}
            required
          />
      </div>
      <button type="submit">Submit</button>
      <button type="button" onClick={() =>navigate('/warehouses')}>Cancel</button>
    </form>
  )
}

export default WarehouseForm