@umituz/web-dashboard 3.2.4 → 4.1.0

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.
Files changed (126) hide show
  1. package/README.md +228 -14
  2. package/package.json +23 -30
  3. package/src/domains/analytics/components/AnalyticsCard.tsx +43 -42
  4. package/src/domains/analytics/components/AnalyticsChart.tsx +345 -149
  5. package/src/domains/analytics/components/AnalyticsLayout.tsx +93 -112
  6. package/src/domains/analytics/components/MetricCard.tsx +29 -87
  7. package/src/domains/analytics/hooks/index.ts +7 -1
  8. package/src/domains/analytics/hooks/useAnalytics.ts +144 -139
  9. package/src/domains/analytics/index.ts +11 -0
  10. package/src/domains/analytics/services/AnalyticsEngineService.ts +103 -55
  11. package/src/domains/analytics/services/PerformanceService.ts +117 -69
  12. package/src/domains/analytics/types/analytics.ts +20 -6
  13. package/src/domains/analytics/types/index.ts +3 -0
  14. package/src/domains/analytics/utils/analytics.test.ts +183 -0
  15. package/src/domains/analytics/utils/analytics.ts +26 -9
  16. package/src/domains/analytics/utils/i18nKeys.ts +40 -0
  17. package/src/domains/analytics/utils/index.ts +2 -0
  18. package/src/domains/auth/components/AuthLayout.tsx +63 -54
  19. package/src/domains/auth/components/ForgotPasswordForm.tsx +96 -98
  20. package/src/domains/auth/components/LoginForm.tsx +167 -226
  21. package/src/domains/auth/components/RegisterForm.tsx +202 -272
  22. package/src/domains/auth/components/ResetPasswordForm.tsx +105 -151
  23. package/src/domains/auth/components/shared/AuthErrorBanner.tsx +35 -0
  24. package/src/domains/auth/components/shared/EmailInput.tsx +91 -0
  25. package/src/domains/auth/components/shared/PasswordInput.tsx +119 -0
  26. package/src/domains/auth/components/shared/PasswordStrengthIndicator.tsx +75 -0
  27. package/src/domains/auth/components/shared/SocialLoginButtons.tsx +58 -0
  28. package/src/domains/auth/components/shared/SocialProviderIcons.tsx +48 -0
  29. package/src/domains/auth/components/shared/index.ts +20 -0
  30. package/src/domains/auth/hooks/index.ts +1 -0
  31. package/src/domains/auth/hooks/useAuth.ts +151 -232
  32. package/src/domains/auth/index.ts +8 -4
  33. package/src/domains/auth/types/auth.ts +26 -5
  34. package/src/domains/auth/types/index.ts +1 -0
  35. package/src/domains/auth/utils/auth.test.ts +182 -0
  36. package/src/domains/auth/utils/auth.ts +71 -130
  37. package/src/domains/auth/utils/i18nKeys.ts +127 -0
  38. package/src/domains/auth/utils/index.ts +7 -1
  39. package/src/domains/auth/utils/secureToken.ts +33 -0
  40. package/src/domains/auth/utils/validationKeys.ts +23 -0
  41. package/src/domains/calendar/hooks/useCalendar.ts +145 -151
  42. package/src/domains/calendar/index.ts +0 -1
  43. package/src/domains/calendar/services/CalendarService.ts +122 -179
  44. package/src/domains/calendar/utils/contentItemMapper.test.ts +108 -0
  45. package/src/domains/calendar/utils/contentItemMapper.ts +99 -0
  46. package/src/domains/calendar/utils/index.ts +33 -30
  47. package/src/domains/layouts/components/BrandLogo.tsx +12 -9
  48. package/src/domains/layouts/components/DashboardHeader.tsx +78 -80
  49. package/src/domains/layouts/components/DashboardLayout.tsx +45 -21
  50. package/src/domains/layouts/components/DashboardSidebar.tsx +48 -51
  51. package/src/domains/layouts/types/layout.ts +7 -1
  52. package/src/domains/layouts/types/user.ts +3 -1
  53. package/src/domains/modules/build.test.tsx +97 -0
  54. package/src/domains/modules/build.tsx +71 -0
  55. package/src/domains/modules/index.ts +2 -0
  56. package/src/domains/modules/types.ts +29 -0
  57. package/src/domains/onboarding/components/AppFocusStep.tsx +99 -68
  58. package/src/domains/onboarding/components/OnboardingWizard.tsx +109 -183
  59. package/src/domains/onboarding/components/PlanStep.tsx +156 -123
  60. package/src/domains/onboarding/components/PlatformsStep.tsx +74 -54
  61. package/src/domains/onboarding/components/StepNavigation.tsx +108 -0
  62. package/src/domains/onboarding/components/StepProgress.tsx +62 -0
  63. package/src/domains/onboarding/components/UserTypeStep.tsx +59 -80
  64. package/src/domains/onboarding/components/index.ts +4 -0
  65. package/src/domains/onboarding/hooks/useOnboarding.ts +76 -66
  66. package/src/domains/onboarding/index.ts +1 -0
  67. package/src/domains/onboarding/types/onboarding.ts +57 -17
  68. package/src/domains/onboarding/utils/i18nKeys.ts +72 -0
  69. package/src/domains/onboarding/utils/index.ts +2 -0
  70. package/src/domains/permissions/PermissionsContext.tsx +103 -0
  71. package/src/domains/permissions/hasPermission.test.ts +50 -0
  72. package/src/domains/permissions/hasPermission.ts +38 -0
  73. package/src/domains/permissions/index.ts +19 -0
  74. package/src/domains/permissions/types.ts +35 -0
  75. package/src/domains/permissions/utils/i18nKeys.ts +11 -0
  76. package/src/domains/session/DemoLogin.tsx +50 -0
  77. package/src/domains/session/OrgSwitcher.tsx +110 -0
  78. package/src/domains/session/SessionContext.tsx +150 -0
  79. package/src/domains/session/inMemoryAuthAdapter.ts +53 -0
  80. package/src/domains/session/index.ts +18 -0
  81. package/src/domains/session/types.ts +47 -0
  82. package/src/domains/session/utils/i18nKeys.ts +12 -0
  83. package/src/domains/settings/components/AuditLogList.tsx +59 -0
  84. package/src/domains/settings/components/PermissionMatrixScreen.tsx +80 -0
  85. package/src/domains/settings/components/SettingsLayout.tsx +75 -60
  86. package/src/domains/settings/components/SettingsSection.tsx +35 -22
  87. package/src/domains/settings/components/UserManagementTable.tsx +69 -0
  88. package/src/domains/settings/components/index.ts +10 -0
  89. package/src/domains/settings/hooks/useSettings.ts +77 -52
  90. package/src/domains/settings/types/settings.ts +2 -0
  91. package/src/domains/settings/utils/i18nKeys.ts +18 -0
  92. package/src/domains/settings/utils/index.ts +1 -0
  93. package/src/domains/settings/utils/settings.ts +11 -4
  94. package/src/i18n/I18nContext.tsx +33 -0
  95. package/src/i18n/defaultT.test.ts +43 -0
  96. package/src/i18n/defaultT.ts +34 -0
  97. package/src/i18n/index.ts +7 -0
  98. package/src/i18n/types.ts +13 -0
  99. package/src/index.ts +1 -7
  100. package/src/primitives/Button.tsx +24 -0
  101. package/src/primitives/Checkbox.tsx +17 -0
  102. package/src/primitives/Input.tsx +23 -0
  103. package/src/primitives/Skeleton.tsx +6 -0
  104. package/src/primitives/cn.ts +10 -0
  105. package/src/primitives/index.ts +23 -0
  106. package/src/styles/dashboard.css +2731 -0
  107. package/src/styles/tokens.contract.test.ts +91 -0
  108. package/src/styles/tokens.css +116 -0
  109. package/src/domains/billing/components/BillingLayout.tsx +0 -63
  110. package/src/domains/billing/components/BillingPage.tsx +0 -49
  111. package/src/domains/billing/components/BillingPortal.tsx +0 -198
  112. package/src/domains/billing/components/InvoiceCard.tsx +0 -143
  113. package/src/domains/billing/components/PaymentMethodsList.tsx +0 -116
  114. package/src/domains/billing/components/PlanComparison.tsx +0 -199
  115. package/src/domains/billing/components/UsageCard.tsx +0 -103
  116. package/src/domains/billing/components/index.ts +0 -13
  117. package/src/domains/billing/constants/billing.ts +0 -69
  118. package/src/domains/billing/hooks/index.ts +0 -7
  119. package/src/domains/billing/hooks/useBilling.ts +0 -385
  120. package/src/domains/billing/index.ts +0 -73
  121. package/src/domains/billing/types/billing.ts +0 -342
  122. package/src/domains/billing/types/index.ts +0 -30
  123. package/src/domains/billing/utils/billing.ts +0 -360
  124. package/src/domains/billing/utils/index.ts +0 -31
  125. package/src/domains/billing/utils/polar.ts +0 -63
  126. package/src/domains/calendar/components/index.ts +0 -7
