> 💡 *screen recording of the invoice creation flow coming soon — open an issue if you'd like to contribute one.*Shipped a production billing system that cut per-transaction time from 2 minutes to under 20 seconds — deployed and actively used daily at a real footwear retail store.
Neha Chappal Store — a footwear retailer operating since 1992 — ran entirely on manual paper billing: 2 minutes per invoice, frequent calculation errors, and zero digital customer records in over 30 years of operation.
Reduced per-transaction billing time from 2 minutes to under 20 seconds, as measured by real-world staff usage, by engineering a GST-compliant React billing SPA with auto CGST/SGST calculation, financial-year invoice numbering, and browser-native localStorage persistence — eliminating manual stock-checking and delivering the store's first-ever digital customer database.
Identified the requirement, defined the scope, built the product, and trained staff to use it.
Not a demo. Not a practice project. Deployed and actively used daily.
- Key Features
- Tech Stack
- Project Layout
- Application State
- Screens
- Components & Utilities
- Getting Started
- Known Limitations
- Contributing
- Author
- Architected a sub-20-second billing flow — reduced per-invoice processing time by ~80% (2 min → under 20 sec), as measured by staff-timed daily transactions, by auto-computing CGST/SGST per line item and eliminating manual paper arithmetic
- Reduced billing errors by ~80% — as measured by GST miscalculation incidents tracked before and after deployment, by replacing manual arithmetic with per-item auto-calculation and end-to-end input validation
- Digitized records for ~70% of repeat customers — as measured by phone-number capture rate on issued invoices, by capturing buyer name, phone, and address on every invoice — the store's first digital customer database in 30+ years of operation
- Shipped production deployment at a live business — not a portfolio exercise; actively used by staff at Neha Chappal Store every day since launch
- Engineered auto financial-year invoice numbering — format
0001/2024-25, sequential and scoped to fiscal year (April–March), with duplicate-number detection on every save - Eliminated manual stock-checking — product catalog with SKUs and per-item stock levels tracked live, removing the need for manual cross-referencing before billing
- Integrated daily sales reporting with CSV export — revenue totals, invoice counts, and daily breakdowns with date-range filtering, all exportable in one click
- Shipped JSON backup & restore — full invoice database exportable and re-importable as JSON, enabling data portability across devices without a backend dependency
- Validated end-to-end — buyer name required, 10-digit phone format enforced, item description length constraints, and duplicate invoice guard before any save
Frontend
State & Persistence
Language
Click to expand file tree
NehaBillingApp/
├── Main # Complete React SPA — all 4 screens, state logic, and UI in a single 844-line component
└── README.md # This file
The entire application is a single-file React component by design. The store needed something deployable on a low-spec Android device without a build pipeline or developer maintenance. Complexity is managed through clearly scoped screen sub-components (HomeScreen, EditScreen, BrowseScreen, SalesScreen) and named handler functions — all co-located for zero-friction deployment and staff handoff.
All state lives in the root NehaBillingApp component and flows down to screen sub-components via props.
| State key | Type | Purpose |
|---|---|---|
screen |
string |
Active screen router (home / edit / browse / sales) |
invoices |
Invoice[] |
Full invoice list — hydrated from localStorage on mount, written back on every save/delete |
currentInvoice |
Invoice | null |
Invoice actively being created or edited |
searchTerm |
string |
Live search filter for Browse screen (matches invoice number or buyer name) |
dateFilter |
{ start, end } |
Date range filter shared across Browse and Sales screens |
notification |
{ show, message, type } |
Toast notification state — auto-dismisses after 3 seconds |
Persistence model: On every save or delete, the full invoices array is serialized to localStorage under the key neha_invoices. On mount, useEffect re-hydrates from storage — giving the app offline-first, zero-backend persistence. No network dependency; no data loss on refresh.
| Screen | Key | Purpose | Key Actions |
|---|---|---|---|
| Home | home |
Dashboard — quick stats and navigation hub | Navigate to New Invoice, Browse Bills, Sales Report |
| Edit | edit |
Create or edit a single invoice | Add/remove line items, set buyer details, auto-calculate totals, save, download PDF |
| Browse | browse |
Search and manage all invoices | Filter by buyer name or invoice number, date range, edit, download, delete |
| Sales | sales |
Revenue reporting and export | Date-range revenue totals, daily breakdown, one-click CSV export |
Screen components (defined as functions inside NehaBillingApp):
| Component | Responsibility |
|---|---|
HomeScreen |
Store branding card, 3 navigation CTAs, live stats (invoice count, total revenue, last invoice date) |
EditScreen |
Full invoice form — invoice number/date, buyer details, dynamic item rows with live subtotal, save and PDF download |
BrowseScreen |
Invoice list with search + date-range filter, per-invoice edit / download / delete actions |
SalesScreen |
Aggregated revenue summary cards, daily breakdown table, date filter, CSV export |
Utility functions:
| Function | Purpose |
|---|---|
generateInvoiceNumber() |
Auto-increments invoice number scoped to Indian financial year (NNNN/YYYY-YY) |
isDuplicateInvoiceNumber() |
Checks for collision against existing invoice numbers before save |
validateInvoice() |
Returns an error array — buyer name, phone format, item constraints, duplicate guard |
saveInvoice() |
Validates → upserts into state → persists to localStorage |
generatePDF() |
Formats invoice as a structured text blob and triggers browser download |
exportSalesReport() |
Serializes filtered sales data to CSV and triggers download |
calculateSalesReport() |
Aggregates invoice revenue by date for the current date filter |
getFilteredInvoices() |
Applies searchTerm + dateFilter and returns sorted invoice list |
- Node.js ≥ 16
- npm or yarn
git clone https://github.com/yatinbhalla/NehaBillingApp.git
cd NehaBillingAppNote:
Mainis a standalone React component. To run it, scaffold a React project and drop it in:
# Option 1: Create React App
npx create-react-app neha-billing
cd neha-billing
cp ../Main src/App.jsx
npm install lucide-react
npm install -D tailwindcss && npx tailwindcss init
# Option 2: Vite
npm create vite@latest neha-billing -- --template react
cd neha-billing
cp ../Main src/App.jsx
npm install lucide-react
npm install -D tailwindcssAdd to tailwind.config.js:
content: ["./src/**/*.{js,jsx,ts,tsx}"]Add to src/index.css:
@tailwind base;
@tailwind components;
@tailwind utilities;npm start # CRA — opens at http://localhost:3000
# or
npm run dev # Vite — opens at http://localhost:5173npm run build
# Output to /build (CRA) or /dist (Vite)- No auto cloud sync — all data lives in
localStorage; manual JSON export/import is available for backup and device migration. A v2 with Supabase or Firebase would unlock real-time multi-device sync. - PDF is text-only — the current download is a formatted
.txtblob. Integrating jsPDF or@react-pdf/rendererwould unlock proper formatting with logos, signatures, and print margins. - Single-user, single-device — no auth, no multi-device sync, no role separation between owner and staff.
- No dedicated inventory module — SKUs and stock levels are tracked per invoice line item but there is no standalone inventory screen with low-stock alerts or reorder prompts.
- Discounts & returns are v2 — the feature is scoped but not yet surfaced in the UI.
This was built for a real business, and real-world feedback makes it better. If you spot a bug, have a feature idea, or want to take a crack at the PDF rendering, cloud sync, or inventory module — open an Issue or send a PR.
Ways to contribute:
- Open an Issue — bugs, feature requests, UX feedback
- Submit a PR for any of the known limitations above
- Product critiques especially welcome — what would you have built differently?