@umituz/web-dashboard 4.7.1 → 5.0.1

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 (49) hide show
  1. package/README.md +63 -88
  2. package/package.json +5 -7
  3. package/src/domains/analytics/components/AnalyticsCard.tsx +1 -6
  4. package/src/domains/analytics/components/AnalyticsChart.tsx +2 -14
  5. package/src/domains/analytics/components/AnalyticsLayout.tsx +3 -17
  6. package/src/domains/analytics/components/MetricCard.tsx +1 -6
  7. package/src/domains/analytics/utils/i18nKeys.ts +0 -9
  8. package/src/domains/auth/components/AuthLayout.tsx +1 -26
  9. package/src/domains/auth/components/ForgotPasswordForm.tsx +2 -14
  10. package/src/domains/auth/components/LoginForm.tsx +2 -15
  11. package/src/domains/auth/components/RegisterForm.tsx +3 -14
  12. package/src/domains/auth/components/ResetPasswordForm.tsx +3 -14
  13. package/src/domains/auth/components/shared/AuthErrorBanner.tsx +1 -11
  14. package/src/domains/auth/components/shared/EmailInput.tsx +2 -20
  15. package/src/domains/auth/components/shared/PasswordInput.tsx +3 -22
  16. package/src/domains/auth/components/shared/PasswordStrengthIndicator.tsx +1 -13
  17. package/src/domains/auth/components/shared/SocialLoginButtons.tsx +1 -15
  18. package/src/domains/auth/utils/i18nKeys.ts +0 -18
  19. package/src/domains/charts/components.tsx +2 -2
  20. package/src/domains/layouts/components/BrandLogo.tsx +7 -22
  21. package/src/domains/layouts/components/DashboardHeader.tsx +2 -23
  22. package/src/domains/layouts/components/DashboardLayout.tsx +2 -39
  23. package/src/domains/layouts/components/DashboardSidebar.tsx +3 -21
  24. package/src/domains/permissions/PermissionsContext.tsx +1 -17
  25. package/src/domains/permissions/utils/i18nKeys.ts +0 -5
  26. package/src/domains/session/DemoLogin.tsx +2 -10
  27. package/src/domains/session/OrgSwitcher.tsx +2 -10
  28. package/src/domains/settings/components/AuditLogList.tsx +1 -10
  29. package/src/domains/settings/components/PermissionMatrixScreen.tsx +1 -8
  30. package/src/domains/settings/components/SettingsLayout.tsx +1 -21
  31. package/src/domains/settings/components/SettingsSection.tsx +1 -13
  32. package/src/domains/settings/components/UserManagementTable.tsx +1 -8
  33. package/src/domains/settings/utils/i18nKeys.ts +0 -6
  34. package/src/index.ts +0 -17
  35. package/src/styles/dashboard.contract.test.ts +42 -0
  36. package/src/styles/dashboard.css +492 -920
  37. package/src/i18n/I18nContext.tsx +0 -33
  38. package/src/i18n/defaultT.test.ts +0 -43
  39. package/src/i18n/defaultT.ts +0 -34
  40. package/src/i18n/index.ts +0 -7
  41. package/src/i18n/types.ts +0 -13
  42. package/src/primitives/Button.tsx +0 -24
  43. package/src/primitives/Checkbox.tsx +0 -17
  44. package/src/primitives/Input.tsx +0 -23
  45. package/src/primitives/Skeleton.tsx +0 -6
  46. package/src/primitives/cn.ts +0 -10
  47. package/src/primitives/index.ts +0 -23
  48. package/src/styles/tokens.contract.test.ts +0 -91
  49. package/src/styles/tokens.css +0 -116
@@ -1,36 +1,18 @@
1
- /**
2
- * EmailInput
3
- *
4
- * Standardized email input used across all auth forms.
5
- * Renders label, input, error state, and disabled state consistently.
6
- */
7
-
8
1
  import { forwardRef } from "react";
