Skip to content

About

React frontend for Brew Inventory, a full-stack inventory management app for a specialty tea and coffee store.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Brew Inventory — Client

React frontend for Brew Inventory, a full-stack inventory management app for a specialty tea and coffee store.

Live: brew-inventory.pages.dev

Note: The backend is hosted on Render's free tier, which spins down after inactivity. The first request after idle may take 30–50 seconds while the server wakes up. Subsequent requests are fast.

Related repository

brew-inventory-server — Express/PostgreSQL API

Features

  • Browse inventory by category or view all products at once
  • Filter products by category, availability and product attributes
  • Search products by name
  • Add, edit, and delete products with category-specific attribute fields
  • Availability status derived from stock quantity (in stock / low stock / out of stock)
  • Fully responsive: mobile bottom navigation, desktop top navigation
  • Accessible markup throughout

Admin access

To edit or delete products, enter the admin password when prompted:

Password: brew123

Screenshots

Categories

Products

Product detail

Tech stack

  • React with Vite
  • React Router for client-side routing
  • Vitest and React Testing Library for unit and integration testing
  • use-debounce for debounced search input
  • PropTypes for runtime prop validation
  • ESLint for linting

Views

Route Component Description
/ Categories Grid of all categories with product counts
/products Products Full product list with search and filter
/categories/:id Products Products filtered by category
/products/:id Product Single product detail with attributes
/products/new AddProduct Add a new product
/products/:id/edit EditProduct Edit an existing product

Project structure

