Frontend
Stack
- React
19.2.7 - TypeScript
6.0.2 - Vite
8.1.1 - React Router DOM
7.18.1 - Recharts
3.10.1 - Stripe React SDK
Application structure
Key folders:
src/api- typed API wrappers overapiClientsrc/auth- auth provider, route guards, JWT/token helperssrc/components- reusable UI and layout piecessrc/features- cart, analytics, orders, profilesrc/layouts- auth/admin/customer shellssrc/pages- route-level pagessrc/theme- light/dark/system theme state
Routes
Customer routes
/dashboard/books/books/:id/cart/checkout/checkout/payment/:paymentId/payment-success/checkout/payment/:paymentId/failed/orders/orders/:orderId/profile/profile/edit
Admin routes
/admin/dashboard/admin/analytics/admin/books/admin/books/new/admin/books/:id/edit/admin/authors/admin/publishers/admin/categories/admin/users
API integration
apiClient uses VITE_API_BASE_URL and defaults to http://localhost:8080.
It:
- adds the bearer token when available
- retries once on
401by calling/auth/refresh - clears the session if refresh fails
Checkout flow
- Cart is stored in localStorage under
bookstore.cart - Quantity is clamped to
1..2000 - Checkout page calls
POST /api/payments/checkout - Payment page loads Stripe Elements with
VITE_STRIPE_PUBLISHABLE_KEY - Payment success page polls
GET /api/orders/payment/{paymentId}until the order appears
Environment variables
frontend/.env.example:
VITE_API_BASE_URL=http://localhost:8080
VITE_STRIPE_PUBLISHABLE_KEY=pk_test_...
VITE_STRIPE_PUBLISHABLE_KEY is required for the payment page. Without it, Stripe Elements will not mount.
Auth flow
- Login stores access and refresh tokens in
localStorage - A stable
deviceIdis generated and sent on login - On app load,
AuthProviderrestores the session from JWT or refresh token apiClientretries once on401viaPOST /auth/refresh- Register completes with
POST /auth/registerand redirects to login without auto-login
UI-specific behaviors currently in code
- Account dropdown with profile/order links and theme preference
- Customer-side labels were simplified to avoid “Customer Portal” branding
- Admin user management blocks self-delete in the UI
- Cart quantity limit warns inline and via toast when over
2000
Legacy / unused files
These files exist but are not wired into App.tsx:
src/pages/BookListPage.tsxsrc/pages/BookDetailsPage.tsxsrc/pages/CreateBookPage.tsxsrc/pages/EditBookPage.tsxsrc/layouts/AppShell.tsx
The active shells are CustomerShell, AdminShell, and AuthLayout.