Full-Stack Web React · PHP · MariaDB Fall 2024 CIS 435

The Donut
Shop

Customer storefront + admin panel

A full-stack web app with two separate views — a customer-facing storefront that fetches and renders donuts from a PHP REST API, and an admin panel for managing the menu with full CRUD operations.

The Donut Shop storefront
01
Customer View
React components + API-driven rendering

The storefront is built as a React app that fetches the donut list from the PHP API on mount via useEffect. Each donut is rendered by a Donut component that receives name, description, and price as props — the component defines the card structure once and the data drives how many times it renders.

Adding a new donut to the database automatically adds a new card to the page without any code changes — the component just maps over whatever the API returns.

Component composition
App owns the data fetching and state. Donut is a pure presentational component — it receives props and renders, with no knowledge of where the data comes from.
JSX Donut.jsx — presentational component
export function Donut({ name, description, price }) {
  return (
    <div className="DonutPanel">
      <h1>{name}</h1>
      <p className="donutdescription">
        {description}
      </p>
      <h2>{price}</h2>
    </div>
  );
}

// In App — data drives rendering, no manual card creation
{donuts.map(donut =>
  <Donut
    name={donut.Name}
    description={donut.Description}
    price={donut.Price}
  />
)}
02
Admin Panel
Controlled components + optimistic state updates
Donut Shop admin panel
Admin panel — donut selected, fields populated

The admin panel uses controlled inputs — each form field is bound to a useState hook and updates on every keystroke via onChange. React owns the field values, so reading them for an API call is just reading state rather than querying the DOM.

Selecting a donut from the dropdown populates all three fields immediately from the donuts array already in state — no extra fetch needed. Update and Delete buttons are disabled until a donut is selected, derived directly from whether selectedId is empty.

Optimistic state updates
After a successful add, update, or delete the local donuts array is updated directly — the page reflects the change immediately without re-fetching from the API.
03
PHP API
REST routing + prepared statements

A single index.php file handles all four HTTP methods, routing on $_SERVER['REQUEST_METHOD'] to the appropriate handler. All database queries use prepared statements throughout.

Method Operation Details
GET Fetch all donuts Returns full Donuts array — used by both storefront on mount and admin dropdown
POST Add donut Inserts new row, returns generated ID so client can update state without re-fetching
PUT Update donut Checks existence before updating — returns 400 if ID not found
DELETE Delete donut Checks existence before deleting — returns 400 if ID not found
← Previous Game Shop Next → Traffic Intersection