9
- import { Input } from "../../../../primitives";
10
- import { cn } from "../../../../primitives";
2
+ import { Input } from "@umituz/web-design-system/atoms";
3
+ import { cn } from "@umituz/web-design-system/utils/cn";
11
4
 
12
5
  export interface EmailInputProps {
13
- /** Input id (used to wire up the label) */
14
6
  id: string;
15
- /** Label i18n key — resolved via `translate` */
16
7
  labelKey: string;
17
- /** Placeholder i18n key */
18
8
  placeholderKey: string;
19
- /** Current value */
20
9
  value: string;
21
- /** Change handler */
22
10
  onChange: (value: string) => void;
23
- /** Translation function */
24
11
  translate: (key: string) => string;
25
- /** Auto-complete hint (default: "email") */
26
12
  autoComplete?: string;
27
- /** Disable the input */
28
13
  disabled?: boolean;
29
- /** Whether to mark the field as required (renders an asterisk) */
30
14
  required?: boolean;
31
- /** Optional error message to display below the field */
32
15
  error?: string | null;
33
- /** Custom className */
34
16
  className?: string;
35
17
  }
36
18
 
@@ -1,39 +1,20 @@
1
- /**
2
- * PasswordInput
3
- *
4
- * Password field with show/hide toggle, used across all auth forms.
5
- * Centralizes the visibility toggle, autoComplete, and label structure
6
- * so individual forms can stay focused on their unique concerns.
7
- */
8
-
9
1
  import { forwardRef, useState } from "react";
10
2
  import { Eye, EyeOff } from "lucide-react";
11
- import { Input } from "../../../../primitives";
12
- import { Button } from "../../../../primitives";
13
- import { cn } from "../../../../primitives";
3
+ import { Input } from "@umituz/web-design-system/atoms";
4
+ import { Button } from "@umituz/web-design-system/atoms";
5
+ import { cn } from "@umituz/web-design-system/utils/cn";
14
6
 
15
7
  export interface PasswordInputProps {
16
- /** Input id (used to wire up the label) */
17
8
  id: string;
18
- /** Label i18n key */
19
9
  labelKey: string;
20
- /** Placeholder i18n key */
21
10
  placeholderKey: string;
22
- /** Current value */
23
11
  value: string;
24
- /** Change handler */
25
12
  onChange: (value: string) => void;
26
- /** Translation function */
27
13
  translate: (key: string) => string;
28
- /** Auto-complete hint (e.g., "current-password", "new-password") */
29
14
  autoComplete?: string;
30
- /** Disable the input */
31
15
  disabled?: boolean;
32
- /** Whether to mark the field as required (renders an asterisk) */
33
16
  required?: boolean;
34
- /** Optional error message to display below the field */
35
17
  error?: string | null;
36
- /** Custom className */
37
18
  className?: string;
38
19
  }
39
20
 
@@ -1,16 +1,6 @@
1
- /**
2
- * PasswordStrengthIndicator
3
- *
4
- * Renders a 4-segment strength bar plus a localized label band.
5
- * The label i18n key is computed from the strength band so the
6
- * component stays free of hardcoded strings. Bar/label colors come
7
- * from `--u-*` tones (weak/danger, fair/warning-2, good/warning,
8
- * strong/success).
9
- */
10
-
11
1
  import { useMemo } from "react";
12
2
  import { calculatePasswordStrength } from "../../utils/auth";
13
- import { cn } from "../../../../primitives";
3
+ import { cn } from "@umituz/web-design-system/utils/cn";
14
4
 
