@campxdev/shared 3.1.23 → 3.1.24-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CLAUDE.md ADDED
@@ -0,0 +1,202 @@
1
+ # CLAUDE.md
2
+
3
+ ## Project Overview
4
+
5
+ **Package**: `@campxdev/shared` (v3.1.23)
6
+ **Entry point**: `./exports.ts`
7
+ **Type**: Shared React component library (internally called "X1 UI package")
8
+
9
+ This is a shared frontend library consumed by **all CampX frontend microfrontends** (27+ apps). It provides common React components, hooks, utilities, contexts, layouts, and theme configuration. It is the **legacy** shared UI layer (X1, built on MUI + styled-components). The newer design system is `@campxdev/react-blueprint` (X3), but this package remains widely used and actively maintained.
10
+
11
+ **Consumers**: Every `campx-*-web` frontend repo imports from `@campxdev/shared`. Changes here propagate across the entire platform.
12
+
13
+ ## Architecture
14
+
15
+ ### Package Structure
16
+
17
+ ```
18
+ src/
19
+ ├── components/ # Reusable UI components (the bulk of this package)
20
+ ├── hooks/ # Custom React hooks
21
+ ├── utils/ # Helper functions, formatters, parsers
22
+ ├── contexts/ # React context providers (auth, tenant, etc.)
23
+ ├── layouts/ # Page layout shells and wrappers
24
+ ├── theme/ # MUI theme configuration and overrides
25
+ ├── config/ # Axios instances, app config
26
+ ├── constants/ # Shared constants and enums
27
+ ├── shared-state/ # Pullstate global stores
28
+ ├── permissions/ # Permission definitions and helpers
29
+ ├── sitemap/ # Route/navigation definitions
30
+ ├── assets/ # Shared icons, images, static files
31
+ ├── stories/ # Storybook stories
32
+ ├── pages/ # Shared pages (login, error, profile, etc.)
33
+ ├── App.tsx # Dev/preview app (not exported)
34
+ ├── index.tsx # Dev server entry point (not exported)
35
+ ```
36
+
37
+ ### Entry Point
38
+
39
+ The **published entry point** is `exports.ts` (at project root, NOT `src/index.tsx`). This file re-exports everything consumers can import. `src/index.tsx` is only for local dev/preview via `react-scripts start`.
40
+
41
+ When adding new exports, **always add them to `exports.ts`** — otherwise consumers cannot access them.
42
+
43
+ ### Key Technology Stack
44
+
45
+ - **React 18** with TypeScript
46
+ - **MUI v7** (`@mui/material`, `@mui/icons-material`, `@mui/lab`, `@mui/x-date-pickers`)
47
+ - **Emotion** (`@emotion/react`, `@emotion/styled`) — MUI's styling engine
48
+ - **styled-components** — also present for legacy styled components
49
+ - **react-hook-form** + **yup** — form state and validation
50
+ - **react-query v3** — server state management
51
+ - **react-table v7** — table components
52
+ - **Pullstate** — lightweight global state
53
+ - **Axios** — HTTP client
54
+ - **react-router-dom v6** — routing utilities
55
+ - **react-toastify** — toast notifications
56
+ - **Moment.js** — date handling
57
+ - **Fuse.js** — fuzzy search
58
+ - **Storybook 6** — component documentation (dev only)
59
+
60
+ ## Key Commands
61
+
62
+ | Command | Purpose |
63
+ |---------|---------|
64
+ | `yarn start` / `yarn dev` | Start local dev server (CRA, port 3000) for previewing components |
65
+ | `yarn build` | Production build (`CI=false && react-scripts build`) |
66
+ | `yarn test` | Run tests via react-scripts |
67
+ | `yarn lint` | ESLint check across all src files |
68
+ | `yarn lint:fix` | Auto-fix lint issues |
69
+ | `yarn format` | Prettier format all source files |
70
+ | `yarn storybook` | Start Storybook on port 6006 |
71
+ | `yarn build-storybook` | Build static Storybook site |
72
+
73
+ ### Local Linking Workflow (yalc)
74
+
75
+ This is a **library package** — it is not deployed standalone. To test changes in a consuming app:
76
+
77
+ 1. **In this repo**: make changes, then run:
78
+ ```bash
79
+ yalc push
80
+ ```
81
+ 2. **In the consuming repo** (e.g., `campx-common-workspace`):
82
+ ```bash
83
+ yalc add @campxdev/shared
84
+ yarn install
85
+ ```
86
+ 3. After iterating, repeat `yalc push` — consuming repos with `yalc link` will auto-update.
87
+ 4. **Before committing** in the consuming repo, remove yalc link:
88
+ ```bash
89
+ yalc remove @campxdev/shared
90
+ yarn install
91
+ ```
92
+
93
+ > **Note**: The `CI=false` in the build script suppresses treating warnings as errors. This is intentional for CRA builds.
94
+
95
+ ## Exports
96
+
97
+ The `exports.ts` file is the source of truth. Exports are organized by category:
98
+
99
+ ### Components (`src/components/`)
100
+
101
+ The largest export surface. Key component groups:
102
+
103
+ - **Layout & Navigation**: `PageHeader`, `PageContent`, `Breadcrumbs`, `Layout/*`, `Tabs/*`, `StepsHeader/*`
104
+ - **Forms**: `HookForm/*` (react-hook-form wrappers), `Form/*`, `Input/*`, `Selectors/*`, `ImageUpload`, `ExcelToJsonInput/*`
105
+ - **Tables**: `Table`, `Tables/*`, `StyledTableContainer`, `CustomizeReport/*`
106
+ - **Feedback**: `Spinner`, `FullScreenLoader`, `LinearProgress`, `ErrorBox`, `ErrorModal`, `ErrorModalWrapper/*`, `ErrorBoundary/*`, `NoDataIllustration`
107
+ - **Overlays**: `DrawerWrapper/*`, `PopupConfirm/*`, `UploadFileDialog/*`, `ModalButtons/*`
108
+ - **Data Display**: `Card`, `CardsGrid`, `Detail`, `DetailsGrid`, `LabelValue`, `JsonPreview`, `Chips`, `IconLabel`
109
+ - **Actions**: `ActionButton`, `IconButtons/*`, `DropDownButton/*`, `UploadButton/*`, `SwitchButton`, `ListItemButton`
110
+ - **Domain-specific**: `StudentCard/*`, `FeeCard`, `LoginForm`, `ChangePassword`, `ResetPassword`, `MyProfile/*`, `ActiveDevices/*`, `ActivityLog/*`, `ApplicationProfile/*`, `MongoCharts/*`, `Institutions/*`, `DatabaseConfiguration/*`
111
+ - **Misc**: `Attachment`, `FloatingContainer`, `DividerHeading`, `ReportHeader`, `SignatureFooter`, `ReactJoyRide`, `ToastContainer/*`, `MediaRow/*`, `AutocompleteSearch/*`, `FilterComponents/*`
112
+
113
+ ### Hooks (`src/hooks/`)
114
+
115
+ Custom hooks for common patterns — data fetching wrappers, form utilities, UI state, permissions checks, etc.
116
+
117
+ ### Utilities (`src/utils/`)
118
+
119
+ Helper functions: formatters (dates, currency, names), validators, file handling, API helpers, permission checks, etc.
120
+
121
+ ### Contexts (`src/contexts/`)
122
+
123
+ React context providers for auth state, tenant info, app-level configuration that wraps consuming apps.
124
+
125
+ ### Shared State (`src/shared-state/`)
126
+
127
+ Pullstate stores shared across the app — user state, UI state, notifications, etc.
128
+
129
+ ### Theme (`src/theme/`)
130
+
131
+ MUI theme object, palette definitions, typography overrides, component style overrides. Consumers wrap their app with this theme.
132
+
133
+ ### Permissions (`src/permissions/`)
134
+
135
+ Permission constants and helper utilities for role-based access control across the CampX platform.
136
+
137
+ ### Config (`src/config/`)
138
+
139
+ Axios instance configuration, API base URL setup, app-level config constants.
140
+
141
+ ### Constants (`src/constants/`)
142
+
143
+ Shared enums, magic strings, configuration constants used across multiple frontend apps.
144
+
145
+ ### Sitemap (`src/sitemap/`)
146
+
147
+ Route definitions and navigation structure shared across microfrontends.
148
+
149
+ ## Versioning
150
+
151
+ - **Current version**: 3.1.23
152
+ - **Semver conventions**:
153
+ - **Patch** (3.1.x): Bug fixes, style tweaks, non-breaking additions
154
+ - **Minor** (3.x.0): New components, new hooks, new exports (backward-compatible)
155
+ - **Major** (x.0.0): Breaking changes to existing component APIs, removed exports, theme changes that affect all consumers
156
+ - **Bump version** in `package.json` before publishing
157
+ - **Publishing**: Handled via CI/GitHub Actions — do not publish manually to npm
158
+
159
+ ### Breaking Change Considerations
160
+
161
+ Since 27+ microfrontends consume this package, **breaking changes are high-impact**:
162
+ - Never rename or remove an exported component/hook/utility without coordinating migration across all consumers
163
+ - Never change component prop interfaces in a breaking way without a major version bump
164
+ - Prefer adding new props with defaults over modifying existing behavior
165
+ - Deprecate before removing — add console warnings in the interim
166
+
167
+ ## Consuming Repo Conventions
168
+
169
+ Patterns that consuming repos follow (and that this package must support):
170
+
171
+ - **Imports**: Consumers import directly from the package name:
172
+ ```tsx
173
+ import { PageHeader, useAuth, formatDate } from '@campxdev/shared'
174
+ ```
175
+ - **Theme**: Consumers wrap their app with the theme provider exported from this package
176
+ - **Axios**: Consumers may use the Axios instance from this package's config or from `@campxdev/campx-web-utils`
177
+ - **react-hook-form**: Form components expect react-hook-form v7 context. Consumers use `useForm` from react-hook-form and pass `control`/`register` to shared form components
178
+ - **react-query v3**: Hooks that use react-query expect a `QueryClientProvider` in the consumer's tree
179
+ - **react-router-dom v6**: Components that use routing (Breadcrumbs, Layout, etc.) expect a v6 router context
180
+ - **MUI v7**: Consumers must have compatible MUI v7 peer dependencies
181
+ - **Multi-tenancy**: All API-calling utilities must respect tenant context. Never hardcode tenant-specific values
182
+ - **Pullstate**: Consumers share Pullstate stores exported from this package for cross-cutting concerns (user state, etc.)
183
+
184
+ ## Code Style
185
+
186
+ - **TypeScript** throughout — avoid `any` types; prefer explicit interfaces
187
+ - **ESLint + Prettier** configured — run `yarn lint:fix` and `yarn format` before committing
188
+ - **Prettier config**: `.prettierrc` at project root
189
+ - **Component pattern**: Functional components with hooks, no class components
190
+ - **Styling**: Prefer MUI `sx` prop or Emotion `styled()`. styled-components exists but is legacy — prefer Emotion for new code
191
+
192
+ ## Storybook
193
+
194
+ Storybook is available for component documentation and visual testing:
195
+ - `yarn storybook` — starts on port 6006
196
+ - Stories live in `src/stories/`
197
+ - Uses `storybook-addon-react-router-v6` for components requiring router context
198
+ - `cross-env NODE_OPTIONS=--openssl-legacy-provider` is needed for the build due to Storybook 6 + Node 18+ compatibility
199
+
200
+ ## Last Updated
201
+
202
+ 2026-03-13
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@campxdev/shared",
3
- "version": "3.1.23",
3
+ "version": "3.1.24-alpha.2",
4
4
  "main": "./exports.ts",