package/README.md CHANGED
@@ -1,32 +1,246 @@
1
1
  # @umituz/web-dashboard
2
2
 
3
- Comprehensive dashboard library with analytics, billing, calendar, and more.
3
+ Installable app skeleton for SaaS dashboards: layouts, auth, onboarding,
4
+ analytics, a content calendar, an i18n bridge, and a permissions/session/
5
+ module registry. Every domain is an independent entry point — import only
6
+ what your app uses. Camp-agnostic by construction: the package ships its
7
+ own `udb-*` stylesheet driven by `--u-*` tokens, so it works identically in
8
+ vanilla-CSS and Tailwind hosts.
4
9
 
5
- ## Features
10
+ The package is **source-distributed** (published as raw TypeScript in `src/`).
11
+ Your bundler compiles it alongside your app; no prebuilt bundle ships.
6
12
 
7
- - Analytics dashboards with charts
8
- - Billing and subscription management
9
- - Calendar integration
10
- - User management
11
- - Real-time metrics
13
+ ## What changed in v4 (major)
14
+
15
+ - **Billing moved to [@umituz/web-polar-payment](https://github.com/umituz/web-polar-payment)**
16
+ under the `./portal` entry point. The old `./billing*` entry points are gone.
17
+ - **Styling is shipped, not assumed.** Import `@umituz/web-dashboard/styles.css`
18
+ once; all components use `udb-*` BEM classes.
19
+ - **No i18n runtime.** `react-i18next` is out; hosts bridge their own `t` via
20
+ `<DashboardI18nProvider t={i18n.t}>` (see below). Without a provider,
21
+ keys humanize to readable English.
22
+ - **No Firebase.** The calendar persists through the injected
23
+ `ICalendarDatabase` seam; `createInMemoryCalendarDatabase()` is the default.
24
+ - **recharts is out.** `AnalyticsChart` renders line/area/bar/pie/donut as
25
+ dependency-free SVG with native `<title>` tooltips.
26
+ - **New fleet modules**: `./permissions`, `./session`, `./modules` — the
27
+ texora/visora pattern (one module list drives routes + nav + guards) as
28
+ reusable building blocks.
29
+
30
+ ## What changed in 4.1
31
+
32
+ - **The design system is back — for real this time.** 4.0 dropped
33
+ `@umituz/web-design-system` entirely; 4.1 makes it a runtime dependency
34
+ again and actually renders it:
35
+ - `./primitives` (`Button`, `Input`, `Checkbox`, `Skeleton`, `cn`) are thin
36
+ adapters that **delegate to the DS components** — the dashboard prop API
37
+ is unchanged, call sites need zero edits.
38
+ - `UserManagementTable` renders the DS `DataTable`; `MetricCard` composes
39
+ the DS `MetricCard`; `AnalyticsCard` is built on DS `Card` primitives.
40
+ - `styles.css` imports `@umituz/web-design-system/styles.css` transitively
41
+ (Tailwind v4 precompiled) — hosts still import only the dashboard
42
+ stylesheet.
43
+ - **`--u-*` tokens are now bridges.** `tokens.css` maps every color/radius/
44
+ shadow token to the DS `--color-*`/`--radius-*` variables (with the old
45
+ literal as fallback). Override either side; dark mode (`data-udb-theme="dark"`)
46
+ now sets DS variables and the bridge flows through.
47
+ - **Primitive base CSS is gone from `dashboard.css`.** Only dashboard-owned
48
+ modifiers remain (`udb-btn__spinner`, `udb-input--error/--with-toggle`,
49
+ `udb-skeleton--*`, `udb-card--sm/--lg`, `udb-table` for the permission
50
+ matrix); bases come from the DS stylesheet.
51
+ - **Peer footprint**: pulling the dashboard in transitively installs the DS's
52
+ Radix UI peers (npm 7+ handles this automatically; only imported components
53
+ end up in the bundle).
12
54
 
13
55
  ## Installation
14
56
 
15
57
  ```bash
16
58
  npm install @umituz/web-dashboard
59
+ import "@umituz/web-dashboard/styles.css";
17
60
  ```
18
61
 
19
- ## Usage
62
+ Peers: `react` + `react-dom` (^18 or ^19) and `react-router-dom` (^6 or ^7).
63
+ Runtime deps: `@umituz/web-design-system` + `lucide-react`. Nothing else.
64
+
65
+ ### Tailwind hosts
66
+
67
+ Every `udb-*` rule sets its own `box-sizing`/`background`/`border` explicitly,
68
+ so preflight cannot leak in — but load order still matters with `*`-selector
69
+ resets: import the package stylesheet **after** your base layer.
70
+
71
+ ### Theming & dark mode
72
+
73
+ `tokens.css` bridges every `--u-*` token to a design-system variable
74
+ (`--u-color-primary: var(--color-primary, #2563eb)`), so you can theme two
75
+ ways: override the `--u-*` bridge heads, or set the DS `--color-*`/`--radius-*`
76
+ variables (e.g. from your own Tailwind `@theme`). Dark mode is host-driven:
77
+ put `data-udb-theme="dark"` on any ancestor — the dashboard dark block sets
78
+ the DS variables and both layers switch together.
20
79
 
21
- ```typescript
22
- import { useAnalytics } from '@umituz/web-dashboard';
80
+ ## Entry points
23
81
 
24
- function Dashboard() {
25
- const { data, loading } = useAnalytics();
26
- // ...
27
- }
82
+ ```bash
83
+ @umituz/web-dashboard/styles.css # component stylesheet (udb-* BEM)
84
+ @umituz/web-dashboard/tokens.css # --u-* custom properties only
85
+ @umituz/web-dashboard/primitives # Button, Input, Checkbox, Skeleton, cn
86
+ @umituz/web-dashboard/i18n # DashboardI18nProvider, useT, defaultT
87
+ @umituz/web-dashboard/permissions # PermissionMatrix, hasPermission, guards
88
+ @umituz/web-dashboard/session # AuthAdapter, SessionProvider, OrgSwitcher, DemoLogin
89
+ @umituz/web-dashboard/modules # DashboardModule, buildRoutes, buildNav
90
+ @umituz/web-dashboard/layouts # DashboardLayout, DashboardSidebar, DashboardHeader
91
+ @umituz/web-dashboard/settings # SettingsLayout, admin skeletons (users, matrix, audit)
92
+ @umituz/web-dashboard/onboarding # OnboardingWizard + steps, useOnboarding
93
+ @umituz/web-dashboard/auth # Login/Register/Forgot/Reset forms, AuthLayout
94
+ @umituz/web-dashboard/analytics # AnalyticsLayout, SVG AnalyticsChart, services
95
+ @umituz/web-dashboard/calendar # useCalendar, CalendarService (injected DB)
96
+ @umituz/web-dashboard/config # dashboard config helpers
28
97
  ```
29
98
 
99
+ Each domain also exposes `components`, `hooks`, `utils`, `types`
100
+ sub-entries (and `services` for analytics/calendar). The new v4 modules
101
+ (`permissions`, `session`, `modules`) are **deep-entry only** — they are not
102
+ re-exported from the root, so router-less hosts never pull router code in
103
+ transitively.
104
+
105
+ ## The v4 composition
106
+
107
+ A host app assembles the skeleton from four seams:
108
+
109
+ ```tsx
110
+ import { DashboardI18nProvider } from "@umituz/web-dashboard/i18n";
111
+ import { SessionProvider, createInMemoryAuthAdapter } from "@umituz/web-dashboard/session";
112
+ import { PermissionsProvider } from "@umituz/web-dashboard/permissions";
113
+
114
+ const adapter = createInMemoryAuthAdapter({ users: DEMO_USERS });
115
+
116
+ <DashboardI18nProvider t={i18n.t}>
117
+ <SessionProvider adapter={adapter}>
118
+ <PermissionsProvider matrix={ROLE_PERMISSIONS} role={user?.role}>
119
+ <App />
120
+ </PermissionsProvider>
121
+ </SessionProvider>
122
+ </DashboardI18nProvider>
123
+ ```
124
+
125
+ ### One module list → routes + nav + guards
126
+
127
+ ```tsx
128
+ import { buildRoutes, buildNav } from "@umituz/web-dashboard/modules";
129
+ import { usePermissions } from "@umituz/web-dashboard/permissions";
130
+
131
+ const MODULES: DashboardModule[] = [
132
+ { path: "/dashboard", labelKey: "nav.dashboard", icon: LayoutDashboard,
133
+ navGroup: "nav.overview", order: 1, permission: "dashboard.view",
134
+ element: <DashboardPage /> },
135
+ { path: "/sales/:id", labelKey: "nav.salesDetail", icon: Circle,
136
+ navGroup: "nav.commercial", inNav: false, permission: "sales.view",
137
+ element: <SalesDetailPage /> },
138
+ ];
139
+
140
+ // routes: element pre-wrapped in <RequirePermission>
141
+ const routes = buildRoutes(MODULES); // -> <Route path key={...} {...route} />
142
+
143
+ // nav: permission-filtered, grouped, ordered -> feed DashboardLayout config
144
+ const { can } = usePermissions();
145
+ const sidebarGroups = buildNav(MODULES, { can });
146
+ ```
147
+
148
+ Groups keep their first-appearance order in the list; `order` sorts items
149
+ within a group; `inNav: false` hides detail routes from the sidebar.
150
+
151
+ ### Permissions
152
+
153
+ `hasPermission(matrix, role, permission)` is pure and deny-by-default.
154
+ Matrix grants are `"*"` (everything), `"sales.*"` (module wildcard) or exact
155
+ strings. `<RequirePermission permission>` guards pages (lock screen
156
+ fallback); `<Can>` is its inline twin.
157
+
158
+ ### Session
159
+
160
+ Hosts adapt their auth to `AuthAdapter` (`login`/`logout`/`current`;
161
+ `listTenants`/`demoLogin` optional). `useSession()` exposes user, tenants,
162
+ active tenant, status + `switchTenant`. `OrgSwitcher` renders the tenant
163
+ dropdown; `DemoLogin` the one-click demo entry.
164
+
165
+ ### Calendar
166
+
167
+ ```tsx
168
+ import { CalendarService, createInMemoryCalendarDatabase } from "@umituz/web-dashboard/calendar/services";
169
+
170
+ // Bring your own backend:
171
+ class MyDatabase implements ICalendarDatabase { /* ... */ }
172
+ const service = new CalendarService(new MyDatabase());
173
+ // or demo/test:
174
+ const demo = new CalendarService(createInMemoryCalendarDatabase());
175
+ ```
176
+
177
+ ### Analytics
178
+
179
+ `AnalyticsChart` consumes the same `ChartConfig` as v3 for
180
+ line/area/bar/pie/donut. Tooltips are native SVG `<title>` elements;
181
+ legends are color chips; unsupported types render an empty state.
182
+ `useAnalytics` stays dependency-injected (`createStubAnalyticsApiClient`).
183
+
184
+ ## i18n contract
185
+
186
+ Components render **i18n keys**, never English strings. Bridge your runtime
187
+ once:
188
+
189
+ ```tsx
190
+ import { DashboardI18nProvider } from "@umituz/web-dashboard/i18n";
191
+
192
+ <DashboardI18nProvider t={i18n.t}> {/* i18next's t — signature already matches */}
193
+ ```
194
+
195
+ Interpolation uses the standard `{{placeholder}}` syntax. Without a
196
+ provider, `useT()` falls back to `defaultT`, which humanizes keys
197
+ (`auth.login.welcomeBack` → "Welcome back") so a bare install still renders
198
+ readably. The per-domain key catalogs are the string contract:
199
+
200
+ ```ts
201
+ import { AUTH_KEYS } from "@umituz/web-dashboard/auth";
202
+ import { ANALYTICS_KEYS } from "@umituz/web-dashboard/analytics";
203
+ import { ONBOARDING_KEYS } from "@umituz/web-dashboard/onboarding";
204
+ import { SETTINGS_ADMIN_KEYS } from "@umituz/web-dashboard/settings/utils";
205
+ import { PERMISSIONS_KEYS } from "@umituz/web-dashboard/permissions";
206
+ import { SESSION_KEYS } from "@umituz/web-dashboard/session";
207
+ ```
208
+
209
+ ## Platform compatibility
210
+
211
+ - React 18 and 19, react-router-dom 6 and 7
212
+ - `generateResetToken` requires `crypto.getRandomValues` (all modern browsers,
213
+ Node ≥ 19) and **throws** rather than falling back to an insecure PRNG
214
+ - Rendering targets the DOM; React Native is not supported
215
+
216
+ ## Development
217
+
218
+ ```bash
219
+ npm install
220
+ npm run lint # eslint
221
+ npm run typecheck # tsc --noEmit
222
+ npm test # vitest unit tests (pure utils + module builders)
223
+ npm run test:watch
224
+ ```
225
+
226
+ CI runs lint + typecheck + test on every push/PR to `main`.
227
+
228
+ ## Migration: 3.x → 4.0
229
+
230
+ 1. Billing UI: switch imports to `@umituz/web-polar-payment/portal`.
231
+ 2. Design-system imports: use `@umituz/web-dashboard/primitives`
232
+ (`Button`/`Input`/`Checkbox`/`Skeleton` cover the used surface).
233
+ 3. Styling: import `styles.css` once; Tailwind utility classes no longer
234
+ exist inside the package. Config values that used to carry Tailwind
235
+ strings changed: `PlatformOption.color` is a plain CSS color string,
236
+ `PlanOption.badgeColor` became `badgeTone: "muted" | "primary" | "accent"`.
237
+ 4. i18n: wrap your app in `DashboardI18nProvider t={i18n.t}`; the
238
+ `react-i18next` peer is gone.
239
+ 5. Calendar: pass your own `ICalendarDatabase` (or the in-memory default);
240
+ the Firebase implementation was removed.
241
+ 6. v3.2.5 behavioral notes still apply (opt-in mock auth, route skeletons
242
+ off by default, `PerformanceService.startMonitoring()` explicit).
243
+
30
244
  ## License
31
245
 
32
246
  MIT
package/package.json CHANGED
@@ -1,12 +1,22 @@
1
1
  {
2
2
  "name": "@umituz/web-dashboard",
3
- "version": "3.2.4",
4
- "description": "Dashboard Layout System - Comprehensive analytics, calendar, customizable layouts, and config-based architecture",
3
+ "version": "4.1.0",
4
+ "description": "Installable app skeleton for the fleet — layouts, auth, onboarding, analytics (dependency-free SVG charts), calendar, i18n injection, permissions/session/module registry; ships its own udb-* stylesheet and --u-* tokens",
5
+ "type": "module",
5
6
  "main": "./src/index.ts",
6
7
  "types": "./src/index.ts",
7
- "sideEffects": false,
8
+ "sideEffects": [
9
+ "*.css"
10
+ ],
8
11
  "exports": {
9
12
  ".": "./src/index.ts",
13
+ "./styles.css": "./src/styles/dashboard.css",
14
+ "./tokens.css": "./src/styles/tokens.css",
15
+ "./primitives": "./src/primitives/index.ts",
16
+ "./i18n": "./src/i18n/index.ts",
17
+ "./permissions": "./src/domains/permissions/index.ts",
18
+ "./session": "./src/domains/session/index.ts",
19
+ "./modules": "./src/domains/modules/index.ts",
10
20
  "./layouts": "./src/domains/layouts/index.ts",
11
21
  "./layouts/components": "./src/domains/layouts/components/index.ts",
12
22
  "./layouts/hooks": "./src/domains/layouts/hooks/index.ts",
@@ -35,16 +45,11 @@
35
45
  "./analytics/types": "./src/domains/analytics/types/index.ts",
36
46
  "./analytics/services": "./src/domains/analytics/services/index.ts",
37
47
  "./calendar": "./src/domains/calendar/index.ts",
38
- "./calendar/types": "./src/domains/calendar/types/calendar.types",
48
+ "./calendar/types": "./src/domains/calendar/types/calendar.types.ts",
39
49
  "./calendar/services": "./src/domains/calendar/services/index.ts",
40
50
  "./calendar/hooks": "./src/domains/calendar/hooks/index.ts",
41
51
  "./calendar/utils": "./src/domains/calendar/utils/index.ts",
42
52
  "./config": "./src/domain/config/index.ts",
43
- "./billing": "./src/domains/billing/index.ts",
44
- "./billing/components": "./src/domains/billing/components/index.ts",
45
- "./billing/hooks": "./src/domains/billing/hooks/index.ts",
46
- "./billing/utils": "./src/domains/billing/utils/index.ts",
47
- "./billing/types": "./src/domains/billing/types/index.ts",
48
53
  "./package.json": "./package.json"
49
54
  },
50
55
  "files": [
@@ -54,6 +59,8 @@
54
59
  "scripts": {
55
60
  "typecheck": "tsc --noEmit",
56
61
  "lint": "eslint src",
62
+ "test": "vitest run",
63
+ "test:watch": "vitest",
57
64
  "version:patch": "npm version patch -m 'chore: release v%s'",
58
65
  "version:minor": "npm version minor -m 'chore: release v%s'",
59
66
  "version:major": "npm version major -m 'chore: release v%s'"
@@ -61,30 +68,22 @@
61
68
  "peerDependencies": {
62
69
  "react": "^18.0.0 || ^19.0.0",
63
70
  "react-dom": "^18.0.0 || ^19.0.0",
64
- "react-router-dom": "^6.0.0 || ^7.0.0",
65
- "firebase": "^10.0.0 || ^11.0.0 || ^12.0.0",
66
- "@umituz/web-firebase": "^3.0.0",
67
- "@umituz/web-polar-payment": "^1.0.20"
71
+ "react-router-dom": "^6.0.0 || ^7.0.0"
68
72
  },
69
73
  "dependencies": {
70
- "class-variance-authority": "^0.7.1",
71
- "clsx": "^2.1.1",
72
- "lucide-react": "^0.577.0",
73
- "recharts": "^2.15.0",
74
- "tailwind-merge": "^3.5.0"
74
+ "@umituz/web-design-system": "^4.0.2",
75
+ "lucide-react": "^0.577.0"
75
76
  },
76
77
  "devDependencies": {
78
+ "@types/node": "^22.20.5",
77
79
  "@types/react": "^19.2.14",
78
80
  "@types/react-dom": "^19.2.3",
79
81
  "@typescript-eslint/eslint-plugin": "^8.57.2",
80
82
  "@typescript-eslint/parser": "^8.57.2",
81
- "@umituz/web-design-system": "^3.1.11",
82
- "@umituz/web-firebase": "^3.6.0",
83
83
  "eslint": "^10.0.2",
84
- "firebase": "^12.0.0",
85
- "react-i18next": "^16.5.4",
86
84
  "react-router-dom": "^7.13.1",
87
- "typescript": "^5.9.3"
85
+ "typescript": "^5.9.3",
86
+ "vitest": "^5.0.1"
88
87
  },
89
88
  "keywords": [
90
89
  "dashboard",
@@ -113,13 +112,7 @@
113
112
  "metrics",
114
113
  "kpi",
115
114
  "visualization",
116
- "recharts",
117
- "billing",
118
- "subscription",
119
- "payment",
120
- "invoices",
121
- "pricing",
122
- "plans",
115
+ "svg-charts",
123
116
  "react",
124
117
  "typescript",
125
118
  "components",
@@ -1,15 +1,28 @@
1
1
  /**
2
- * Analytics Card Component
3
- *
4
- * Configurable analytics card with chart or metrics
2
+ * Analytics Card — chart/metric container on the design-system Card.
3
+ * Size modifiers ("sm"/"lg") are dashboard-owned padding overrides.
5
4
  */
6
5
 
7
6
  import { Loader2, AlertCircle } from "lucide-react";
8
- import { cn } from "@umituz/web-design-system/utils";
7
+ import {
8
+ Card,
9
+ CardHeader,
10
+ CardTitle,
11
+ CardDescription,
12
+ CardContent,
13
+ } from "@umituz/web-design-system/organisms";
14
+ import { cn } from "../../../primitives";
9
15
  import type { AnalyticsCardProps } from "../types/analytics";
10
16
  import { MetricCard } from "./MetricCard";
11
17
  import { AnalyticsChart } from "./AnalyticsChart";
12
18
 
19
+ const SURFACE_CLASS = {
20
+ sm: "udb-card--sm",
21
+ md: undefined,
22
+ lg: "udb-card--lg",
23
+ full: undefined,
24
+ } as const;
25
+
13
26
  export const AnalyticsCard = ({
14
27
  title,
15
28
  description,
@@ -21,59 +34,47 @@ export const AnalyticsCard = ({
21
34
  className,
22
35
  children,
23
36
  }: AnalyticsCardProps) => {
24
- const sizeClasses = {
25
- sm: "p-4",
26
- md: "p-6",
27
- lg: "p-8",
28
- full: "p-6",
29
- };
30
-
31
37
  if (loading) {
32
38
  return (
33
- <div className={cn("bg-background border border-border rounded-xl", sizeClasses[size], className)}>
34
- <div className="flex items-center justify-center h-48">
35
- <Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
39
+ <Card className={cn(SURFACE_CLASS[size], className)}>
40
+ <div className="udb-analytics-card__status" role="status">
41
+ <Loader2 className="udb-spin udb-analytics-card__spinner" aria-hidden="true" />
36
42
  </div>
37
- </div>
43
+ </Card>
38
44
  );
39
45
  }
40
46
 
41
47
  if (error) {
42
48
  return (
43
- <div className={cn("bg-background border border-border rounded-xl", sizeClasses[size], className)}>
44
- <div className="flex items-center justify-center h-48 gap-3 text-destructive">
45
- <AlertCircle className="h-5 w-5" />
46
- <p className="text-sm">{error}</p>
49
+ <Card className={cn(SURFACE_CLASS[size], className)}>
50
+ <div className="udb-analytics-card__status udb-analytics-card__status--error" role="alert">
51
+ <AlertCircle className="udb-analytics-card__error-icon" aria-hidden="true" />
52
+ <p className="udb-analytics-card__error-text">{error}</p>
47
53
  </div>
48
- </div>
54
+ </Card>
49
55
  );
50
56
  }
51
57
 
52
58
  return (
53
- <div className={cn("bg-background border border-border rounded-xl", sizeClasses[size], className)}>
54
- {/* Header */}
59
+ <Card className={cn(SURFACE_CLASS[size], className)}>
55
60
  {(title || description) && (
56
- <div className="mb-6">
57
- {title && <h3 className="text-lg font-semibold text-foreground">{title}</h3>}
58
- {description && <p className="text-sm text-muted-foreground mt-1">{description}</p>}
59
- </div>
60
- )}
61
-
62
- {/* Chart */}
63
- {chart && <AnalyticsChart config={chart} />}
64
-
65
- {/* Metrics */}
66
- {metrics && metrics.length > 0 && (
67
- <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
68
- {metrics.map((metric) => (
69
- <MetricCard key={metric.id} metric={metric} size="sm" />
70
- ))}
71
- </div>
61
+ <CardHeader>
62
+ {title && <CardTitle>{title}</CardTitle>}
63
+ {description && <CardDescription>{description}</CardDescription>}
64
+ </CardHeader>
72
65
  )}
73
-
74
- {/* Custom Content */}
75
- {children}
76
- </div>
66
+ <CardContent>
67
+ {chart && <AnalyticsChart config={chart} />}
68
+ {metrics && metrics.length > 0 && (
69
+ <div className="udb-analytics-card__metrics">
70
+ {metrics.map((metric) => (
71
+ <MetricCard key={metric.id} metric={metric} size="sm" />
72
+ ))}
73
+ </div>
74
+ )}
75
+ {children}
76
+ </CardContent>
77
+ </Card>
77
78
  );
78
79
  };
79
80