A real-time order management dashboard for venue operators, built with React, TypeScript, and Tailwind CSS v4.
- Real-time Order Updates — New orders appear automatically without page refresh
- Optimistic UI Updates — Instant feedback when advancing order status
- Smart Status Filtering — Filter orders by status with live count badges
- Urgency Indicators — Visual warnings for orders waiting 8+ minutes
- Responsive Design — Works seamlessly on desktop, tablet, and mobile
- Error Handling — Automatic rollback when updates fail (15% simulated failure rate)
- Performance Optimized — React Query caching, deduplication, and background refetches
- Dark Mode UI — Modern dark theme with smooth animations
Get up and running in 3 simple steps:
# 1. Install dependencies
npm install
# 2. Start development server
npm run dev
# 3. Open http://localhost:5173 in your browserBefore you begin, ensure you have the following installed:
- Node.js (v18 or higher) — Download here
- npm (v9 or higher) — Comes with Node.js
- Git — Download here
Check your versions:
node --version # Should be v18+
npm --version # Should be v9+git clone <your-repo-url>
cd tapin-order-dashboardnpm installThis will install all required packages including:
- React 19.2.4
- TypeScript 6.0.2
- Tailwind CSS v4.0.0
- TanStack Query 5.99.0
- Vite 8.0.4
npm run devThe app will be available at http://localhost:5173
| Command | Description |
|---|---|
npm run dev |
Start development server with hot reload |
npm run build |
Build for production (outputs to dist/) |
npm run preview |
Preview production build locally |
npm run lint |
Run ESLint to check code quality |
Create a production-ready build:
npm run buildThe optimized files will be in the dist/ folder. You can preview the build:
npm run previewDeploy the dist/ folder to any static hosting service:
- Vercel
- Netlify
- AWS S3 + CloudFront
- GitHub Pages
- React 19 — Latest React with concurrent features
- TypeScript 6 — Type-safe development
- Vite 8 — Lightning-fast build tool with HMR
- Tailwind CSS v4 — Utility-first CSS with new CSS-based configuration
- @tailwindcss/vite — Native Vite integration for Tailwind v4
- Custom Design Tokens — Semantic theme values extracted to CSS variables
- TanStack Query v5 — Server state management with caching
- React Hooks — Local UI state with
useState
- ESLint — Code linting with React-specific rules
- TypeScript Strict Mode — Enhanced type checking
| Concern | Solution |
|---|---|
| Server / async state | TanStack Query (useQuery, useMutation) |
| UI filter state | useState in OrderDashboard |
| Global state | None — not needed for this scope |
TanStack Query was chosen over a manual useEffect + useState approach
because it gives us caching, deduplication, background refetches, and
cancelQueries for free — all of which the optimistic update pattern depends on.
useOrders implements the standard TanStack Query optimistic pattern:
onMutate— cancel outgoing refetches → snapshot current cache → apply the status change immediately so the UI responds without a network round-trip.onError— restore the snapshot, rolling back the card to its previous state. A 15 % artificial failure rate inordersApi.tslets you see this in action — just click "Advance" a few times.onSettled— always invalidate so the cache reconciles with the server.
useOrdersRealtime simulates an SSE connection via setInterval. In
production the hook body would be replaced with:
const sse = new EventSource('/api/orders/stream');
sse.addEventListener('order:new', (e) => {
const order: Order = JSON.parse(e.data);
queryClient.setQueriesData<OrdersResponse>(
{ queryKey: ['orders'] },
(old) => old ? { ...old, orders: [order, ...old.orders], total: old.total + 1 } : old,
);
});
sse.addEventListener('order:updated', (e) => {
const updated: Order = JSON.parse(e.data);
queryClient.setQueriesData<OrdersResponse>(
{ queryKey: ['orders'] },
(old) => old
? { ...old, orders: old.orders.map((o) => (o.id === updated.id ? updated : o)) }
: old,
);
});
return () => sse.close();The push handler writes directly into the React Query cache, so every subscribed component re-renders without a network round-trip for the client.
- No pagination UI — the API layer supports
page, but the dashboard shows the first page only. With more time I'd add an infinite-scroll or numbered paginator. - Mock failure rate —
FAILURE_RATE = 0.15inordersApi.tsis on by default to demonstrate rollback. Set it to0to remove random failures. - Single mutation slot — one
useMutationinstance means clicking a second card while the first is in-flight will show the loading state on the second card only (the first finishes in the background). AMap<id, status>approach would handle concurrent mutations more precisely. - No toast library — errors surface as an inline banner above the grid.
In production I'd use
sonneror similar for non-blocking toasts.
- Pagination or virtual scrolling (
@tanstack/react-virtual) for 500+ orders - Vitest + React Testing Library tests for
useOrders(optimistic flow, rollback, empty/error states) - A real SSE endpoint (Node/Express) replacing the polling simulation
- WebSocket fallback detection
- Keyboard-accessible status advancement
React.lazy+ route-level code splitting for a multi-page app
This project uses Tailwind CSS v4, which introduced significant changes from v3:
-
CSS-based Configuration — No more
tailwind.config.jsJavaScript file- Configuration now lives in
src/index.cssusing@themedirective - Theme values are CSS custom properties
- Configuration now lives in
-
Vite Plugin — Uses
@tailwindcss/viteinstead of PostCSS- Removed
postcss.config.jsandautoprefixer - Faster builds with native Vite integration
- Removed
-
Arbitrary Values Extraction — All square bracket notation moved to theme
text-[10px]→text-badgetext-[11px]→text-logoborder-l-[3px]→border-l-accent- Custom opacity values:
3%,6%,7%,8%
All design tokens are defined in src/index.css:
@theme {
/* Font Sizes */
--font-size-badge: 10px;
--font-size-logo: 11px;
/* Border Widths */
--border-width-accent: 3px;
/* Custom Opacities */
--opacity-3: 0.03;
--opacity-6: 0.06;
--opacity-7: 0.07;
--opacity-8: 0.08;
/* Shadows & Animations */
--shadow-card: 0 1px 2px rgba(0,0,0,0.4), 0 0 0 1px rgba(255,255,255,0.04);
--shadow-card-hover: 0 8px 24px rgba(0,0,0,0.4), 0 0 0 1px rgba(255,255,255,0.06);
--animate-fade-in: fade-in 0.2s ease-out;
}- Better IDE Support — CSS variables provide better autocomplete
- Native Browser Integration — No build step needed for CSS variables
- Type-safe Theme — Semantic names instead of magic numbers
- Easier Maintenance — Update once, apply everywhere
-
Run dev server with hot reload:
npm run dev
-
Edit components in
src/features/orders/components/- Changes appear instantly thanks to Vite HMR
-
Check for errors:
npm run lint npm run build # TypeScript type checking
The app uses in-memory mock data (src/lib/mockData.ts). To modify:
- Change failure rate: Edit
FAILURE_RATEinsrc/features/orders/services/ordersApi.ts - Add menu items: Update
MENU_ITEMSarray insrc/lib/mockData.ts - Adjust timing: Modify
LATENCY_MSfor API delay simulation
- Update
OrderStatustype insrc/features/orders/types.ts - Add mapping in
STATUS_LABELS,STATUS_BORDER,STATUS_GLOW - Update
STATUS_FLOWif status should be advanceable - Add filter button config in
StatusFilter.tsx
If port 5173 is occupied:
# Kill the process using the port
kill -9 $(lsof -ti:5173)
# Or specify a different port
npm run dev -- --port 3000If you encounter build errors after pulling changes:
# Clear cache and reinstall
rm -rf node_modules package-lock.json dist
npm install
npm run build- Ensure
src/index.cssis imported insrc/main.tsx - Check that
@import "tailwindcss"is at the top ofindex.css - Verify
@tailwindcss/viteplugin is invite.config.ts - Restart dev server
Check your Node.js version:
node --version # Should be v18+Update TypeScript if needed:
npm install -D typescript@latestContributions are welcome! Here's how to get started:
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Make your changes and test thoroughly
- Commit your changes:
git commit -m 'feat: add amazing feature' - Push to the branch:
git push origin feature/amazing-feature - Open a Pull Request
We follow Conventional Commits:
feat:— New featurefix:— Bug fixrefactor:— Code refactoringdocs:— Documentation changesstyle:— Formatting, missing semicolons, etc.test:— Adding testschore:— Maintenance tasks
This project is open source and available under the MIT License.
Built with:
If you have any questions or run into issues:
- Check the Troubleshooting section
- Search existing issues on GitHub
- Open a new issue with a detailed description
Happy coding! 🚀
