@umituz/web-dashboard 1.0.2 → 1.0.7

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/dist/index.d.ts CHANGED
@@ -1,8 +1,403 @@
1
- export { BrandLogo, DashboardHeader, DashboardLayout, DashboardLayout as DashboardLayoutDefault, DashboardSidebar } from './presentation/index.js';
2
- export { DashboardHeaderProps, DashboardLayoutConfig, DashboardNotification, DashboardSidebarProps, DashboardTheme, DashboardThemePreset, DashboardUser, SidebarGroup, SidebarItem, UserNavMenuItem } from './domain/types/index.js';
3
- export { DASHBOARD_THEME_PRESETS, DEFAULT_DASHBOARD_THEME, DEFAULT_DASHBOARD_THEME_DARK, applyDashboardTheme, getDashboardThemePreset, mergeDashboardTheme } from './domain/theme/index.js';
4
- export { useNotifications, useSidebar } from './infrastructure/hooks/index.js';
5
- export { filterSidebarItems, formatNotificationTime, generateNotificationId, getPageTitle, isPathActive } from './infrastructure/utils/index.js';
6
- import 'react/jsx-runtime';
7
- import 'lucide-react';
8
- import 'react';
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { LucideIcon } from 'lucide-react';
3
+ import * as react from 'react';
4
+
5
+ /**
6
+ * Dashboard Types
7
+ *
8
+ * Core type definitions for the dashboard layout system
9
+ */
10
+
11
+ /**
12
+ * Single sidebar menu item
13
+ */
14
+ interface SidebarItem {
15
+ /** Display label (can be i18n key) */
16
+ label: string;
17
+ /** Icon from lucide-react */
18
+ icon: LucideIcon;
19
+ /** Route path */
20
+ path: string;
21
+ /** Filter by app type (optional) */
22
+ requiredApp?: 'mobile' | 'web';
23
+ /** Enable/disable this item (default: true) */
24
+ enabled?: boolean;
25
+ }
26
+ /**
27
+ * Group of sidebar items with a title
28
+ */
29
+ interface SidebarGroup {
30
+ /** Group title (can be i18n key) */
31
+ title: string;
32
+ /** Items in this group */
33
+ items: SidebarItem[];
34
+ /** Optional: Route to title mapping for page headers */
35
+ titleMap?: Record<string, string>;
36
+ }
37
+ /**
38
+ * Dashboard header props
39
+ */
40
+ interface DashboardHeaderProps {
41
+ /** Whether sidebar is collapsed */
42
+ collapsed: boolean;
43
+ /** Toggle sidebar collapsed state */
44
+ setCollapsed: (collapsed: boolean) => void;
45
+ /** Toggle mobile menu open state */
46
+ setMobileOpen: (open: boolean) => void;
47
+ /** Current page title */
48
+ title: string;
49
+ }
50
+ /**
51
+ * Dashboard sidebar props
52
+ */
53
+ interface DashboardSidebarProps {
54
+ /** Whether sidebar is collapsed */
55
+ collapsed: boolean;
56
+ /** Toggle sidebar collapsed state */
57
+ setCollapsed: (collapsed: boolean) => void;
58
+ }
59
+ /**
60
+ * Dashboard layout configuration
61
+ */
62
+ interface DashboardLayoutConfig {
63
+ /** Sidebar groups */
64
+ sidebarGroups: SidebarGroup[];
65
+ /** Extra title mappings for routes */
66
+ extraTitleMap?: Record<string, string>;
67
+ /** Brand name */
68
+ brandName?: string;
69
+ /** Brand tagline */
70
+ brandTagline?: string;
71
+ }
72
+ /**
73
+ * Dashboard theme configuration
74
+ * Extends CSS variables for customization
75
+ */
76
+ interface DashboardTheme {
77
+ /** Primary color (CSS variable compatible) */
78
+ primary?: string;
79
+ /** Secondary color */
80
+ secondary?: string;
81
+ /** Sidebar background */
82
+ sidebarBackground?: string;
83
+ /** Sidebar foreground */
84
+ sidebarForeground?: string;
85
+ /** Sidebar border */
86
+ sidebarBorder?: string;
87
+ /** Header background */
88
+ headerBackground?: string;
89
+ /** Background color */
90
+ background?: string;
91
+ /** Foreground color */
92
+ foreground?: string;
93
+ /** Border color */
94
+ border?: string;
95
+ /** Accent color */
96
+ accent?: string;
97
+ /** Accent foreground */
98
+ accentForeground?: string;
99
+ /** Destructive color */
100
+ destructive?: string;
101
+ /** Destructive foreground */
102
+ destructiveForeground?: string;
103
+ /** Muted background */
104
+ muted?: string;
105
+ /** Muted foreground */
106
+ mutedForeground?: string;
107
+ /** Card background */
108
+ card?: string;
109
+ /** Card foreground */
110
+ cardForeground?: string;
111
+ /** Popover background */
112
+ popover?: string;
113
+ /** Popover foreground */
114
+ popoverForeground?: string;
115
+ /** Radius (border-radius) */
116
+ radius?: string;
117
+ }
118
+ /**
119
+ * Theme preset for quick setup
120
+ */
121
+ interface DashboardThemePreset {
122
+ /** Preset name */
123
+ name: string;
124
+ /** Theme configuration */
125
+ theme: DashboardTheme;
126
+ /** Whether this is a dark theme */
127
+ dark?: boolean;
128
+ }
129
+ /**
130
+ * Notification item
131
+ */
132
+ interface DashboardNotification {
133
+ /** Unique ID */
134
+ id: string;
135
+ /** Notification text */
136
+ text: string;
137
+ /** Whether notification is read */
138
+ read: boolean;
139
+ /** Creation timestamp */
140
+ createdAt: Date | string | number;
141
+ }
142
+ /**
143
+ * User profile info for header
144
+ */
145
+ interface DashboardUser {
146
+ /** User ID */
147
+ id: string;
148
+ /** Display name */
149
+ name?: string;
150
+ /** Email address */
151
+ email?: string;
152
+ /** Avatar URL */
153
+ avatar?: string;
154
+ /** Whether user has mobile app access */
155
+ hasMobileApp?: boolean;
156
+ /** Whether user has web app access */
157
+ hasWebApp?: boolean;
158
+ }
159
+ /**
160
+ * Navigation item for user menu
161
+ */
162
+ interface UserNavMenuItem {
163
+ /** Display label */
164
+ label: string;
165
+ /** Icon component */
166
+ icon: React.ComponentType<{
167
+ className?: string;
168
+ }>;
169
+ /** Route path */
170
+ path: string;
171
+ }
172
+
173
+ interface DashboardLayoutProps {
174
+ /** Layout configuration */
175
+ config: DashboardLayoutConfig;
176
+ /** Auth user */
177
+ user?: DashboardUser;
178
+ /** Auth loading state */
179
+ authLoading?: boolean;
180
+ /** Authenticated state */
181
+ isAuthenticated?: boolean;
182
+ /** Notifications */
183
+ notifications?: DashboardNotification[];
184
+ /** Logout function */
185
+ onLogout?: () => Promise<void>;
186
+ /** Mark all as read function */
187
+ onMarkAllRead?: () => void;
188
+ /** Dismiss notification function */
189
+ onDismissNotification?: (id: string) => void;
190
+ /** Login route for redirect */
191
+ loginRoute?: string;
192
+ }
193
+ /**
194
+ * Dashboard Layout Component
195
+ *
196
+ * Main layout wrapper for dashboard pages.
197
+ * Provides sidebar, header, and content area with responsive design.
198
+ *
199
+ * Features:
200
+ * - Collapsible sidebar
201
+ * - Mobile menu overlay
202
+ * - Breadcrumb page titles
203
+ * - Loading skeletons
204
+ * - Auth protection
205
+ *
206
+ * @param props - Dashboard layout props
207
+ */
208
+ declare const DashboardLayout: ({ config, user, authLoading, isAuthenticated, notifications, onLogout, onMarkAllRead, onDismissNotification, loginRoute, }: DashboardLayoutProps) => react_jsx_runtime.JSX.Element | null;
209
+
210
+ interface DashboardHeaderPropsExtended extends DashboardHeaderProps {
211
+ /** Auth user */
212
+ user?: DashboardUser;
213
+ /** Notifications */
214
+ notifications?: DashboardNotification[];
215
+ /** Logout function */
216
+ onLogout?: () => Promise<void>;
217
+ /** Mark all as read function */
218
+ onMarkAllRead?: () => void;
219
+ /** Dismiss notification function */
220
+ onDismissNotification?: (id: string) => void;
221
+ /** Settings route */
222
+ settingsRoute?: string;
223
+ /** Profile route */
224
+ profileRoute?: string;
225
+ /** Billing route */
226
+ billingRoute?: string;
227
+ }
228
+ /**
229
+ * Dashboard Header Component
230
+ *
231
+ * Displays top navigation bar with theme toggle, notifications,
232
+ * user menu, and organisation selector.
233
+ *
234
+ * @param props - Dashboard header props
235
+ */
236
+ declare const DashboardHeader: ({ collapsed, setCollapsed, setMobileOpen, title, user, notifications, onLogout, onMarkAllRead, onDismissNotification, settingsRoute, profileRoute, billingRoute, }: DashboardHeaderPropsExtended) => react_jsx_runtime.JSX.Element;
237
+
238
+ interface DashboardSidebarPropsExtended extends DashboardSidebarProps {
239
+ /** Sidebar groups configuration */
240
+ sidebarGroups: SidebarGroup[];
241
+ /** Brand name */
242
+ brandName?: string;
243
+ /** Brand tagline */
244
+ brandTagline?: string;
245
+ /** Create post route */
246
+ createPostRoute?: string;
247
+ /** Auth user */
248
+ user?: DashboardUser;
249
+ }
250
+ /**
251
+ * Dashboard Sidebar Component
252
+ *
253
+ * Displays collapsible sidebar with navigation menu items.
254
+ * Supports app-based filtering (mobile/web) and collapsible groups.
255
+ *
256
+ * @param props - Dashboard sidebar props
257
+ */
258
+ declare const DashboardSidebar: ({ collapsed, setCollapsed, sidebarGroups, brandName, brandTagline, createPostRoute, user, }: DashboardSidebarPropsExtended) => react_jsx_runtime.JSX.Element;
259
+
260
+ interface BrandLogoProps {
261
+ className?: string;
262
+ size?: number;
263
+ }
264
+ /**
265
+ * BrandLogo Component
266
+ *
267
+ * Displays the application brand logo as an SVG.
268
+ * Supports custom sizing and styling through className.
269
+ *
270
+ * @param className - Optional CSS classes for styling
271
+ * @param size - Width and height in pixels (default: 32)
272
+ */
273
+ declare const BrandLogo: ({ className, size }: BrandLogoProps) => react_jsx_runtime.JSX.Element;
274
+
275
+ /**
276
+ * Dashboard Theme System
277
+ *
278
+ * Provides theme configuration and presets for the dashboard layout.
279
+ * Themes are applied via CSS variables, allowing runtime customization.
280
+ */
281
+
282
+ /**
283
+ * Default dashboard theme (light mode)
284
+ */
285
+ declare const DEFAULT_DASHBOARD_THEME: DashboardTheme;
286
+ /**
287
+ * Default dashboard theme (dark mode)
288
+ */
289
+ declare const DEFAULT_DASHBOARD_THEME_DARK: DashboardTheme;
290
+ /**
291
+ * Available theme presets
292
+ */
293
+ declare const DASHBOARD_THEME_PRESETS: DashboardThemePreset[];
294
+ /**
295
+ * Apply theme to document root via CSS variables
296
+ *
297
+ * @param theme - Theme configuration to apply
298
+ */
299
+ declare function applyDashboardTheme(theme: DashboardTheme): void;
300
+ /**
301
+ * Get theme preset by name
302
+ *
303
+ * @param name - Preset name
304
+ * @returns Theme preset or undefined
305
+ */
306
+ declare function getDashboardThemePreset(name: string): DashboardThemePreset | undefined;
307
+ /**
308
+ * Merge custom theme with default theme
309
+ *
310
+ * @param customTheme - Custom theme configuration
311
+ * @param dark - Whether to use dark mode base
312
+ * @returns Merged theme configuration
313
+ */
314
+ declare function mergeDashboardTheme(customTheme: Partial<DashboardTheme>, dark?: boolean): DashboardTheme;
315
+
316
+ /**
317
+ * Use Notifications Hook
318
+ *
319
+ * Manages notification state and actions
320
+ *
321
+ * @param initialNotifications - Initial notification list
322
+ * @returns Notification state and actions
323
+ */
324
+ declare function useNotifications(initialNotifications?: DashboardNotification[]): {
325
+ notifications: DashboardNotification[];
326
+ markAllRead: () => void;
327
+ dismiss: (id: string) => void;
328
+ add: (notification: Omit<DashboardNotification, "id">) => void;
329
+ };
330
+ /**
331
+ * Use Sidebar Hook
332
+ *
333
+ * Manages sidebar state
334
+ *
335
+ * @returns Sidebar state and actions
336
+ */
337
+ declare function useSidebar(initialCollapsed?: boolean): {
338
+ collapsed: boolean;
339
+ setCollapsed: react.Dispatch<react.SetStateAction<boolean>>;
340
+ toggle: () => void;
341
+ mobileOpen: boolean;
342
+ setMobileOpen: react.Dispatch<react.SetStateAction<boolean>>;
343
+ openMobile: () => void;
344
+ closeMobile: () => void;
345
+ };
346
+
347
+ /**
348
+ * Dashboard Utilities
349
+ *
350
+ * Utility functions for dashboard operations
351
+ */
352
+ /**
353
+ * Format notification timestamp to relative time
354
+ *
355
+ * @param createdAt - Notification creation timestamp
356
+ * @param t - i18n translation function
357
+ * @returns Formatted time string
358
+ */
359
+ declare function formatNotificationTime(createdAt: Date | string | number, t: (key: string, params?: Record<string, unknown>) => string): string;
360
+ /**
361
+ * Check if a path is active
362
+ *
363
+ * @param currentPath - Current location pathname
364
+ * @param targetPath - Target path to check
365
+ * @returns True if paths match
366
+ */
367
+ declare function isPathActive(currentPath: string, targetPath: string): boolean;
368
+ /**
369
+ * Get page title from sidebar configuration
370
+ *
371
+ * @param pathname - Current pathname
372
+ * @param sidebarGroups - Sidebar groups configuration
373
+ * @param extraTitleMap - Extra title mappings
374
+ * @returns Page title or null
375
+ */
376
+ declare function getPageTitle(pathname: string, sidebarGroups: Array<{
377
+ items: Array<{
378
+ path: string;
379
+ label: string;
380
+ }>;
381
+ }>, extraTitleMap?: Record<string, string>): string | null;
382
+ /**
383
+ * Filter sidebar items by app type and enabled status
384
+ *
385
+ * @param items - Sidebar items to filter
386
+ * @param user - Current user object
387
+ * @returns Filtered items
388
+ */
389
+ declare function filterSidebarItems<T extends {
390
+ enabled?: boolean;
391
+ requiredApp?: "mobile" | "web";
392
+ }>(items: T[], user?: {
393
+ hasMobileApp?: boolean;
394
+ hasWebApp?: boolean;
395
+ }): T[];
396
+ /**
397
+ * Generate notification ID
398
+ *
399
+ * @returns Unique notification ID
400
+ */
401
+ declare function generateNotificationId(): string;
402
+
403
+ export { BrandLogo, DASHBOARD_THEME_PRESETS, DEFAULT_DASHBOARD_THEME, DEFAULT_DASHBOARD_THEME_DARK, DashboardHeader, type DashboardHeaderProps, DashboardLayout, type DashboardLayoutConfig, type DashboardNotification, DashboardSidebar, type DashboardSidebarProps, type DashboardTheme, type DashboardThemePreset, type DashboardUser, type SidebarGroup, type SidebarItem, type UserNavMenuItem, applyDashboardTheme, filterSidebarItems, formatNotificationTime, generateNotificationId, getDashboardThemePreset, getPageTitle, isPathActive, mergeDashboardTheme, useNotifications, useSidebar };
package/dist/index.js CHANGED
@@ -1,17 +1,17 @@
1
1
  "use client";