5
5
  "scripts": {
6
6
  "start": "react-scripts start",
@@ -36,6 +36,7 @@
36
36
  "@mui/material": "^7.0.2",
37
37
  "@mui/x-date-pickers": "^8.1.0",
38
38
  "axios": "^1.7.2",
39
+ "crypto-js": "^4.2.0",
39
40
  "device-detector-js": "^3.0.3",
40
41
  "fuse.js": "^6.6.2",
41
42
  "js-cookie": "^3.0.5",
@@ -69,6 +70,7 @@
69
70
  "@storybook/preset-create-react-app": "^4.0.0",
70
71
  "@storybook/react": "^6.5.14",
71
72
  "@storybook/testing-library": "^0.0.13",
73
+ "@types/crypto-js": "^4.2.2",
72
74
  "@types/js-cookie": "^3.0.6",
73
75
  "@types/node": "^18.11.8",
74
76
  "@types/react": "^18.3.3",
@@ -2,6 +2,7 @@ import Axios, { InternalAxiosRequestConfig } from 'axios'
2
2
  import Cookies from 'js-cookie'
3
3
  import { toast } from 'react-toastify'
4
4
  import { NetworkStore } from '../components/ErrorBoundary/GlobalNetworkLoadingIndicator'
5
+ import { generateClientToken } from '../utils/clientAuthToken'
5
6
 
6
7
  // Declare the extended axios types to include our custom property
7
8
  declare module 'axios' {
@@ -95,6 +96,16 @@ axios.interceptors.request.use(
95
96
  config.headers.set('campx_open_payments_key', openPaymentsKey)
96
97
  }
97
98
 
99
+ // Inject client authentication token
100
+ const campxClientId = process.env.REACT_APP_CLIENT_ID
101
+ const campxClientSecret = process.env.REACT_APP_CAMPX_CLIENT_SECRET
102
+ if (campxClientId && campxClientSecret) {
103
+ config.headers.set(
104
+ 'x-campx-client',
105
+ generateClientToken(campxClientId, campxClientSecret),
106
+ )
107
+ }
108
+
98
109
  return {
99
110
  ...config,
100
111
  params,
@@ -138,7 +149,7 @@ export const axiosErrorToast = (error: any, fallback?: string) => {
138
149
  const fallbackMessage = fallback ?? 'Something went wrong.'
139
150
  const errorMessage =
140
151
  typeof error?.response?.data?.message !== 'string'
141
- ? (error?.response?.data?.message?.join('\n') ?? fallbackMessage)
152
+ ? error?.response?.data?.message?.join('\n') ?? fallbackMessage
142
153
  : error?.response?.data?.message
143
154
 
144
155
  return toast.error(errorMessage)
@@ -1,7 +1,7 @@
1
1
  import Axios from 'axios'
2
2
  import Cookies from 'js-cookie'
3
3
  import { NetworkStore } from '../components/ErrorBoundary/GlobalNetworkLoadingIndicator'
4
- import { isDevelopment } from '../constants'
4
+ import { generateClientToken } from '../utils/clientAuthToken'
5
5
  import { formatParams } from './axios'
6
6
 
7
7
  // const sessionKey = Cookies.get('campx_session_key')
@@ -25,6 +25,15 @@ axiosEvaluator.interceptors.request.use(
25
25
  NetworkStore.update((s) => {
26
26
  s.loading = true
27
27
  })
28
+ // Inject client authentication token
29
+ const campxClientId = process.env.REACT_APP_CLIENT_ID
30
+ const campxClientSecret = process.env.REACT_APP_CAMPX_CLIENT_SECRET
31
+ if (campxClientId && campxClientSecret) {
32
+ config.headers.set(
33
+ 'x-campx-client',
34
+ generateClientToken(campxClientId, campxClientSecret),
35
+ )
36
+ }
28
37
  return { ...config, params }
29
38
  },
30
39
  function (error) {
@@ -2,6 +2,7 @@ import Axios from 'axios'
2
2
  import Cookies from 'js-cookie'
3
3
  import { NetworkStore } from '../components/ErrorBoundary/GlobalNetworkLoadingIndicator'
4
4
  import { isDevelopment } from '../constants'
5
+ import { generateClientToken } from '../utils/clientAuthToken'
5
6
  import { formatParams } from './axios'
6
7
 
7
8
  const sessionKey = Cookies.get('campx_session_key')
@@ -33,6 +34,15 @@ axiosTenant.interceptors.request.use(
33
34
  NetworkStore.update((s) => {
34
35
  s.loading = true
35
36
  })
37
+ // Inject client authentication token
38
+ const campxClientId = process.env.REACT_APP_CLIENT_ID
39
+ const campxClientSecret = process.env.REACT_APP_CAMPX_CLIENT_SECRET
40
+ if (campxClientId && campxClientSecret) {
41
+ config.headers.set(
42
+ 'x-campx-client',
43
+ generateClientToken(campxClientId, campxClientSecret),
44
+ )
45
+ }
36
46
  return { ...config, params }
37
47
  },
38
48
  function (error) {
@@ -0,0 +1,17 @@
1
+ import CryptoJS from 'crypto-js'
2
+
3
+ function toBase64Url(base64: string): string {
4
+ return base64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '')
5
+ }
6
+
7
+ export function generateClientToken(clientId: string, secret: string): string {
8
+ const payload = { clientId, iat: Math.floor(Date.now() / 1000) }
9
+ const payloadBase64url = toBase64Url(btoa(JSON.stringify(payload)))
10
+
11
+ const signatureWordArray = CryptoJS.HmacSHA256(payloadBase64url, secret)
12
+ const signatureBase64url = toBase64Url(
13
+ CryptoJS.enc.Base64.stringify(signatureWordArray),
14
+ )
15
+
16
+ return `${payloadBase64url}.${signatureBase64url}`
17
+ }