Skip to content

Architecture

Source: pharmanet-admin/src/

Project Structure

src/
├── main.jsx                     # Entry point
├── App.jsx                      # Provider wrappers (Redux, Router, Theme)
├── routes.jsx                   # React Router v6 config
├── assets/styles/               # Global CSS + MUI theme (light/dark)
├── components/
│   ├── common/                  # DataTable, ErrorBoundary, LoadingSpinner, etc.
│   ├── layouts/                 # Header, Sidebar, MainLayout, AuthLayout
│   ├── dashboard/               # Charts, StatsCards, QuickActions
│   ├── products/                # ProductForm, ProductList, VariantManager
│   ├── orders/                  # OrderList, OrderDetails, OrderTimeline
│   ├── users/                   # UserList, ApprovePharmacies, DocumentViewer
│   ├── payments/                # TransactionList, ChapaConfig, PaymentLogs
│   ├── cms/                     # Banners, BannerForm, PageEditor
│   ├── reports/                 # SalesReport, ProductPerformance
│   ├── settings/                # GeneralSettings, EmailSettings
│   └── categories/              # CategoryTree, CategoryForm
├── pages/                       # Lazy-loaded page components
├── services/                    # 18 Supabase service modules
├── store/                       # 9 Redux Toolkit slices
├── hooks/                       # usePagination, useInactivityLogout, useTokenManager
├── utils/                       # Constants, formatters, validators, helpers
└── test/                        # Integration, accessibility, visual tests

Routing

// src/routes.jsx — createBrowserRouter
const router = createBrowserRouter([
  {
    path: '/',
    element: <ProtectedRoute><MainLayout /></ProtectedRoute>,
    children: [
      { index: true, element: <Dashboard /> },
      { path: 'users', element: <Users /> },
      { path: 'products', element: <Products /> },
      { path: 'orders', element: <Orders /> },
      { path: 'payments', element: <Payments /> },
      { path: 'cms', element: <CMS /> },
      { path: 'promotions', element: <Promotions /> },
      { path: 'reports', element: <Reports /> },
      { path: 'settings', element: <Settings /> },
      { path: 'featured-products', element: <AdminFeaturedProducts /> },
      { path: 'subscriptions', element: <AdminPharmacySubscriptions /> },
    ],
  },
  {
    path: '/auth',
    element: <AuthLayout />,
    children: [
      { path: 'login', element: <Login /> },
      { path: 'forgot-password', element: <ForgotPassword /> },
      { path: 'reset-password', element: <ResetPassword /> },
    ],
  },
]);

All pages are lazy-loaded with React.lazy() + <Suspense>.

State Management: Redux Toolkit

9 slices compose the store:

const store = configureStore({
  reducer: {
    auth: authReducer,
    users: userReducer,
    products: productReducer,
    orders: orderReducer,
    ui: uiReducer,
    dashboard: dashboardReducer,
    categories: categoryReducer,
    featureProduct: featureProductReducer,
    pharmacySubscription: pharmacySubscriptionReducer,
  },
});
Item Icon Path
Dashboard DashboardIcon /
Users PeopleIcon /users
Categories CategoryIcon /categories
Products InventoryIcon /products
Orders ReceiptLongIcon /orders
Payments PaymentIcon /payments
CMS ArticleIcon /cms
Reports AssessmentIcon /reports
Settings SettingsIcon /settings
Featured Products StarIcon /featured-products
Subscriptions LocalPharmacyIcon /subscriptions
Promotions CampaignIcon /promotions

Data Flow

graph LR
    UI[UI Component] --> |useDispatch| THUNK[Async Thunk]
    THUNK --> |call| SVC[Service Module]
    SVC --> |Supabase query| DB[(PostgreSQL)]
    DB --> |response| SVC
    SVC --> |return data| THUNK
    THUNK --> |dispatch fulfilled| SLICE[Redux Slice]
    SLICE --> |update state| STORE[Redux Store]
    STORE --> |useSelector| UI
    DB --> |Realtime subscription| SLICE