2
2
 
3
- // src/presentation/organisms/DashboardLayout.tsx
3
+ // src/domains/layouts/components/DashboardLayout.tsx
4
4
  import { useState as useState3, useEffect } from "react";
5
5
  import { useLocation as useLocation2, Outlet, Navigate } from "react-router-dom";
6
6
  import { Skeleton } from "@umituz/web-design-system/atoms";
7
7
 
8
- // src/presentation/molecules/DashboardSidebar.tsx
8
+ // src/domains/layouts/components/DashboardSidebar.tsx
9
9
  import { useState } from "react";
10
10
  import { Link, useLocation } from "react-router-dom";
11
11
  import { useTranslation } from "react-i18next";
12
12
  import { Button } from "@umituz/web-design-system/atoms";
13
13
 
14
- // src/presentation/molecules/BrandLogo.tsx
14
+ // src/domains/layouts/components/BrandLogo.tsx
15
15
  import { cn } from "@umituz/web-design-system/utils";
16
16
  import { jsx, jsxs } from "react/jsx-runtime";
17
17
  var BrandLogo = ({ className, size = 32 }) => {
@@ -94,8 +94,45 @@ var BrandLogo = ({ className, size = 32 }) => {
94
94
  );
95
95
  };
96
96
 
97
- // src/presentation/molecules/DashboardSidebar.tsx
97
+ // src/domains/layouts/components/DashboardSidebar.tsx
98
98
  import { PenTool, Menu, ChevronLeft, ChevronDown, ChevronRight } from "lucide-react";
99
+
100
+ // src/domains/layouts/utils/dashboard.ts
101
+ function formatNotificationTime(createdAt, t) {
102
+ const date = new Date(createdAt);
103
+ const secs = Math.floor((Date.now() - date.getTime()) / 1e3);
104
+ if (secs < 60) return t("dashboard.activityFeed.times.justNow");
105
+ if (secs < 3600) return t("dashboard.activityFeed.times.minutesAgo", { val: Math.floor(secs / 60) });
106
+ if (secs < 86400) return t("dashboard.activityFeed.times.hoursAgo", { val: Math.floor(secs / 3600) });
107
+ return t("dashboard.activityFeed.times.daysAgo", { val: Math.floor(secs / 86400) });
108
+ }
109
+ function isPathActive(currentPath, targetPath) {
110
+ return currentPath === targetPath;
111
+ }
112
+ function getPageTitle(pathname, sidebarGroups, extraTitleMap) {
113
+ for (const group of sidebarGroups) {
114
+ const item = group.items.find((i) => i.path === pathname);
115
+ if (item) return item.label;
116
+ }
117
+ if (extraTitleMap?.[pathname]) {
118
+ return extraTitleMap[pathname];
119
+ }
120
+ return null;
121
+ }
122
+ function filterSidebarItems(items, user) {
123
+ return items.filter((item) => {
124
+ if (item.enabled === false) return false;
125
+ if (!item.requiredApp) return true;
126
+ if (item.requiredApp === "mobile") return user?.hasMobileApp ?? false;
127
+ if (item.requiredApp === "web") return user?.hasWebApp ?? false;
128
+ return true;
129
+ });
130
+ }
131
+ function generateNotificationId() {
132
+ return crypto.randomUUID();
133
+ }
134
+
135
+ // src/domains/layouts/components/DashboardSidebar.tsx
99
136
  import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
100
137
  var DashboardSidebar = ({
101
138
  collapsed,
@@ -136,13 +173,7 @@ var DashboardSidebar = ({
136
173
  }
137
174
  ) }) }),
138
175
  /* @__PURE__ */ jsx2("nav", { className: "flex-1 overflow-y-auto px-2 py-3 scrollbar-hide", children: /* @__PURE__ */ jsx2("div", { className: "space-y-6", children: sidebarGroups.map((group) => {
139
- const filteredItems = group.items.filter((item) => {
140
- if (item.enabled === false) return false;
141
- if (!item.requiredApp) return true;
142
- if (item.requiredApp === "mobile") return user?.hasMobileApp;
143
- if (item.requiredApp === "web") return user?.hasWebApp;
144
- return true;
145
- });
176
+ const filteredItems = filterSidebarItems(group.items, user);
146
177
  if (filteredItems.length === 0) return null;
147
178
  const isGroupCollapsed = collapsedGroups[group.title];
148
179
  return /* @__PURE__ */ jsxs2("div", { className: "space-y-1", children: [
@@ -182,8 +213,8 @@ var DashboardSidebar = ({
182
213
  ] });
183
214
  };
184
215
 
185
- // src/presentation/organisms/DashboardHeader.tsx
186
- import React, { useState as useState2, useCallback } from "react";
216
+ // src/domains/layouts/components/DashboardHeader.tsx
217
+ import React, { useState as useState2 } from "react";
187
218
  import {
188
219
  Bell,
189
220
  X,
@@ -210,7 +241,6 @@ var DashboardHeader = ({
210
241
  onLogout,
211
242
  onMarkAllRead,
212
243
  onDismissNotification,
213
- formatDate,
214
244
  settingsRoute = "/dashboard/settings",
215
245
  profileRoute = "/dashboard/profile",
216
246
  billingRoute = "/dashboard/billing"
@@ -223,20 +253,11 @@ var DashboardHeader = ({
223
253
  const markAllRead = () => {
224
254
  onMarkAllRead?.();
225
255
  };
226
- const formatTimeAgo = useCallback((createdAt) => {
227
- if (!formatDate) return "";
228
- const date = new Date(createdAt);
229
- const secs = Math.floor((Date.now() - date.getTime()) / 1e3);
230
- if (secs < 60) return t("dashboard.activityFeed.times.justNow");
231
- if (secs < 3600) return t("dashboard.activityFeed.times.minutesAgo", { val: Math.floor(secs / 60) });
232
- if (secs < 86400) return t("dashboard.activityFeed.times.hoursAgo", { val: Math.floor(secs / 3600) });
233
- return t("dashboard.activityFeed.times.daysAgo", { val: Math.floor(secs / 86400) });
234
- }, [t, formatDate]);
235
256
  const handleLogout = async () => {
236
257
  try {
237
258
  await onLogout?.();
238
259
  navigate("/login");
239
- } catch (error) {
260
+ } catch {
240
261
  }
241
262
  };
242
263
  const ThemeToggle = () => {
@@ -294,7 +315,7 @@ var DashboardHeader = ({
294
315
  /* @__PURE__ */ jsx3("p", { className: "text-sm text-foreground leading-snug", children: n.text }),
295
316
  /* @__PURE__ */ jsxs3("p", { className: "text-[10px] text-muted-foreground mt-1 flex items-center gap-1", children: [
296
317
  /* @__PURE__ */ jsx3("span", { className: "inline-block w-1 h-1 rounded-full bg-muted-foreground/30" }),
297
- formatTimeAgo(n.createdAt)
318
+ formatNotificationTime(n.createdAt, t)
298
319
  ] })
299
320
  ] }),
300
321
  /* @__PURE__ */ jsx3(
@@ -400,7 +421,7 @@ var DashboardHeader = ({
400
421
  ] });
401
422
  };
402
423
 
403
- // src/presentation/organisms/DashboardLayout.tsx
424
+ // src/domains/layouts/components/DashboardLayout.tsx
404
425
  import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
405
426
  var DashboardLayout = ({
406
427
  config,
@@ -488,9 +509,8 @@ var DashboardLayout = ({
488
509
  ] })
489
510
  ] });
490
511
  };
491
- var DashboardLayout_default = DashboardLayout;
492
512
 
493
- // src/domain/theme/index.ts
513
+ // src/domains/layouts/theme/index.ts
494
514
  var DEFAULT_DASHBOARD_THEME = {
495
515
  primary: "hsl(222.2 47.4% 11.2%)",
496
516
  secondary: "hsl(217.2 32.6% 17.5%)",
@@ -660,22 +680,22 @@ function mergeDashboardTheme(customTheme, dark = false) {
660
680
  };
661
681
  }
662
682
 
663
- // src/infrastructure/hooks/index.ts
664
- import { useState as useState4, useCallback as useCallback2 } from "react";
683
+ // src/domains/layouts/hooks/dashboard.ts
684
+ import { useState as useState4, useCallback } from "react";
665
685
  function useNotifications(initialNotifications = []) {
666
686
  const [notifications, setNotifications] = useState4(initialNotifications);
667
- const markAllRead = useCallback2(() => {
687
+ const markAllRead = useCallback(() => {
668
688
  setNotifications(
669
689
  (prev) => prev.map((n) => ({ ...n, read: true }))
670
690
  );
671
691
  }, []);
672
- const dismiss = useCallback2((id) => {
692
+ const dismiss = useCallback((id) => {
673
693
  setNotifications((prev) => prev.filter((n) => n.id !== id));
674
694
  }, []);
675
- const add = useCallback2((notification) => {
695
+ const add = useCallback((notification) => {
676
696
  const newNotification = {
677
697
  ...notification,
678
- id: Math.random().toString(36).substring(7),
698
+ id: crypto.randomUUID(),
679
699
  read: false,
680
700
  createdAt: /* @__PURE__ */ new Date()
681
701
  };
@@ -691,13 +711,13 @@ function useNotifications(initialNotifications = []) {
691
711
  function useSidebar(initialCollapsed = false) {
692
712
  const [collapsed, setCollapsed] = useState4(initialCollapsed);
693
713
  const [mobileOpen, setMobileOpen] = useState4(false);
694
- const toggle = useCallback2(() => {
714
+ const toggle = useCallback(() => {
695
715
  setCollapsed((prev) => !prev);
696
716
  }, []);
697
- const openMobile = useCallback2(() => {
717
+ const openMobile = useCallback(() => {
698
718
  setMobileOpen(true);
699
719
  }, []);
700
- const closeMobile = useCallback2(() => {
720
+ const closeMobile = useCallback(() => {
701
721
  setMobileOpen(false);
702
722
  }, []);
703
723
  return {
@@ -710,41 +730,6 @@ function useSidebar(initialCollapsed = false) {
710
730
  closeMobile
711
731
  };
712
732
  }
713
-
714
- // src/infrastructure/utils/index.ts
715
- function formatNotificationTime(createdAt, t) {
716
- const date = new Date(createdAt);
717
- const secs = Math.floor((Date.now() - date.getTime()) / 1e3);
718
- if (secs < 60) return t("dashboard.activityFeed.times.justNow");
719
- if (secs < 3600) return t("dashboard.activityFeed.times.minutesAgo", { val: Math.floor(secs / 60) });
720
- if (secs < 86400) return t("dashboard.activityFeed.times.hoursAgo", { val: Math.floor(secs / 3600) });
721
- return t("dashboard.activityFeed.times.daysAgo", { val: Math.floor(secs / 86400) });
722
- }
723
- function isPathActive(currentPath, targetPath) {
724
- return currentPath === targetPath;
725
- }
726
- function getPageTitle(pathname, sidebarGroups, extraTitleMap) {
727
- for (const group of sidebarGroups) {
728
- const item = group.items.find((i) => i.path === pathname);
729
- if (item) return item.label;
730
- }
731
- if (extraTitleMap?.[pathname]) {
732
- return extraTitleMap[pathname];
733
- }
734
- return null;
735
- }
736
- function filterSidebarItems(items, user) {
737
- return items.filter((item) => {
738
- if (item.enabled === false) return false;
739
- if (!item.requiredApp) return true;
740
- if (item.requiredApp === "mobile") return user?.hasMobileApp ?? false;
741
- if (item.requiredApp === "web") return user?.hasWebApp ?? false;
742
- return true;
743
- });
744
- }
745
- function generateNotificationId() {
746
- return `${Date.now()}-${Math.random().toString(36).substring(7)}`;
747
- }
748
733
  export {
749
734
  BrandLogo,
750
735
  DASHBOARD_THEME_PRESETS,
@@ -752,7 +737,6 @@ export {
752
737
  DEFAULT_DASHBOARD_THEME_DARK,
753
738
  DashboardHeader,
754
739
  DashboardLayout,
755
- DashboardLayout_default as DashboardLayoutDefault,
756
740
  DashboardSidebar,
757
741
  applyDashboardTheme,
758
742
  filterSidebarItems,