Live Demo: View Application
This project is a refactored React application designed with long-term maintainability, scalability, and robustness as first-class goals. The main objective of this refactor is to transform the original codebase into a clean, well-structured, and future-proof architecture, suitable for continuous expansion over many years.
All architectural decisions prioritize clarity, separation of concerns, and predictable data flow. The application is built using React + TypeScript + Vite, with a feature-oriented structure and modern best practices.
- React Tasks Application
- React 19 - UI library
- TypeScript - Type safety
- Vite - Build tool and dev server
- Zustand - State management
- Zod - Runtime schema validation
- Axios - HTTP client
- React Router DOM - Routing
- Tailwind CSS - Styling
- Radix UI - Accessible UI primitives (shadcn-inspired components)
- Lucide React - Icon library
- Vitest - Unit testing framework
- Node.js (v18 or higher recommended)
- npm or yarn package manager
-
Clone the repository
git clone <repository-url> cd ReactTaskTS-cuonghv91
-
Install dependencies
npm install
-
Start the development server
npm run dev
-
Open your browser Navigate to
http://localhost:5173(or the port shown in your terminal)
npm run dev- Start development servernpm run build- Build for productionnpm run preview- Preview production build locallynpm run lint- Run ESLintnpm run test- Run unit tests with Vitest
src/
├─ components/
│ ├─ ui/
│ │ └─ Reusable, framework-agnostic UI components
│ └─ error-boundary.tsx
│ └─ React Error Boundary for graceful error handling
│
├─ features/
│ ├─ product/
│ │ ├─ api.ts - Product API interface
│ │ ├─ hook.ts - Zustand store with localStorage persistence
│ │ ├─ schema.ts - Zod schemas for runtime validation
│ │ ├─ type-guards.ts - Type guards with Zod validation
│ │ ├─ factory.ts - Centralized product construction
│ │ ├─ validation.ts - Form validation logic
│ │ └─ statistics.ts - Business logic for statistics
│ └─ theme/
│ └─ Application theming and UI state
│
├─ https/
│ └─ axios.ts
│ └─ Centralized Axios instance with global configuration
│
├─ lib/
│ ├─ constant.ts
│ ├─ helpers.ts
│ └─ utils.ts
│ └─ Shared utilities and constants
│
├─ pages/
│ ├─ not-found/
│ │ └─ 404 handling (components, hooks, types isolated)
│ │
│ ├─ product/
│ │ ├─ components/
│ │ │ ├─ common-fields.tsx (Shared form fields)
│ │ │ ├─ product-form.tsx
│ │ │ ├─ product-list.tsx
│ │ │ ├─ product-card.tsx
│ │ │ └─ Type-specific field components
│ │ ├─ registry/
│ │ │ └─ display.registry.tsx (Registry pattern for product display)
│ │ ├─ types/
│ │ │ └─ product.types.ts
│ │ └─ index.tsx
│ │ └─ Product listing and creation page
│ │
│ └─ product-detail/
│ └─ Product detail page
│
├─ routes/
│ ├─ layouts/
│ │ └─ Application layout definitions
│ └─ index.tsx
│ └─ Centralized route configuration
│
├─ App.tsx
│ └─ Root application component
│
├─ providers.tsx
│ └─ Global providers (state, theme, etc.)
│
├─ main.tsx
│ └─ Application bootstrap
│
└─ global.css
└─ Global styles
Instead of grouping code by technical type only (components, hooks, services), the application groups logic by business domain:
features/productfeatures/theme
This approach:
- Scales naturally as the app grows
- Keeps related logic close together
- Prevents massive shared folders over time
-
components/ui → Pure, reusable UI primitives with no business logic
-
components/common-fields.tsx → Shared form fields (name, price, brand) to reduce duplication (DRY principle)
-
features/_ and pages/_ → Own all domain-specific behavior
This ensures UI components remain stable even as business rules evolve.
src/https/axios.ts
- Single Axios instance
- Global configuration
- Easy to add: interceptors, authentication, logging, retries, error normalization
This avoids scattered API logic and makes backend changes safer.
src/routes/
- Routes are declared in one place
- Layouts are reusable and composable
- Easy to introduce: protected routes, role-based access, lazy loading
Zustand is used intentionally for:
- Simplicity
- Explicit state ownership
- Minimal boilerplate
State logic is colocated with the feature it belongs to.
src/pages/product/registry/display.registry.tsx
The application uses a registry pattern for product display logic:
- OCP Compliant: New product types can be added without modifying existing code
- Centralized Display Logic: Product subtitles, size displays, and additional info are managed through a registry
- Type-Safe: Full TypeScript support with discriminated unions
This pattern replaces switch statements and enables easy extension of product types.
src/features/product/schema.ts
Zod schemas provide runtime type safety at all system boundaries:
- Schema Validation: All external data (localStorage, JSON imports) is validated
- Type Guards: Type guards use Zod for actual validation, not just type assertions
- Centralized Factory: Product construction through factory pattern with validation
- Form Validation: Centralized validation logic with detailed error messages
This ensures invalid data cannot propagate through the application.
src/components/error-boundary.tsx
React Error Boundaries are implemented throughout the application:
- Graceful Degradation: Errors in components don't crash the entire app
- User-Friendly Messages: Clear error messages with retry functionality
- Development Support: Detailed error information in development mode
Error boundaries wrap critical sections like forms, lists, and detail pages.
- Feature-first architecture for scalability
- Clear separation of concerns
- Explicit ownership of logic (UI vs domain vs infrastructure)
- Type safety end-to-end (no
anyorunknowntypes) - Minimal coupling, high cohesion
- DRY principle (common fields extracted to shared components)
- Registry pattern for extensibility (OCP compliance)
- Error boundaries for robust error handling
- Easy onboarding for new developers
This architecture supports:
- Adding new features without touching existing ones
- Adding new product types through registry pattern (no code modifications needed)
- Refactoring safely with strong TypeScript guarantees
- Graceful error handling that doesn't break user experience
- Onboarding new developers quickly
- Migrating to SSR or backend integration later
- Replacing UI libraries without rewriting business logic
- Shared components reduce duplication and maintenance burden