15
5
  const STRENGTH_KEYS = {
16
6
  weak: 'auth.passwordStrength.weak',
@@ -29,9 +19,7 @@ const scoreToBand = (score: number): StrengthBand => {
29
19
  };
30
20
 
31
21
  export interface PasswordStrengthIndicatorProps {
32
- /** Password to evaluate */
33
22
  password: string;
34
- /** Translation function */
35
23
  translate: (key: string) => string;
36
24
  }
37
25
 
@@ -1,28 +1,14 @@
1
- /**
2
- * SocialLoginButtons
3
- *
4
- * Renders a list of social auth providers as a row of icon buttons.
5
- * Generic over the provider id so adding a new provider is a config change,
6
- * not a code change.
7
- */
8
-
9
- import { Button } from "../../../../primitives";
1
+ import { Button } from "@umituz/web-design-system/atoms";
10
2
  import { GoogleIcon, AppleIcon } from "./SocialProviderIcons";
11
3
 
12
4
  export type SocialProviderId = 'google' | 'apple';
13
5
 
14
6
  export interface SocialLoginButtonsProps {
15
- /** Provider handlers keyed by provider id */
16
7
  onProvider: (id: SocialProviderId) => void;
17
- /** Translation function */
18
8
  translate: (key: string) => string;
19
- /** Disable all buttons (e.g., during form submission) */
20
9
  disabled?: boolean;
21
10
  }
22
11
 
23
- /**
24
- * Centralized provider config. Add new providers here and the UI follows.
25
- */
26
12
  const SOCIAL_PROVIDERS: ReadonlyArray<{
27
13
  id: SocialProviderId;
28
14
  labelKey: string;
@@ -1,13 +1,4 @@
1
- /**
2
- * Auth Domain i18n Keys
3
- *
4
- * Centralized catalog of i18n keys used across auth components.
5
- * Components stay free of hardcoded strings and consume these
6
- * constants — the consumer app provides the actual translations.
7
- */
8
-
9
1
  export const AUTH_KEYS = {
10
- // Login screen
11
2
  login: {
12
3
  welcomeBack: 'auth.login.welcomeBack',
13
4
  signInTo: 'auth.login.signInTo',
@@ -20,7 +11,6 @@ export const AUTH_KEYS = {
20
11
  orContinueWith: 'auth.login.orContinueWith',
21
12
  },
22
13
 
23
- // Register screen
24
14
  register: {
25
15
  createAccount: 'auth.register.createAccount',
26
16
  join: 'auth.register.join',
@@ -39,7 +29,6 @@ export const AUTH_KEYS = {
39
29
  passwordsDoNotMatch: 'auth.register.passwordsDoNotMatch',
40
30
  },
41
31
 
42
- // Forgot password
43
32
  forgotPassword: {
44
33
  title: 'auth.forgotPassword.title',
45
34
  description: 'auth.forgotPassword.description',
@@ -55,7 +44,6 @@ export const AUTH_KEYS = {
55
44
  step3: 'auth.forgotPassword.steps.step3',
56
45
  },
57
46
 
58
- // Reset password
59
47
  resetPassword: {
60
48
  title: 'auth.resetPassword.title',
61
49
  description: 'auth.resetPassword.description',
@@ -68,7 +56,6 @@ export const AUTH_KEYS = {
68
56
  goToSignIn: 'auth.resetPassword.goToSignIn',
69
57
  },
70
58
 
71
- // Shared fields
72
59
  fields: {
73
60
  email: 'auth.fields.email',
74
61
  password: 'auth.fields.password',
@@ -81,7 +68,6 @@ export const AUTH_KEYS = {
81
68
  fullName: 'auth.placeholders.fullName',
82
69
  },
83
70
 
84
- // Errors
85
71
  errors: {
86
72
  invalidCredentials: 'auth.errors.invalidCredentials',
87
73
  loginFailed: 'auth.errors.loginFailed',
@@ -96,7 +82,6 @@ export const AUTH_KEYS = {
96
82
  resetFailed: 'auth.errors.resetFailed',
97
83
  },
98
84
 
99
- // Password strength
100
85
  passwordStrength: {
101
86
  weak: 'auth.passwordStrength.weak',
102
87
  fair: 'auth.passwordStrength.fair',
@@ -104,20 +89,17 @@ export const AUTH_KEYS = {
104
89
  strong: 'auth.passwordStrength.strong',
105
90
  },
106
91
 
107
- // Social
108
92
  social: {
109
93
  continueWithGoogle: 'auth.social.continueWithGoogle',
110
94
  continueWithApple: 'auth.social.continueWithApple',
111
95
  },
112
96
 
113
- // Layout shell
114
97
  layout: {
115
98
  backToHome: 'auth.layout.backToHome',
116
99
  orContinueWith: 'auth.layout.orContinueWith',
117
100
  allRightsReserved: 'auth.layout.allRightsReserved',
118
101
  },
119
102
 
120
- // Accessibility
121
103
  a11y: {
122
104
  showPassword: 'auth.a11y.showPassword',
123
105
  hidePassword: 'auth.a11y.hidePassword',
@@ -244,7 +244,7 @@ export function Donut({
244
244
  cy={size / 2}
245
245
  r={radius}
246
246
  fill="none"
247
- stroke="var(--u-color-surface-muted)"
247
+ stroke="var(--color-muted)"
248
248
  strokeWidth={thickness}
249
249
  />
250
250
  {segments.map((seg, i) => {
@@ -454,7 +454,7 @@ export function LineChart({
454
454
  cx={xAt(i)}
455
455
  cy={yFn(v)}
456
456
  r={hover === i ? 3.4 : 0}
457
- fill="var(--u-color-surface)"
457
+ fill="var(--color-card)"
458
458
  stroke={toneOf(s, si)}
459
459
  strokeWidth={2}
460
460
  />
@@ -1,21 +1,10 @@
1
- import { cn } from "../../../primitives";
1
+ import { cn } from "@umituz/web-design-system/utils/cn";
2
2
 
3
3
  interface BrandLogoProps {
4
4
  className?: string;
5
5
  size?: number;
6
6
  }
7
7
 
8
- /**
9
- * BrandLogo Component
10
- *
11
- * Displays the application brand logo as an SVG.
12
- * Colors come from the package tokens (`--u-color-primary`,
13
- * `--u-color-secondary`) so hosts restyle it by overriding CSS
14
- * custom properties — no host theme variables required.
15
- *
16
- * @param className - Optional CSS classes for styling
17
- * @param size - Width and height in pixels (default: 32)
18
- */
19
8
  export const BrandLogo = ({ className, size = 32 }: BrandLogoProps) => {
20
9
  return (
21
10
  <svg
@@ -27,24 +16,22 @@ export const BrandLogo = ({ className, size = 32 }: BrandLogoProps) => {
27
16
  className={cn("udb-brand-logo", className)}
28
17
  aria-hidden="true"
29
18
  >
30
- {/* Solid Foundation / Platform */}
31
19
  <rect
32
20
  x="15"
33
21
  y="65"
34
22
  width="70"
35
23
  height="15"
36
24
  rx="4"
37
- fill="var(--u-color-primary)"
25
+ fill="var(--color-primary)"
38
26
  />
39
27
 
40
- {/* Assembly Paths / Structure */}
41
28
  <rect
42
29
  x="25"
43
30
  y="25"
44
31
  width="12"
45
32
  height="40"
46
33
  rx="2"
47
- fill="var(--u-color-primary)"
34
+ fill="var(--color-primary)"
48
35
  />
49
36
  <rect
50
37
  x="44"
@@ -52,7 +39,7 @@ export const BrandLogo = ({ className, size = 32 }: BrandLogoProps) => {
52
39
  width="12"
53
40
  height="30"
54
41
  rx="2"
55
- fill="var(--u-color-primary)"
42
+ fill="var(--color-primary)"
56
43
  />
57
44
  <rect
58
45
  x="63"
@@ -60,25 +47,23 @@ export const BrandLogo = ({ className, size = 32 }: BrandLogoProps) => {
60
47
  width="12"
61
48
  height="45"
62
49
  rx="2"
63
- fill="var(--u-color-primary)"
50
+ fill="var(--color-primary)"
64
51
  />
65
52
 
66
- {/* Modern Accent - The 'Assembly' Bridge */}
67
53
  <rect
68
54
  x="20"
69
55
  y="45"
70
56
  width="60"
71
57
  height="10"
72
58
  rx="2"
73
- fill="var(--u-color-secondary)"
59
+ fill="var(--color-secondary)"
74
60
  />
75
61
 
76
- {/* Connection Point / Beacon */}
77
62
  <circle
78
63
  cx="50"
79
64
  cy="20"
80
65
  r="5"
81
- fill="var(--u-color-secondary)"
66
+ fill="var(--color-secondary)"
82
67
  />
83
68
  </svg>
84
69
  );
@@ -3,43 +3,25 @@ import {
3
3
  Bell, X, Sun, Moon, Menu, User, Settings, LogOut,
4
4
  ChevronDown
5
5
  } from "lucide-react";
6
- import { Button } from "../../../primitives";
6
+ import { Button } from "@umituz/web-design-system/atoms";
7
7
  import { useNavigate } from "react-router-dom";
8
- import { useT } from "../../../i18n";
8
+ import { useT } from "@umituz/web-localization/react";
9
9
  import type { DashboardHeaderProps, HeaderProfileItem } from "../types/layout";
10
10
  import type { DashboardNotification } from "../types/notification";
11
11
  import type { DashboardUser } from "../types/user";
12
12
  import { formatNotificationTime } from "../utils/dashboard";
13
13
 
14
14
  interface DashboardHeaderPropsExtended extends DashboardHeaderProps {
15
- /** Auth user */
16
15
  user?: DashboardUser;
17
- /** Notifications */
18
16
  notifications?: DashboardNotification[];
19
- /** Logout function */
20
17
  onLogout?: () => Promise<void>;
21
- /** Mark all as read function */
22
18
  onMarkAllRead?: () => void;
23
- /** Dismiss notification function */
24
19
  onDismissNotification?: (id: string) => void;
25
- /** Settings route */
26
20
  settingsRoute?: string;
27
- /** Profile route */
28
21
  profileRoute?: string;
29
- /** Host-injected profile-menu entries — billing and friends live here,
30
- * not in the skeleton. */
31
22
  extraProfileItems?: HeaderProfileItem[];
32
23
  }
33
24
 
34
- /**
35
- * Dashboard Header Component
36
- *
37
- * Displays top navigation bar with theme toggle, notifications,
38
- * user menu, and organisation selector. Styling is entirely
39
- * `udb-header*` / `udb-menu*` classes from the package stylesheet.
40
- *
41
- * @param props - Dashboard header props
42
- */
43
25
  export const DashboardHeader = ({
44
26
  collapsed,
45
27
  setCollapsed,
@@ -72,7 +54,6 @@ export const DashboardHeader = ({
72
54
  await onLogout?.();
73
55
  navigate("/login");
74
56
  } catch {
75
- // Error handling can be added by parent component
76
57
  }
77
58
  };
78
59
 
@@ -93,7 +74,6 @@ export const DashboardHeader = ({
93
74
  </div>
94
75
 
95
76
  <div className="udb-header__actions">
96
- {/* Theme Toggle — rendered only when the host app wires it up */}
97
77
  {onToggleTheme && (
98
78
  <Button
99
79
  variant="ghost"
@@ -107,7 +87,6 @@ export const DashboardHeader = ({
107
87
  </Button>
108
88
  )}
109
89
 
110
- {/* Notifications */}
111
90
  <div className="udb-header__anchor">
112
91
  <Button
113
92
  variant="ghost"
@@ -1,7 +1,7 @@
1
1
  import { useState, useEffect } from "react";
2
2
  import { useLocation, Outlet, Navigate } from "react-router-dom";
3
- import { useT } from "../../../i18n";
4
- import { Skeleton } from "../../../primitives";
3
+ import { useT } from "@umituz/web-localization/react";
4
+ import { Skeleton } from "@umituz/web-design-system/atoms";
5
5
  import { DashboardSidebar } from "./DashboardSidebar";
6
6
  import { DashboardHeader } from "./DashboardHeader";
7
7
  import type { DashboardLayoutConfig } from "../types/layout";
@@ -9,54 +9,20 @@ import type { DashboardNotification } from "../types/notification";
9
9
  import type { DashboardUser } from "../types/user";
10
10
 
11
11
  interface DashboardLayoutProps {
12
- /** Layout configuration */
13
12
  config: DashboardLayoutConfig;
14
- /** Auth user */
15
13
  user?: DashboardUser;
16
- /** Auth loading state */
17
14
  authLoading?: boolean;
18
- /** Authenticated state */
19
15
  isAuthenticated?: boolean;
20
- /** Notifications */
21
16
  notifications?: DashboardNotification[];
22
- /** Logout function */
23
17
  onLogout?: () => Promise<void>;
24
- /** Mark all as read function */
25
18
  onMarkAllRead?: () => void;
26
- /** Dismiss notification function */
27
19
  onDismissNotification?: (id: string) => void;
28
- /** Login route for redirect */
29
20
  loginRoute?: string;
30
- /** Current theme, forwarded to the header toggle (default: "light") */
31
21
  theme?: "light" | "dark";
32
- /** Theme toggle handler — header toggle is hidden when omitted */
33
22
  onToggleTheme?: () => void;
34
- /**
35
- * Artificial route-transition skeleton duration in ms (default: 0 = off).
36
- * Content renders immediately by default; set > 0 only if you want
37
- * a skeleton to mask route swaps.
38
- */
39
23
  routeTransitionMs?: number;
40
24
  }
41
25
 
42
- /**
43
- * Dashboard Layout Component
44
- *
45
- * Main layout wrapper for dashboard pages.
46
- * Provides sidebar, header, and content area with responsive design.
47
- *
48
- * Features:
49
- * - Collapsible sidebar
50
- * - Mobile menu overlay
51
- * - Breadcrumb page titles
52
- * - Loading skeletons (opt-in via routeTransitionMs)
53
- * - Auth protection
54
- *
55
- * All styling comes from `udb-*` classes in the package stylesheet
56
- * (`@umituz/web-dashboard/styles.css`) — no utility framework required.
57
- *
58
- * @param props - Dashboard layout props
59
- */
60
26
  export const DashboardLayout = ({
61
27
  config,
62
28
  user,
@@ -109,7 +75,6 @@ export const DashboardLayout = ({
109
75
 
110
76
  return (
111
77
  <div className="udb-root udb-layout">
112
- {/* Desktop Sidebar */}
113
78
  <aside
114
79
  className={`udb-layout__sidebar ${collapsed ? "udb-layout__sidebar--collapsed" : ""}`}
115
80
  >
@@ -123,7 +88,6 @@ export const DashboardLayout = ({
123
88
  />
124
89
  </aside>
125
90
 
126
- {/* Mobile Menu Overlay */}
127
91
  {mobileOpen && (
128
92
  <div className="udb-layout__mobile">
129
93
  <div className="udb-layout__backdrop" onClick={() => setMobileOpen(false)} />
@@ -140,7 +104,6 @@ export const DashboardLayout = ({
140
104
  </div>
141
105
  )}
142
106
 
143
- {/* Main Content Area */}
144
107
  <div className="udb-layout__main">
145
108
  <DashboardHeader
146
109
  collapsed={collapsed}
@@ -1,8 +1,9 @@
1
1
  import { useState } from "react";
2
2
  import { Link, useLocation } from "react-router-dom";
3
- import { useT } from "../../../i18n";
3
+ import { useT } from "@umituz/web-localization/react";
4
4
 
5
- import { Button, cn } from "../../../primitives";
5
+ import { Button } from "@umituz/web-design-system/atoms";
6
+ import { cn } from "@umituz/web-design-system/utils/cn";
6
7
  import { BrandLogo } from "./BrandLogo";
7
8
  import { PenTool, Menu, ChevronLeft, ChevronDown, ChevronRight } from "lucide-react";
8
9
  import type { DashboardSidebarProps } from "../types/layout";
@@ -11,29 +12,14 @@ import type { SidebarGroup } from "../types/sidebar";
11
12
  import { filterSidebarItems } from "../utils/dashboard";
12
13
 
13
14
  interface DashboardSidebarPropsExtended extends DashboardSidebarProps {
14
- /** Sidebar groups configuration */
15
15
  sidebarGroups: SidebarGroup[];
16
- /** Brand name */
17
16
  brandName?: string;
18
- /** Brand tagline */
19
17
  brandTagline?: string;
20
- /** Create post route */
21
18
  createPostRoute?: string;
22
- /** Whether to show the primary create button (default: true) */
23
19
  showCreatePost?: boolean;
24
- /** Auth user */
25
20
  user?: DashboardUser;
26
21
  }
27
22
 
28
- /**
29
- * Dashboard Sidebar Component
30
- *
31
- * Displays collapsible sidebar with navigation menu items.
32
- * Supports app-based filtering (mobile/web) and collapsible groups.
33
- * Styling is entirely `udb-sidebar*` classes from the package stylesheet.
34
- *
35
- * @param props - Dashboard sidebar props
36
- */
37
23
  export const DashboardSidebar = ({
38
24
  collapsed,
39
25
  setCollapsed,
@@ -57,7 +43,6 @@ export const DashboardSidebar = ({
57
43
 
58
44
  return (
59
45
  <div className={cn("udb-sidebar", collapsed && "udb-sidebar--collapsed")}>
60
- {/* Brand Section */}
61
46
  <div className="udb-sidebar__brand">
62
47
  <BrandLogo size={32} />
63
48
  {!collapsed && (
@@ -68,7 +53,6 @@ export const DashboardSidebar = ({
68
53
  )}
69
54
  </div>
70
55
 
71
- {/* Create Button */}
72
56
  {showCreatePost && createPostRoute && (
73
57
  <div className="udb-sidebar__create">
74
58
  <Link to={createPostRoute}>
@@ -84,7 +68,6 @@ export const DashboardSidebar = ({
84
68
  </div>
85
69
  )}
86
70
 
87
- {/* Navigation */}
88
71
  <nav className="udb-sidebar__nav">
89
72
  <div className="udb-sidebar__groups">
90
73
  {sidebarGroups.map((group) => {
@@ -135,7 +118,6 @@ export const DashboardSidebar = ({
135
118
  </div>
136
119
  </nav>
137
120
 
138
- {/* Collapse Toggle */}
139
121
  <div className="udb-sidebar__footer">
140
122
  {!collapsed && (
141
123
  <p className="udb-sidebar__footer-label">
@@ -1,20 +1,12 @@
1
- /**
2
- * Permissions context — provides the matrix + active role and a
3
- * `can(permission)` helper bound to them. Guard components
4
- * (<RequirePermission>, <Can>) consume this context.
5
- */
6
-
7
1
  import { createContext, useCallback, useContext, useMemo, type ReactNode } from "react";
8
2
  import { Lock } from "lucide-react";
9
- import { useT } from "../../i18n";
3
+ import { useT } from "@umituz/web-localization/react";
10
4
  import { hasPermission } from "./hasPermission";
11
5
  import { PERMISSIONS_KEYS } from "./utils/i18nKeys";
12
6
  import type { Permission, PermissionMatrix, RoleKey } from "./types";
13
7
 
14
8
  export interface PermissionsProviderProps {
15
- /** Role x permission matrix. */
16
9
  matrix: PermissionMatrix;
17
- /** Active user's role. */
18
10
  role: RoleKey | null | undefined;
19
11
  children: ReactNode;
20
12
  }
@@ -57,7 +49,6 @@ export const usePermissions = (): PermissionsContextValue => {
57
49
  return context;
58
50
  };
59
51
 
60
- /** Default lock screen rendered by RequirePermission when denied. */
61
52
  const ForbiddenFallback = () => {
62
53
  const t = useT();
63
54
  return (
@@ -72,17 +63,11 @@ const ForbiddenFallback = () => {
72
63
  };
73
64
 
74
65
  export interface RequirePermissionProps {
75
- /** Permission required to render the children. */
76
66
  permission: Permission;
77
67
  children: ReactNode;
78
- /** Rendered instead of the default lock screen when denied. */
79
68
  fallback?: ReactNode;
80
69
  }
81
70
 
82
- /**
83
- * Page-level permission gate — renders the fallback (lock screen by
84
- * default) instead of the children when `can(permission)` is false.
85
- */
86
71
  export const RequirePermission = ({
87
72
  permission,
88
73
  children,
@@ -95,7 +80,6 @@ export const RequirePermission = ({
95
80
 
96
81
  export interface CanProps extends RequirePermissionProps {}
97
82
 
98
- /** Declarative twin of RequirePermission for inline use. */
99
83
  export const Can = ({ permission, children, fallback }: CanProps) => (
100
84
  <RequirePermission permission={permission} fallback={fallback}>
101
85
  {children}
@@ -1,8 +1,3 @@
1
- /**
2
- * Permission domain i18n keys — the documented string contract.
3
- * Hosts translate these via <DashboardI18nProvider t={...}>.
4
- */
5
-
6
1
  export const PERMISSIONS_KEYS = {
7
2
  forbidden: {
8
3
  title: "permissions.forbidden.title",
@@ -1,18 +1,10 @@
1
- /**
2
- * DemoLogin — one-click demo entry (fleet pattern: log in as a demo
3
- * persona without a password). Controlled: the click delegates to
4
- * `onDemo` (typically `session.demoLogin`); the label defaults to
5
- * the i18n catalog.
6
- */
7
-
8
1
  import { UserRound } from "lucide-react";
9
- import { Button } from "../../primitives";
10
- import { useT } from "../../i18n";
2
+ import { Button } from "@umituz/web-design-system/atoms";
3
+ import { useT } from "@umituz/web-localization/react";
11
4
  import { SESSION_KEYS } from "./utils/i18nKeys";
12
5
 
13
6
  export interface DemoLoginProps {
14
7
  onDemo: (userId: string) => void | Promise<void>;
15
- /** Demo user id to log in as. */
16
8
  userId: string;
17
9
  label?: string;
18
10
  variant?: "default" | "outline" | "ghost";
@@ -1,15 +1,7 @@
1
- /**
2
- * OrgSwitcher — tenant switcher trigger + dropdown.
3
- *
4
- * Controlled component: tenants and the active id come in as props,
5
- * switches are delegated via onSwitch. Styled entirely with existing
6
- * udb-* classes (profile button, avatar, menu).
7
- */
8
-
9
1
  import { useState } from "react";
10
2
  import { Building2, Check, ChevronDown } from "lucide-react";
11
- import { cn } from "../../primitives";
12
- import { useT } from "../../i18n";
3
+ import { cn } from "@umituz/web-design-system/utils/cn";
4
+ import { useT } from "@umituz/web-localization/react";
13
5
  import { SESSION_KEYS } from "./utils/i18nKeys";
14
6
  import type { Tenant } from "./types";
15
7