└── 📁brew-inventory-client
    └── 📁public
        ├── apple-touch-icon.png
        ├── favicon-96x96.png
        ├── favicon.ico
        ├── favicon.svg
        ├── icons.svg
        ├── robots.txt
        ├── site.webmanifest
        ├── web-app-manifest-192x192.png
        ├── web-app-manifest-512x512.png
    └── 📁screenshots
        ├── categories-desktop.png
        ├── categories-mobile.png
        ├── product-detail-desktop.png
        ├── product-detail-mobile.png
        ├── products-desktop.png
        ├── products-mobile.png
    └── 📁src
        └── 📁assets
            ├── logo.png
        └── 📁components
            └── 📁BottomNav
                ├── BottomNav.jsx
                ├── BottomNav.module.css
                ├── BottomNav.test.jsx
            └── 📁BottomNavLink
                ├── BottomNavLink.jsx
                ├── BottomNavLink.module.css
                ├── BottomNavLink.test.jsx
            └── 📁Breadcrumb
                ├── Breadcrumb.jsx
                ├── Breadcrumb.module.css
                ├── Breadcrumb.test.jsx
            └── 📁FieldError
                ├── FieldError.jsx
                ├── FieldError.module.css
                ├── FieldError.test.jsx
            └── 📁FormError
                ├── FormError.jsx
                ├── FormError.module.css
                ├── FormError.test.jsx
            └── 📁Header
                ├── Header.jsx
                ├── Header.module.css
                ├── Header.test.jsx
            └── 📁NavLink
                ├── NavLink.jsx
                ├── NavLink.module.css
                ├── NavLink.test.jsx
            └── 📁ProductForm
                ├── ProductForm.jsx
                ├── ProductForm.module.css
                ├── ProductForm.test.jsx
        └── 📁hooks
            ├── useAvailability.jsx
            ├── useAvailability.test.js
            ├── useIsWide.js
            ├── useIsWide.test.js
            ├── useSections.js
            ├── useSections.test.js
        └── 📁pages
            └── 📁addProduct
                └── 📁components
                    └── 📁AddProduct
                        ├── AddProduct.jsx
                        ├── AddProduct.test.jsx
            └── 📁categories
                └── 📁components
                    └── 📁Categories
                        ├── Categories.jsx
                        ├── Categories.module.css
                        ├── Categories.test.jsx
                    └── 📁Category
                        ├── Category.jsx
                        ├── Category.module.css
                        ├── Category.test.jsx
                    └── 📁SkeletonCategories
                        ├── SkeletonCategories.jsx
                        ├── SkeletonCategories.module.css
            └── 📁editProduct
                └── 📁components
                    └── 📁EditProduct
                        ├── EditProduct.jsx
                        ├── EditProduct.test.jsx
                    └── 📁SkeletonEditProduct
                        ├── SkeletonEditProduct.jsx
                        ├── SkeletonEditProduct.module.css
            └── 📁error
                └── 📁components
                    └── 📁ErrorState
                        ├── ErrorState.jsx
                        ├── ErrorState.module.css
                        ├── ErrorState.test.jsx
            └── 📁productDetail
                └── 📁components
                    └── 📁DeleteModal
                        ├── DeleteModal.jsx
                        ├── DeleteModal.module.css
                        ├── DeleteModal.test.jsx
                    └── 📁ProductDetail
                        ├── ProductDetail.jsx
                        ├── ProductDetail.module.css
                        ├── ProductDetail.test.jsx
                    └── 📁SkeletonProductDetail
                        ├── SkeletonProductDetail.jsx
                        ├── SkeletonProductDetail.module.css
            └── 📁products
                └── 📁components
                    └── 📁FilterBottomSheet
                        ├── FilterBottomSheet.jsx
                        ├── FilterBottomSheet.module.css
                        ├── FilterBottomSheet.test.jsx
                    └── 📁FilterDropdown
                        ├── FilterDropdown.jsx
                        ├── FilterDropdown.module.css
                        ├── FilterDropdown.test.jsx
                    └── 📁FilterEmptyState
                        ├── FilterEmptyState.jsx
                        ├── FilterEmptyState.module.css
                    └── 📁FilterSection
                        ├── FilterSection.jsx
                        ├── FilterSection.module.css
                        ├── FilterSection.test.jsx
                    └── 📁Product
                        ├── Product.jsx
                        ├── Product.module.css
                        ├── Product.test.jsx
                    └── 📁ProductEmptyState
                        ├── ProductEmptyState.jsx
                        ├── ProductEmptyState.module.css
                        ├── ProductEmptyState.test.jsx
                    └── 📁ProductRow
                        ├── ProductRow.jsx
                        ├── ProductRow.module.css
                        ├── ProductRow.test.jsx
                    └── 📁Products
                        ├── Products.jsx
                        ├── Products.module.css
                        ├── Products.test.jsx
                    └── 📁ProductsTable
                        ├── ProductsTable.jsx
                        ├── ProductsTable.module.css
                        ├── ProductsTable.test.jsx
                    └── 📁SearchBar
                        ├── SearchBar.jsx
                        ├── SearchBar.module.css
                        ├── SearchBar.test.jsx
                    └── 📁SheetChip
                        ├── SheetChip.jsx
                        ├── SheetChip.module.css
                        ├── SheetChip.test.jsx
                    └── 📁SkeletonProducts
                        ├── SkeletonProducts.jsx
                        ├── SkeletonProducts.module.css
        └── 📁router
            ├── routes.jsx
        └── 📁styles
            ├── App.css
            ├── normalize.css
        └── 📁tests
            └── 📁integration
                ├── addProductForm.test.jsx
                ├── filterProducts.test.jsx
                ├── searchProducts.test.jsx
        └── 📁utils
            ├── filterUtils.js
            ├── filterUtils.test.js
            ├── utils.js
            ├── utils.test.js
        ├── App.jsx
        ├── constants.js
        ├── contexts.js
        ├── main.jsx
    ├── .gitignore
    ├── eslint.config.js
    ├── index.html
    ├── package-lock.json
    ├── package.json
    ├── README.md
    ├── test-setup.js
    └── vite.config.js

Getting started

Prerequisites

Setup

  1. Clone the repository
git clone https://github.com/Maddily/brew-inventory-client.git
cd brew-inventory-client
  1. Install dependencies
npm install
  1. Start the development server
npm run dev

The app will be running at http://localhost:5173.

Make sure the API server is running at http://localhost:3000 before using the app.

Deployment

Hosted on Cloudflare Pages. VITE_API_URL is set as a build-time environment variable pointing to the deployed brew-inventory-server API on Render.

Running tests

Unit tests:

npm test

Integration tests:

npm run test:integration

Unit tests cover components, hooks, and utility functions in isolation using Vitest and React Testing Library, with network requests mocked. Integration tests exercise real component trees together — filling out the actual product form, selecting real filter chips, and typing in the real search bar — to verify the seams between components work end to end, not just each piece in isolation.

About

React frontend for Brew Inventory, a full-stack inventory management app for a specialty tea and coffee store.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages