@umituz/web-dashboard 3.2.4 → 4.0.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.
- package/README.md +202 -14
- package/package.json +21 -29
- package/src/domains/analytics/components/AnalyticsCard.tsx +23 -21
- package/src/domains/analytics/components/AnalyticsChart.tsx +345 -149
- package/src/domains/analytics/components/AnalyticsLayout.tsx +93 -112
- package/src/domains/analytics/components/MetricCard.tsx +42 -64
- package/src/domains/analytics/hooks/index.ts +7 -1
- package/src/domains/analytics/hooks/useAnalytics.ts +144 -139
- package/src/domains/analytics/index.ts +11 -0
- package/src/domains/analytics/services/AnalyticsEngineService.ts +103 -55
- package/src/domains/analytics/services/PerformanceService.ts +117 -69
- package/src/domains/analytics/types/analytics.ts +20 -6
- package/src/domains/analytics/types/index.ts +3 -0
- package/src/domains/analytics/utils/analytics.test.ts +183 -0
- package/src/domains/analytics/utils/analytics.ts +26 -9
- package/src/domains/analytics/utils/i18nKeys.ts +40 -0
- package/src/domains/analytics/utils/index.ts +2 -0
- package/src/domains/auth/components/AuthLayout.tsx +63 -54
- package/src/domains/auth/components/ForgotPasswordForm.tsx +96 -98
- package/src/domains/auth/components/LoginForm.tsx +167 -226
- package/src/domains/auth/components/RegisterForm.tsx +202 -272
- package/src/domains/auth/components/ResetPasswordForm.tsx +105 -151
- package/src/domains/auth/components/shared/AuthErrorBanner.tsx +35 -0
- package/src/domains/auth/components/shared/EmailInput.tsx +91 -0
- package/src/domains/auth/components/shared/PasswordInput.tsx +119 -0
- package/src/domains/auth/components/shared/PasswordStrengthIndicator.tsx +75 -0
- package/src/domains/auth/components/shared/SocialLoginButtons.tsx +58 -0
- package/src/domains/auth/components/shared/SocialProviderIcons.tsx +48 -0
- package/src/domains/auth/components/shared/index.ts +20 -0
- package/src/domains/auth/hooks/index.ts +1 -0
- package/src/domains/auth/hooks/useAuth.ts +151 -232
- package/src/domains/auth/index.ts +8 -4
- package/src/domains/auth/types/auth.ts +26 -5
- package/src/domains/auth/types/index.ts +1 -0
- package/src/domains/auth/utils/auth.test.ts +182 -0
- package/src/domains/auth/utils/auth.ts +71 -130
- package/src/domains/auth/utils/i18nKeys.ts +127 -0
- package/src/domains/auth/utils/index.ts +7 -1
- package/src/domains/auth/utils/secureToken.ts +33 -0
- package/src/domains/auth/utils/validationKeys.ts +23 -0
- package/src/domains/calendar/hooks/useCalendar.ts +145 -151
- package/src/domains/calendar/index.ts +0 -1
- package/src/domains/calendar/services/CalendarService.ts +122 -179
- package/src/domains/calendar/utils/contentItemMapper.test.ts +108 -0
- package/src/domains/calendar/utils/contentItemMapper.ts +99 -0
- package/src/domains/calendar/utils/index.ts +33 -30
- package/src/domains/layouts/components/BrandLogo.tsx +12 -9
- package/src/domains/layouts/components/DashboardHeader.tsx +78 -80
- package/src/domains/layouts/components/DashboardLayout.tsx +45 -21
- package/src/domains/layouts/components/DashboardSidebar.tsx +48 -51
- package/src/domains/layouts/types/layout.ts +7 -1
- package/src/domains/layouts/types/user.ts +3 -1
- package/src/domains/modules/build.test.tsx +97 -0
- package/src/domains/modules/build.tsx +71 -0
- package/src/domains/modules/index.ts +2 -0
- package/src/domains/modules/types.ts +29 -0
- package/src/domains/onboarding/components/AppFocusStep.tsx +99 -68
- package/src/domains/onboarding/components/OnboardingWizard.tsx +109 -183
- package/src/domains/onboarding/components/PlanStep.tsx +156 -123
- package/src/domains/onboarding/components/PlatformsStep.tsx +74 -54
- package/src/domains/onboarding/components/StepNavigation.tsx +108 -0
- package/src/domains/onboarding/components/StepProgress.tsx +62 -0
- package/src/domains/onboarding/components/UserTypeStep.tsx +59 -80
- package/src/domains/onboarding/components/index.ts +4 -0
- package/src/domains/onboarding/hooks/useOnboarding.ts +76 -66
- package/src/domains/onboarding/index.ts +1 -0
- package/src/domains/onboarding/types/onboarding.ts +57 -17
- package/src/domains/onboarding/utils/i18nKeys.ts +72 -0
- package/src/domains/onboarding/utils/index.ts +2 -0
- package/src/domains/permissions/PermissionsContext.tsx +103 -0
- package/src/domains/permissions/hasPermission.test.ts +50 -0
- package/src/domains/permissions/hasPermission.ts +38 -0
- package/src/domains/permissions/index.ts +19 -0
- package/src/domains/permissions/types.ts +35 -0
- package/src/domains/permissions/utils/i18nKeys.ts +11 -0
- package/src/domains/session/DemoLogin.tsx +50 -0
- package/src/domains/session/OrgSwitcher.tsx +110 -0
- package/src/domains/session/SessionContext.tsx +150 -0
- package/src/domains/session/inMemoryAuthAdapter.ts +53 -0
- package/src/domains/session/index.ts +18 -0
- package/src/domains/session/types.ts +47 -0
- package/src/domains/session/utils/i18nKeys.ts +12 -0
- package/src/domains/settings/components/AuditLogList.tsx +59 -0
- package/src/domains/settings/components/PermissionMatrixScreen.tsx +80 -0
- package/src/domains/settings/components/SettingsLayout.tsx +75 -60
- package/src/domains/settings/components/SettingsSection.tsx +35 -22
- package/src/domains/settings/components/UserManagementTable.tsx +87 -0
- package/src/domains/settings/components/index.ts +10 -0
- package/src/domains/settings/hooks/useSettings.ts +77 -52
- package/src/domains/settings/types/settings.ts +2 -0
- package/src/domains/settings/utils/i18nKeys.ts +18 -0
- package/src/domains/settings/utils/settings.ts +11 -4
- package/src/i18n/I18nContext.tsx +33 -0
- package/src/i18n/defaultT.test.ts +43 -0
- package/src/i18n/defaultT.ts +34 -0
- package/src/i18n/index.ts +7 -0
- package/src/i18n/types.ts +13 -0
- package/src/index.ts +1 -7
- package/src/primitives/Button.tsx +30 -0
- package/src/primitives/Checkbox.tsx +40 -0
- package/src/primitives/Input.tsx +19 -0
- package/src/primitives/Skeleton.tsx +26 -0
- package/src/primitives/cn.ts +15 -0
- package/src/primitives/index.ts +23 -0
- package/src/styles/dashboard.css +3045 -0
- package/src/styles/tokens.contract.test.ts +66 -0
- package/src/styles/tokens.css +124 -0
- package/src/domains/billing/components/BillingLayout.tsx +0 -63
- package/src/domains/billing/components/BillingPage.tsx +0 -49
- package/src/domains/billing/components/BillingPortal.tsx +0 -198
- package/src/domains/billing/components/InvoiceCard.tsx +0 -143
- package/src/domains/billing/components/PaymentMethodsList.tsx +0 -116
- package/src/domains/billing/components/PlanComparison.tsx +0 -199
- package/src/domains/billing/components/UsageCard.tsx +0 -103
- package/src/domains/billing/components/index.ts +0 -13
- package/src/domains/billing/constants/billing.ts +0 -69
- package/src/domains/billing/hooks/index.ts +0 -7
- package/src/domains/billing/hooks/useBilling.ts +0 -385
- package/src/domains/billing/index.ts +0 -73
- package/src/domains/billing/types/billing.ts +0 -342
- package/src/domains/billing/types/index.ts +0 -30
- package/src/domains/billing/utils/billing.ts +0 -360
- package/src/domains/billing/utils/index.ts +0 -31
- package/src/domains/billing/utils/polar.ts +0 -63
- package/src/domains/calendar/components/index.ts +0 -7
package/README.md
CHANGED
|
@@ -1,32 +1,220 @@
|
|
|
1
1
|
# @umituz/web-dashboard
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
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
|
-
|
|
8
|
-
|
|
9
|
-
-
|
|
10
|
-
|
|
11
|
-
-
|
|
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
|
+
- **`@umituz/web-design-system` is no longer a dependency.** The primitives
|
|
18
|
+
(`Button`, `Input`, `Checkbox`, `Skeleton`, `cn`) live in `./primitives`.
|
|
19
|
+
- **Styling is shipped, not assumed.** Import `@umituz/web-dashboard/styles.css`
|
|
20
|
+
(and optionally `tokens.css`) once; all components use `udb-*` BEM classes.
|
|
21
|
+
Tailwind, design-system tokens and utility classes are gone from the package.
|
|
22
|
+
- **No i18n runtime.** `react-i18next` is out; hosts bridge their own `t` via
|
|
23
|
+
`<DashboardI18nProvider t={i18n.t}>` (see below). Without a provider,
|
|
24
|
+
keys humanize to readable English.
|
|
25
|
+
- **No Firebase.** The calendar persists through the injected
|
|
26
|
+
`ICalendarDatabase` seam; `createInMemoryCalendarDatabase()` is the default.
|
|
27
|
+
- **recharts is out.** `AnalyticsChart` renders line/area/bar/pie/donut as
|
|
28
|
+
dependency-free SVG with native `<title>` tooltips.
|
|
29
|
+
- **New fleet modules**: `./permissions`, `./session`, `./modules` — the
|
|
30
|
+
texora/visora pattern (one module list drives routes + nav + guards) as
|
|
31
|
+
reusable building blocks.
|
|
12
32
|
|
|
13
33
|
## Installation
|
|
14
34
|
|
|
15
35
|
```bash
|
|
16
36
|
npm install @umituz/web-dashboard
|
|
37
|
+
import "@umituz/web-dashboard/styles.css";
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Peers: `react` + `react-dom` (^18 or ^19) and `react-router-dom` (^6 or ^7).
|
|
41
|
+
Runtime deps: `clsx` + `lucide-react`. Nothing else.
|
|
42
|
+
|
|
43
|
+
### Tailwind hosts
|
|
44
|
+
|
|
45
|
+
Every `udb-*` rule sets its own `box-sizing`/`background`/`border` explicitly,
|
|
46
|
+
so preflight cannot leak in — but load order still matters with `*`-selector
|
|
47
|
+
resets: import the package stylesheet **after** your base layer.
|
|
48
|
+
|
|
49
|
+
### Theming & dark mode
|
|
50
|
+
|
|
51
|
+
Override the `--u-*` custom properties (see `tokens.css` for the full list).
|
|
52
|
+
Dark mode is host-driven: put `data-udb-theme="dark"` on any ancestor.
|
|
53
|
+
|
|
54
|
+
## Entry points
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
@umituz/web-dashboard/styles.css # component stylesheet (udb-* BEM)
|
|
58
|
+
@umituz/web-dashboard/tokens.css # --u-* custom properties only
|
|
59
|
+
@umituz/web-dashboard/primitives # Button, Input, Checkbox, Skeleton, cn
|
|
60
|
+
@umituz/web-dashboard/i18n # DashboardI18nProvider, useT, defaultT
|
|
61
|
+
@umituz/web-dashboard/permissions # PermissionMatrix, hasPermission, guards
|
|
62
|
+
@umituz/web-dashboard/session # AuthAdapter, SessionProvider, OrgSwitcher, DemoLogin
|
|
63
|
+
@umituz/web-dashboard/modules # DashboardModule, buildRoutes, buildNav
|
|
64
|
+
@umituz/web-dashboard/layouts # DashboardLayout, DashboardSidebar, DashboardHeader
|
|
65
|
+
@umituz/web-dashboard/settings # SettingsLayout, admin skeletons (users, matrix, audit)
|
|
66
|
+
@umituz/web-dashboard/onboarding # OnboardingWizard + steps, useOnboarding
|
|
67
|
+
@umituz/web-dashboard/auth # Login/Register/Forgot/Reset forms, AuthLayout
|
|
68
|
+
@umituz/web-dashboard/analytics # AnalyticsLayout, SVG AnalyticsChart, services
|
|
69
|
+
@umituz/web-dashboard/calendar # useCalendar, CalendarService (injected DB)
|
|
70
|
+
@umituz/web-dashboard/config # dashboard config helpers
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Each domain also exposes `components`, `hooks`, `utils`, `types`
|
|
74
|
+
sub-entries (and `services` for analytics/calendar). The new v4 modules
|
|
75
|
+
(`permissions`, `session`, `modules`) are **deep-entry only** — they are not
|
|
76
|
+
re-exported from the root, so router-less hosts never pull router code in
|
|
77
|
+
transitively.
|
|
78
|
+
|
|
79
|
+
## The v4 composition
|
|
80
|
+
|
|
81
|
+
A host app assembles the skeleton from four seams:
|
|
82
|
+
|
|
83
|
+
```tsx
|
|
84
|
+
import { DashboardI18nProvider } from "@umituz/web-dashboard/i18n";
|
|
85
|
+
import { SessionProvider, createInMemoryAuthAdapter } from "@umituz/web-dashboard/session";
|
|
86
|
+
import { PermissionsProvider } from "@umituz/web-dashboard/permissions";
|
|
87
|
+
|
|
88
|
+
const adapter = createInMemoryAuthAdapter({ users: DEMO_USERS });
|
|
89
|
+
|
|
90
|
+
<DashboardI18nProvider t={i18n.t}>
|
|
91
|
+
<SessionProvider adapter={adapter}>
|
|
92
|
+
<PermissionsProvider matrix={ROLE_PERMISSIONS} role={user?.role}>
|
|
93
|
+
<App />
|
|
94
|
+
</PermissionsProvider>
|
|
95
|
+
</SessionProvider>
|
|
96
|
+
</DashboardI18nProvider>
|
|
17
97
|
```
|
|
18
98
|
|
|
19
|
-
|
|
99
|
+
### One module list → routes + nav + guards
|
|
100
|
+
|
|
101
|
+
```tsx
|
|
102
|
+
import { buildRoutes, buildNav } from "@umituz/web-dashboard/modules";
|
|
103
|
+
import { usePermissions } from "@umituz/web-dashboard/permissions";
|
|
20
104
|
|
|
21
|
-
|
|
22
|
-
|
|
105
|
+
const MODULES: DashboardModule[] = [
|
|
106
|
+
{ path: "/dashboard", labelKey: "nav.dashboard", icon: LayoutDashboard,
|
|
107
|
+
navGroup: "nav.overview", order: 1, permission: "dashboard.view",
|
|
108
|
+
element: <DashboardPage /> },
|
|
109
|
+
{ path: "/sales/:id", labelKey: "nav.salesDetail", icon: Circle,
|
|
110
|
+
navGroup: "nav.commercial", inNav: false, permission: "sales.view",
|
|
111
|
+
element: <SalesDetailPage /> },
|
|
112
|
+
];
|
|
23
113
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
114
|
+
// routes: element pre-wrapped in <RequirePermission>
|
|
115
|
+
const routes = buildRoutes(MODULES); // -> <Route path key={...} {...route} />
|
|
116
|
+
|
|
117
|
+
// nav: permission-filtered, grouped, ordered -> feed DashboardLayout config
|
|
118
|
+
const { can } = usePermissions();
|
|
119
|
+
const sidebarGroups = buildNav(MODULES, { can });
|
|
28
120
|
```
|
|
29
121
|
|
|
122
|
+
Groups keep their first-appearance order in the list; `order` sorts items
|
|
123
|
+
within a group; `inNav: false` hides detail routes from the sidebar.
|
|
124
|
+
|
|
125
|
+
### Permissions
|
|
126
|
+
|
|
127
|
+
`hasPermission(matrix, role, permission)` is pure and deny-by-default.
|
|
128
|
+
Matrix grants are `"*"` (everything), `"sales.*"` (module wildcard) or exact
|
|
129
|
+
strings. `<RequirePermission permission>` guards pages (lock screen
|
|
130
|
+
fallback); `<Can>` is its inline twin.
|
|
131
|
+
|
|
132
|
+
### Session
|
|
133
|
+
|
|
134
|
+
Hosts adapt their auth to `AuthAdapter` (`login`/`logout`/`current`;
|
|
135
|
+
`listTenants`/`demoLogin` optional). `useSession()` exposes user, tenants,
|
|
136
|
+
active tenant, status + `switchTenant`. `OrgSwitcher` renders the tenant
|
|
137
|
+
dropdown; `DemoLogin` the one-click demo entry.
|
|
138
|
+
|
|
139
|
+
### Calendar
|
|
140
|
+
|
|
141
|
+
```tsx
|
|
142
|
+
import { CalendarService, createInMemoryCalendarDatabase } from "@umituz/web-dashboard/calendar/services";
|
|
143
|
+
|
|
144
|
+
// Bring your own backend:
|
|
145
|
+
class MyDatabase implements ICalendarDatabase { /* ... */ }
|
|
146
|
+
const service = new CalendarService(new MyDatabase());
|
|
147
|
+
// or demo/test:
|
|
148
|
+
const demo = new CalendarService(createInMemoryCalendarDatabase());
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Analytics
|
|
152
|
+
|
|
153
|
+
`AnalyticsChart` consumes the same `ChartConfig` as v3 for
|
|
154
|
+
line/area/bar/pie/donut. Tooltips are native SVG `<title>` elements;
|
|
155
|
+
legends are color chips; unsupported types render an empty state.
|
|
156
|
+
`useAnalytics` stays dependency-injected (`createStubAnalyticsApiClient`).
|
|
157
|
+
|
|
158
|
+
## i18n contract
|
|
159
|
+
|
|
160
|
+
Components render **i18n keys**, never English strings. Bridge your runtime
|
|
161
|
+
once:
|
|
162
|
+
|
|
163
|
+
```tsx
|
|
164
|
+
import { DashboardI18nProvider } from "@umituz/web-dashboard/i18n";
|
|
165
|
+
|
|
166
|
+
<DashboardI18nProvider t={i18n.t}> {/* i18next's t — signature already matches */}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Interpolation uses the standard `{{placeholder}}` syntax. Without a
|
|
170
|
+
provider, `useT()` falls back to `defaultT`, which humanizes keys
|
|
171
|
+
(`auth.login.welcomeBack` → "Welcome back") so a bare install still renders
|
|
172
|
+
readably. The per-domain key catalogs are the string contract:
|
|
173
|
+
|
|
174
|
+
```ts
|
|
175
|
+
import { AUTH_KEYS } from "@umituz/web-dashboard/auth";
|
|
176
|
+
import { ANALYTICS_KEYS } from "@umituz/web-dashboard/analytics";
|
|
177
|
+
import { ONBOARDING_KEYS } from "@umituz/web-dashboard/onboarding";
|
|
178
|
+
import { SETTINGS_ADMIN_KEYS } from "@umituz/web-dashboard/settings/utils/i18nKeys";
|
|
179
|
+
import { PERMISSIONS_KEYS } from "@umituz/web-dashboard/permissions";
|
|
180
|
+
import { SESSION_KEYS } from "@umituz/web-dashboard/session";
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Platform compatibility
|
|
184
|
+
|
|
185
|
+
- React 18 and 19, react-router-dom 6 and 7
|
|
186
|
+
- `generateResetToken` requires `crypto.getRandomValues` (all modern browsers,
|
|
187
|
+
Node ≥ 19) and **throws** rather than falling back to an insecure PRNG
|
|
188
|
+
- Rendering targets the DOM; React Native is not supported
|
|
189
|
+
|
|
190
|
+
## Development
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
npm install
|
|
194
|
+
npm run lint # eslint
|
|
195
|
+
npm run typecheck # tsc --noEmit
|
|
196
|
+
npm test # vitest unit tests (pure utils + module builders)
|
|
197
|
+
npm run test:watch
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
CI runs lint + typecheck + test on every push/PR to `main`.
|
|
201
|
+
|
|
202
|
+
## Migration: 3.x → 4.0
|
|
203
|
+
|
|
204
|
+
1. Billing UI: switch imports to `@umituz/web-polar-payment/portal`.
|
|
205
|
+
2. Design-system imports: use `@umituz/web-dashboard/primitives`
|
|
206
|
+
(`Button`/`Input`/`Checkbox`/`Skeleton` cover the used surface).
|
|
207
|
+
3. Styling: import `styles.css` once; Tailwind utility classes no longer
|
|
208
|
+
exist inside the package. Config values that used to carry Tailwind
|
|
209
|
+
strings changed: `PlatformOption.color` is a plain CSS color string,
|
|
210
|
+
`PlanOption.badgeColor` became `badgeTone: "muted" | "primary" | "accent"`.
|
|
211
|
+
4. i18n: wrap your app in `DashboardI18nProvider t={i18n.t}`; the
|
|
212
|
+
`react-i18next` peer is gone.
|
|
213
|
+
5. Calendar: pass your own `ICalendarDatabase` (or the in-memory default);
|
|
214
|
+
the Firebase implementation was removed.
|
|
215
|
+
6. v3.2.5 behavioral notes still apply (opt-in mock auth, route skeletons
|
|
216
|
+
off by default, `PerformanceService.startMonitoring()` explicit).
|
|
217
|
+
|
|
30
218
|
## License
|
|
31
219
|
|
|
32
220
|
MIT
|
package/package.json
CHANGED
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/web-dashboard",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "4.0.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":
|
|
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,21 @@
|
|
|
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
74
|
"clsx": "^2.1.1",
|
|
72
|
-
"lucide-react": "^0.577.0"
|
|
73
|
-
"recharts": "^2.15.0",
|
|
74
|
-
"tailwind-merge": "^3.5.0"
|
|
75
|
+
"lucide-react": "^0.577.0"
|
|
75
76
|
},
|
|
76
77
|
"devDependencies": {
|
|
77
78
|
"@types/react": "^19.2.14",
|
|
78
79
|
"@types/react-dom": "^19.2.3",
|
|
79
80
|
"@typescript-eslint/eslint-plugin": "^8.57.2",
|
|
80
81
|
"@typescript-eslint/parser": "^8.57.2",
|
|
81
|
-
"@umituz/web-design-system": "^3.1.11",
|
|
82
|
-
"@umituz/web-firebase": "^3.6.0",
|
|
83
82
|
"eslint": "^10.0.2",
|
|
84
|
-
"firebase": "^12.0.0",
|
|
85
|
-
"react-i18next": "^16.5.4",
|
|
86
83
|
"react-router-dom": "^7.13.1",
|
|
87
|
-
"typescript": "^5.9.3"
|
|
84
|
+
"typescript": "^5.9.3",
|
|
85
|
+
"vitest": "^5.0.1"
|
|
88
86
|
},
|
|
89
87
|
"keywords": [
|
|
90
88
|
"dashboard",
|
|
@@ -113,13 +111,7 @@
|
|
|
113
111
|
"metrics",
|
|
114
112
|
"kpi",
|
|
115
113
|
"visualization",
|
|
116
|
-
"
|
|
117
|
-
"billing",
|
|
118
|
-
"subscription",
|
|
119
|
-
"payment",
|
|
120
|
-
"invoices",
|
|
121
|
-
"pricing",
|
|
122
|
-
"plans",
|
|
114
|
+
"svg-charts",
|
|
123
115
|
"react",
|
|
124
116
|
"typescript",
|
|
125
117
|
"components",
|
|
@@ -1,15 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Analytics Card Component
|
|
3
3
|
*
|
|
4
|
-
* Configurable analytics card with chart or metrics
|
|
4
|
+
* Configurable analytics card with chart or metrics. Surface comes
|
|
5
|
+
* from the shared `udb-card` helper; size modifiers shrink/grow the
|
|
6
|
+
* padding ("full" shares the md default).
|
|
5
7
|
*/
|
|
6
8
|
|
|
7
9
|
import { Loader2, AlertCircle } from "lucide-react";
|
|
8
|
-
import { cn } from "
|
|
10
|
+
import { cn } from "../../../primitives";
|
|
9
11
|
import type { AnalyticsCardProps } from "../types/analytics";
|
|
10
12
|
import { MetricCard } from "./MetricCard";
|
|
11
13
|
import { AnalyticsChart } from "./AnalyticsChart";
|
|
12
14
|
|
|
15
|
+
const SURFACE_CLASS = {
|
|
16
|
+
sm: 'udb-card--sm',
|
|
17
|
+
md: undefined,
|
|
18
|
+
lg: 'udb-card--lg',
|
|
19
|
+
full: undefined,
|
|
20
|
+
} as const;
|
|
21
|
+
|
|
13
22
|
export const AnalyticsCard = ({
|
|
14
23
|
title,
|
|
15
24
|
description,
|
|
@@ -21,18 +30,11 @@ export const AnalyticsCard = ({
|
|
|
21
30
|
className,
|
|
22
31
|
children,
|
|
23
32
|
}: AnalyticsCardProps) => {
|
|
24
|
-
const sizeClasses = {
|
|
25
|
-
sm: "p-4",
|
|
26
|
-
md: "p-6",
|
|
27
|
-
lg: "p-8",
|
|
28
|
-
full: "p-6",
|
|
29
|
-
};
|
|
30
|
-
|
|
31
33
|
if (loading) {
|
|
32
34
|
return (
|
|
33
|
-
<div className={cn("
|
|
34
|
-
<div className="
|
|
35
|
-
<Loader2 className="
|
|
35
|
+
<div className={cn("udb-card", SURFACE_CLASS[size], className)}>
|
|
36
|
+
<div className="udb-analytics-card__status" role="status">
|
|
37
|
+
<Loader2 className="udb-spin udb-analytics-card__spinner" aria-hidden="true" />
|
|
36
38
|
</div>
|
|
37
39
|
</div>
|
|
38
40
|
);
|
|
@@ -40,22 +42,22 @@ export const AnalyticsCard = ({
|
|
|
40
42
|
|
|
41
43
|
if (error) {
|
|
42
44
|
return (
|
|
43
|
-
<div className={cn("
|
|
44
|
-
<div className="
|
|
45
|
-
<AlertCircle className="
|
|
46
|
-
<p className="text
|
|
45
|
+
<div className={cn("udb-card", SURFACE_CLASS[size], className)}>
|
|
46
|
+
<div className="udb-analytics-card__status udb-analytics-card__status--error" role="alert">
|
|
47
|
+
<AlertCircle className="udb-analytics-card__error-icon" aria-hidden="true" />
|
|
48
|
+
<p className="udb-analytics-card__error-text">{error}</p>
|
|
47
49
|
</div>
|
|
48
50
|
</div>
|
|
49
51
|
);
|
|
50
52
|
}
|
|
51
53
|
|
|
52
54
|
return (
|
|
53
|
-
<div className={cn("
|
|
55
|
+
<div className={cn("udb-card", SURFACE_CLASS[size], className)}>
|
|
54
56
|
{/* Header */}
|
|
55
57
|
{(title || description) && (
|
|
56
|
-
<div className="
|
|
57
|
-
{title && <h3 className="
|
|
58
|
-
{description && <p className="
|
|
58
|
+
<div className="udb-analytics-card__header">
|
|
59
|
+
{title && <h3 className="udb-analytics-card__title">{title}</h3>}
|
|
60
|
+
{description && <p className="udb-analytics-card__description">{description}</p>}
|
|
59
61
|
</div>
|
|
60
62
|
)}
|
|
61
63
|
|
|
@@ -64,7 +66,7 @@ export const AnalyticsCard = ({
|
|
|
64
66
|
|
|
65
67
|
{/* Metrics */}
|
|
66
68
|
{metrics && metrics.length > 0 && (
|
|
67
|
-
<div className="
|
|
69
|
+
<div className="udb-analytics-card__metrics">
|
|
68
70
|
{metrics.map((metric) => (
|
|
69
71
|
<MetricCard key={metric.id} metric={metric} size="sm" />
|
|
70
72
|
))}
|