@umituz/web-dashboard 2.5.1 → 3.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@umituz/web-dashboard",
3
- "version": "2.5.1",
4
- "description": "Dashboard Layout System - Customizable, themeable dashboard layouts and settings",
3
+ "version": "3.0.0",
4
+ "description": "Dashboard Layout System - Comprehensive analytics services, customizable layouts, and config-based architecture",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
7
7
  "sideEffects": false,
@@ -33,6 +33,8 @@
33
33
  "./analytics/hooks": "./src/domains/analytics/hooks/index.ts",
34
34
  "./analytics/utils": "./src/domains/analytics/utils/index.ts",
35
35
  "./analytics/types": "./src/domains/analytics/types/index.ts",
36
+ "./analytics/services": "./src/domains/analytics/services/index.ts",
37
+ "./config": "./src/domain/config/index.ts",
36
38
  "./billing": "./src/domains/billing/index.ts",
37
39
  "./billing/components": "./src/domains/billing/components/index.ts",
38
40
  "./billing/hooks": "./src/domains/billing/hooks/index.ts",
@@ -85,6 +87,13 @@
85
87
  "login",
86
88
  "register",
87
89
  "analytics",
90
+ "analytics-services",
91
+ "cohort-analysis",
92
+ "funnel-analysis",
93
+ "user-segmentation",
94
+ "behavior-prediction",
95
+ "performance-monitoring",
96
+ "realtime-metrics",
88
97
  "charts",
89
98
  "metrics",
90
99
  "kpi",
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Dashboard Configuration
3
+ * Config-based dashboard system
4
+ */
5
+
6
+ import type { ChartType } from '../../domains/analytics/types/analytics';
7
+
8
+ /**
9
+ * Analytics service types
10
+ */
11
+ export type AnalyticsServiceType = 'traffic' | 'cohort' | 'funnel' | 'growth' | 'performance';
12
+
13
+ /**
14
+ * Export format
15
+ */
16
+ export type ExportFormat = 'pdf' | 'excel' | 'csv' | 'json';
17
+
18
+ /**
19
+ * Analytics configuration
20
+ */
21
+ export interface AnalyticsConfig {
22
+ /** Enable analytics */
23
+ enabled?: boolean;
24
+ /** Analytics services to include */
25
+ services?: AnalyticsServiceType[];
26
+ /** Real-time updates */
27
+ realtime?: boolean;
28
+ /** Export configuration */
29
+ export?: {
30
+ enabled?: boolean;
31
+ formats?: ExportFormat[];
32
+ };
33
+ }
34
+
35
+ /**
36
+ * Data refresh configuration
37
+ */
38
+ export interface DataConfig {
39
+ /** Refresh interval in milliseconds */
40
+ refreshInterval?: number;
41
+ /** Cache duration in milliseconds */
42
+ cacheDuration?: number;
43
+ /** Retry attempts for failed requests */
44
+ retryAttempts?: number;
45
+ }
46
+
47
+ /**
48
+ * Charts configuration
49
+ */
50
+ export interface ChartsConfig {
51
+ /** Default chart type */
52
+ defaultType?: ChartType;
53
+ /** Chart theme */
54
+ theme?: 'light' | 'dark' | 'auto';
55
+ /** Enable animations */
56
+ animations?: boolean;
57
+ /** Color palette */
58
+ colors?: string[];
59
+ }
60
+
61
+ /**
62
+ * Performance configuration
63
+ */
64
+ export interface PerformanceConfig {
65
+ /** Enable lazy loading */
66
+ lazyLoad?: boolean;
67
+ /** Enable virtual scrolling */
68
+ virtualScrolling?: boolean;
69
+ /** Pagination size */
70
+ paginationSize?: number;
71
+ }
72
+
73
+ /**
74
+ * Dashboard configuration
75
+ */
76
+ export interface DashboardConfig {
77
+ /** Analytics configuration */
78
+ analytics?: AnalyticsConfig;
79
+ /** Data configuration */
80
+ data?: DataConfig;
81
+ /** Charts configuration */
82
+ charts?: ChartsConfig;
83
+ /** Performance configuration */
84
+ performance?: PerformanceConfig;
85
+ }
86
+
87
+ /**
88
+ * Default dashboard configuration
89
+ */
90
+ export const DEFAULT_DASHBOARD_CONFIG: DashboardConfig = {
91
+ analytics: {
92
+ enabled: true,
93
+ services: ['traffic', 'cohort', 'funnel', 'growth'],
94
+ realtime: true,
95
+ export: {
96
+ enabled: true,
97
+ formats: ['pdf', 'excel', 'csv'],
98
+ },
99
+ },
100
+ data: {
101
+ refreshInterval: 30000, // 30 seconds
102
+ cacheDuration: 300000, // 5 minutes
103
+ retryAttempts: 3,
104
+ },
105
+ charts: {
106
+ defaultType: 'line',
107
+ theme: 'auto',
108
+ animations: true,
109
+ colors: ['#6366f1', '#a855f7', '#f59e0b', '#10b981'],
110
+ },
111
+ performance: {
112
+ lazyLoad: true,
113
+ virtualScrolling: true,
114
+ paginationSize: 20,
115
+ },
116
+ };
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Domain Config Index
3
+ */
4
+
5
+ export * from './DashboardConfig';
@@ -2,9 +2,10 @@
2
2
  * useAnalytics Hook
3
3
  *
4
4
  * Core analytics hook for fetching and managing analytics data
5
+ * Enhanced with config support and advanced analytics services
5
6
  */
6
7
 
7
- import { useState, useCallback, useEffect } from "react";
8
+ import { useState, useCallback, useEffect, useMemo } from "react";
8
9
  import type {
9
10
  KPIs,
10
11
  TimeSeriesData,
@@ -13,6 +14,8 @@ import type {
13
14
  AnalyticsExportOptions,
14
15
  } from "../types/analytics";
15
16
  import { createKPI } from "../utils/analytics";
17
+ import { analyticsEngineService, performanceService } from "../services";
18
+ import type { DashboardConfig } from "../../../domain/config";
16
19
 
17
20
  interface UseAnalyticsOptions {
18
21
  /** Analytics API base URL */
@@ -21,6 +24,10 @@ interface UseAnalyticsOptions {
21
24
  initialDateRange?: DateRangeValue;
22
25
  /** Auto-refresh interval in ms (0 to disable) */
23
26
  refreshInterval?: number;
27
+ /** Dashboard configuration */
28
+ config?: DashboardConfig;
29
+ /** Error callback */
30
+ onError?: (error: Error) => void;
24
31
  }
25
32
 
26
33
  interface AnalyticsData {
@@ -43,7 +50,19 @@ interface AnalyticsData {
43
50
  * @returns Analytics data and actions
44
51
  */
45
52
  export function useAnalytics(options: UseAnalyticsOptions = {}) {
46
- const { apiUrl = "/api/analytics", initialDateRange, refreshInterval = 0 } = options;
53
+ const {
54
+ apiUrl = "/api/analytics",
55
+ initialDateRange,
56
+ refreshInterval = 0,
57
+ config,
58
+ onError,
59
+ } = options;
60
+
61
+ // Apply config defaults
62
+ const effectiveRefreshInterval = useMemo(
63
+ () => refreshInterval || config?.data?.refreshInterval || 0,
64
+ [refreshInterval, config]
65
+ );
47
66
 
48
67
  // State
49
68
  const [dateRange, setDateRange] = useState<DateRangeValue>(
@@ -162,11 +181,81 @@ export function useAnalytics(options: UseAnalyticsOptions = {}) {
162
181
 
163
182
  // Auto-refresh
164
183
  useEffect(() => {
165
- if (refreshInterval > 0) {
166
- const interval = setInterval(fetchAnalytics, refreshInterval);
184
+ if (effectiveRefreshInterval > 0) {
185
+ const interval = setInterval(fetchAnalytics, effectiveRefreshInterval);
167
186
  return () => clearInterval(interval);
168
187
  }
169
- }, [fetchAnalytics, refreshInterval]);
188
+ }, [fetchAnalytics, effectiveRefreshInterval]);
189
+
190
+ // Advanced analytics methods
191
+ const calculateRetention = useCallback(
192
+ (userData: any[]) => {
193
+ try {
194
+ return analyticsEngineService.calculateRetention(userData);
195
+ } catch (err) {
196
+ onError?.(err as Error);
197
+ return [];
198
+ }
199
+ },
200
+ [onError]
201
+ );
202
+
203
+ const calculateFunnel = useCallback(
204
+ (data: any[], steps: string[]) => {
205
+ try {
206
+ return analyticsEngineService.calculateFunnel(data, steps);
207
+ } catch (err) {
208
+ onError?.(err as Error);
209
+ return null;
210
+ }
211
+ },
212
+ [onError]
213
+ );
214
+
215
+ const segmentUsers = useCallback(
216
+ (userData: any[]) => {
217
+ try {
218
+ return analyticsEngineService.segmentUsers(userData);
219
+ } catch (err) {
220
+ onError?.(err as Error);
221
+ return [];
222
+ }
223
+ },
224
+ [onError]
225
+ );
226
+
227
+ const predictUserBehavior = useCallback(
228
+ (user: any, historicalData: any[]) => {
229
+ try {
230
+ return analyticsEngineService.predictUserBehavior(user, historicalData);
231
+ } catch (err) {
232
+ onError?.(err as Error);
233
+ return null;
234
+ }
235
+ },
236
+ [onError]
237
+ );
238
+
239
+ const getPerformanceMetrics = useCallback(() => {
240
+ try {
241
+ return performanceService.getDashboardMetrics();
242
+ } catch (err) {
243
+ onError?.(err as Error);
244
+ return null;
245
+ }
246
+ }, [onError]);
247
+
248
+ const getRealtimeMetrics = useCallback(
249
+ (previous?: any) => {
250
+ try {
251
+ return performanceService.simulateRealtimeMetrics(previous);
252
+ } catch (err) {
253
+ onError?.(err as Error);
254
+ return null;
255
+ }
256
+ },
257
+ [onError]
258
+ );
170
259
 
171
260
  return {
172
261
  ...data,
@@ -174,5 +263,12 @@ export function useAnalytics(options: UseAnalyticsOptions = {}) {
174
263
  updateDateRange,
175
264
  refresh,
176
265
  exportData,
266
+ // Advanced analytics
267
+ calculateRetention,
268
+ calculateFunnel,
269
+ segmentUsers,
270
+ predictUserBehavior,
271
+ getPerformanceMetrics,
272
+ getRealtimeMetrics,
177
273
  };
178
274
  }
@@ -17,6 +17,26 @@ export {
17
17
  useAnalytics,
18
18
  } from "./hooks";
19
19
 
20
+ // Services
21
+ export {
22
+ AnalyticsEngineService,
23
+ analyticsEngineService,
24
+ PerformanceService,
25
+ performanceService,
26
+ } from "./services";
27
+ export type {
28
+ ConversionPath,
29
+ HeatmapData,
30
+ UserBehaviorPrediction,
31
+ UserData,
32
+ ConversionData,
33
+ FunnelItem,
34
+ ActivityItem,
35
+ PerformanceMetric,
36
+ DashboardMetrics,
37
+ RealtimeMetrics,
38
+ } from "./services";
39
+
20
40
  // Utils
21
41
  export {
22
42
  formatNumber,
@@ -0,0 +1,319 @@
1
+ /**
2
+ * Analytics Engine Service
3
+ *
4
+ * Advanced analytics operations including cohort analysis, funnel analysis,
5
+ * user segmentation, behavior prediction, and conversion path analysis.
6
+ */
7
+
8
+ import type {
9
+ CohortAnalysis,
10
+ FunnelData,
11
+ UserSegment,
12
+ } from '../types/analytics';
13
+
14
+ export interface ConversionPath {
15
+ path: string[];
16
+ conversions: number;
17
+ value: number;
18
+ abandonmentRate: number;
19
+ }
20
+
21
+ export interface HeatmapData {
22
+ day: string;
23
+ hour: number;
24
+ value: number;
25
+ }
26
+
27
+ export interface UserBehaviorPrediction {
28
+ churnProbability: number;
29
+ lifetimeValue: number;
30
+ nextAction: string;
31
+ confidence: number;
32
+ }
33
+
34
+ export interface UserData {
35
+ signup_date?: string | Date;
36
+ last_activity?: string | Date;
37
+ last_login_days?: number;
38
+ session_duration?: number;
39
+ pages_per_session?: number;
40
+ bounce_rate?: number;
41
+ age?: number;
42
+ location?: string;
43
+ churned?: boolean;
44
+ lifetime_value?: number;
45
+ last_action?: string;
46
+ }
47
+
48
+ export interface ConversionData {
49
+ path?: string[];
50
+ value?: number;
51
+ }
52
+
53
+ export interface FunnelItem {
54
+ [key: string]: boolean | number | undefined;
55
+ time_spent?: number;
56
+ }
57
+
58
+ export interface ActivityItem {
59
+ timestamp: string | Date;
60
+ }
61
+
62
+ /**
63
+ * Analytics Engine Service
64
+ *
65
+ * Singleton service for advanced analytics calculations
66
+ */
67
+ export class AnalyticsEngineService {
68
+ private static instance: AnalyticsEngineService;
69
+
70
+ private constructor() {}
71
+
72
+ public static getInstance(): AnalyticsEngineService {
73
+ if (!AnalyticsEngineService.instance) {
74
+ AnalyticsEngineService.instance = new AnalyticsEngineService();
75
+ }
76
+ return AnalyticsEngineService.instance;
77
+ }
78
+
79
+ /**
80
+ * Calculate cohort retention analysis
81
+ *
82
+ * @param data - User data with signup and activity dates
83
+ * @returns Cohort analysis with retention rates
84
+ */
85
+ public calculateRetention(data: UserData[]): CohortAnalysis[] {
86
+ const cohorts: Map<string, UserData[]> = new Map();
87
+
88
+ data.forEach((user) => {
89
+ if (!user.signup_date) return;
90
+ const signupMonth = new Date(user.signup_date).toISOString().slice(0, 7);
91
+ if (!cohorts.has(signupMonth)) {
92
+ cohorts.set(signupMonth, []);
93
+ }
94
+ const cohort = cohorts.get(signupMonth);
95
+ if (cohort) {
96
+ cohort.push(user);
97
+ }
98
+ });
99
+
100
+ const cohortAnalysis: CohortAnalysis[] = [];
101
+
102
+ cohorts.forEach((users, cohort) => {
103
+ const retention: number[] = [];
104
+ for (let month = 0; month < 12; month++) {
105
+ const activeUsersCount = users.filter((user) => {
106
+ if (!user.last_activity) return false;
107
+ const signupDate = new Date(user.signup_date!);
108
+ const targetDate = new Date(signupDate.getFullYear(), signupDate.getMonth() + month, 1);
109
+ return new Date(user.last_activity) >= targetDate;
110
+ }).length;
111
+
112
+ retention.push((activeUsersCount / users.length) * 100);
113
+ }
114
+
115
+ cohortAnalysis.push({
116
+ cohort,
117
+ size: users.length,
118
+ retention,
119
+ averageRetention: retention.reduce((a, b) => a + b, 0) / retention.length,
120
+ });
121
+ });
122
+
123
+ return cohortAnalysis;
124
+ }
125
+
126
+ /**
127
+ * Analyze conversion paths
128
+ *
129
+ * @param data - Conversion data with paths and values
130
+ * @returns Conversion path analysis
131
+ */
132
+ public analyzeConversionPaths(data: ConversionData[]): ConversionPath[] {
133
+ const paths: Map<string, { count: number; value: number }> = new Map();
134
+ let totalConversions = 0;
135
+
136
+ data.forEach((conversion) => {
137
+ if (!conversion.path) return;
138
+ const pathKey = conversion.path.join(' → ');
139
+ if (!paths.has(pathKey)) {
140
+ paths.set(pathKey, { count: 0, value: 0 });
141
+ }
142
+
143
+ const path = paths.get(pathKey);
144
+ if (path) {
145
+ path.count++;
146
+ path.value += conversion.value || 0;
147
+ totalConversions++;
148
+ }
149
+ });
150
+
151
+ return Array.from(paths.entries())
152
+ .map(([pathString, path]) => ({
153
+ path: pathString.split(' → '),
154
+ conversions: path.count,
155
+ value: path.value,
156
+ abandonmentRate:
157
+ totalConversions > 0 ? ((totalConversions - path.count) / totalConversions) * 100 : 0,
158
+ }))
159
+ .sort((a, b) => b.conversions - a.conversions);
160
+ }
161
+
162
+ /**
163
+ * Calculate funnel analysis
164
+ *
165
+ * @param data - Funnel data with step indicators
166
+ * @param steps - Funnel step names
167
+ * @returns Funnel analysis data
168
+ */
169
+ public calculateFunnel(data: FunnelItem[], steps: string[]): FunnelData {
170
+ let previousCount = data.length;
171
+ const funnelSteps = steps.map((step, index) => {
172
+ const stepCount = data.filter((item) => item[step]).length;
173
+ const conversionRate =
174
+ index === 0 ? 100 : previousCount > 0 ? (stepCount / previousCount) * 100 : 0;
175
+ previousCount = stepCount;
176
+
177
+ const stepData = data.filter((item) => item[step]);
178
+ const avgTime =
179
+ stepData.length > 0
180
+ ? stepData.reduce((sum, item) => sum + (item.time_spent || 0), 0) / stepData.length
181
+ : 0;
182
+
183
+ return {
184
+ name: step,
185
+ count: stepCount,
186
+ conversionRate,
187
+ dropOffRate: 100 - conversionRate,
188
+ averageTime: avgTime,
189
+ };
190
+ });
191
+
192
+ return {
193
+ title: 'Conversion Funnel',
194
+ steps: funnelSteps,
195
+ totalUsers: data.length,
196
+ finalConversion: funnelSteps[funnelSteps.length - 1]?.conversionRate || 0,
197
+ };
198
+ }
199
+
200
+ /**
201
+ * Generate activity heatmap
202
+ *
203
+ * @param data - Activity data with timestamps
204
+ * @returns Heatmap data by day and hour
205
+ */
206
+ public generateActivityHeatmap(data: ActivityItem[]): HeatmapData[] {
207
+ const heatmap: HeatmapData[] = [];
208
+ const days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
209
+
210
+ for (let day = 0; day < 7; day++) {
211
+ for (let hour = 0; hour < 24; hour++) {
212
+ const count = data.filter((item) => {
213
+ const d = new Date(item.timestamp);
214
+ return d.getDay() === day && d.getHours() === hour;
215
+ }).length;
216
+
217
+ heatmap.push({ day: days[day], hour, value: count });
218
+ }
219
+ }
220
+ return heatmap;
221
+ }
222
+
223
+ /**
224
+ * Segment users by behavior
225
+ *
226
+ * @param data - User data
227
+ * @returns User segments
228
+ */
229
+ public segmentUsers(data: UserData[]): UserSegment[] {
230
+ const defineSegment = (
231
+ name: string,
232
+ filter: (u: UserData) => boolean,
233
+ chars: string[]
234
+ ) => {
235
+ const users = data.filter(filter);
236
+ const avg = (field: string) =>
237
+ users.length === 0
238
+ ? 0
239
+ : users.reduce((s, i) => s + ((i as any)[field] || 0), 0) / users.length;
240
+
241
+ return {
242
+ name,
243
+ count: users.length,
244
+ percentage: (users.length / data.length) * 100,
245
+ characteristics: chars,
246
+ behavior: {
247
+ avgSessionDuration: avg('session_duration'),
248
+ pagesPerSession: avg('pages_per_session'),
249
+ bounceRate: avg('bounce_rate'),
250
+ },
251
+ };
252
+ };
253
+
254
+ return [
255
+ defineSegment('Active', (u) => u.last_login_days! <= 7, [
256
+ 'Recent login',
257
+ 'High engagement',
258
+ ]),
259
+ defineSegment('Moderate', (u) => u.last_login_days! > 7 && u.last_login_days! <= 30, [
260
+ 'Occasional login',
261
+ ]),
262
+ defineSegment('Inactive', (u) => u.last_login_days! > 30, [
263
+ 'Churn risk',
264
+ 'Low activity',
265
+ ]),
266
+ ];
267
+ }
268
+
269
+ /**
270
+ * Predict user behavior
271
+ *
272
+ * @param user - Target user
273
+ * @param historicalData - Historical user data
274
+ * @returns Behavior prediction
275
+ */
276
+ public predictUserBehavior(
277
+ user: UserData,
278
+ historicalData: UserData[]
279
+ ): UserBehaviorPrediction {
280
+ const similarUsers = historicalData.filter(
281
+ (u) => Math.abs((u.age || 0) - (user.age || 0)) < 5 && u.location === user.location
282
+ );
283
+
284
+ if (similarUsers.length === 0) {
285
+ return {
286
+ churnProbability: 0,
287
+ lifetimeValue: 0,
288
+ nextAction: 'none',
289
+ confidence: 0,
290
+ };
291
+ }
292
+
293
+ const churnCount = similarUsers.filter((u) => u.churned).length;
294
+ const totalLTV = similarUsers.reduce((s, u) => s + (u.lifetime_value || 0), 0);
295
+
296
+ // Predict next action based on frequency in similar users
297
+ const actions = similarUsers.map((u) => u.last_action).filter(Boolean) as string[];
298
+ const actionCounts = actions.reduce((c: Record<string, number>, a) => {
299
+ c[a] = (c[a] || 0) + 1;
300
+ return c;
301
+ }, {});
302
+ const nextAction = Object.keys(actionCounts).reduce(
303
+ (a, b) => (actionCounts[a] > actionCounts[b] ? a : b),
304
+ 'unknown'
305
+ );
306
+
307
+ return {
308
+ churnProbability: churnCount / similarUsers.length,
309
+ lifetimeValue: totalLTV / similarUsers.length,
310
+ nextAction,
311
+ confidence: Math.min(0.9, similarUsers.length / 100),
312
+ };
313
+ }
314
+ }
315
+
316
+ /**
317
+ * Singleton instance
318
+ */
319
+ export const analyticsEngineService = AnalyticsEngineService.getInstance();
@@ -0,0 +1,321 @@
1
+ /**
2
+ * Performance Service
3
+ *
4
+ * Real-time metrics and dashboard performance monitoring
5
+ */
6
+
7
+ export interface PerformanceMetric {
8
+ name: string;
9
+ value: number;
10
+ unit: string;
11
+ timestamp: number;
12
+ threshold?: number;
13
+ status: 'good' | 'warning' | 'critical';
14
+ }
15
+
16
+ export interface DashboardMetrics {
17
+ loadTime: number;
18
+ renderTime: number;
19
+ apiResponseTime: number;
20
+ memoryUsage: number;
21
+ errorRate: number;
22
+ activeUsers: number;
23
+ }
24
+
25
+ export interface KPIData {
26
+ current: number;
27
+ previous: number;
28
+ growth: number;
29
+ }
30
+
31
+ export interface RealtimeMetrics {
32
+ timestamp: number;
33
+ users: number;
34
+ sessions: number;
35
+ pageViews: number;
36
+ conversions: number;
37
+ revenue: number;
38
+ }
39
+
40
+ /**
41
+ * Performance Service
42
+ *
43
+ * Monitors dashboard performance and provides real-time metrics
44
+ */
45
+ export class PerformanceService {
46
+ private metrics: Map<string, PerformanceMetric[]> = new Map();
47
+ private observers: PerformanceObserver[] = [];
48
+
49
+ constructor() {
50
+ if (typeof window !== 'undefined') {
51
+ this.initializeObservers();
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Initialize performance observers
57
+ */
58
+ private initializeObservers(): void {
59
+ if ('PerformanceObserver' in window) {
60
+ // Observe layout shifts
61
+ try {
62
+ const observer = new PerformanceObserver((list) => {
63
+ for (const entry of list.getEntries()) {
64
+ if (entry.entryType === 'layout-shift') {
65
+ this.recordMetric('CLS', (entry as any).value, 'score', 0.1);
66
+ }
67
+ }
68
+ });
69
+ observer.observe({ entryTypes: ['layout-shift'] });
70
+ this.observers.push(observer);
71
+ } catch (e) {
72
+ // Layout Shift API not supported
73
+ }
74
+
75
+ // Observe largest contentful paint
76
+ try {
77
+ const observer = new PerformanceObserver((list) => {
78
+ for (const entry of list.getEntries()) {
79
+ if (entry.entryType === 'largest-contentful-paint') {
80
+ this.recordMetric('LCP', entry.startTime, 'ms', 2500);
81
+ }
82
+ }
83
+ });
84
+ observer.observe({ entryTypes: ['largest-contentful-paint'] });
85
+ this.observers.push(observer);
86
+ } catch (e) {
87
+ // LCP API not supported
88
+ }
89
+
90
+ // Observe first input delay
91
+ try {
92
+ const observer = new PerformanceObserver((list) => {
93
+ for (const entry of list.getEntries()) {
94
+ if (entry.entryType === 'first-input') {
95
+ this.recordMetric('FID', (entry as any).processingStart - entry.startTime, 'ms', 100);
96
+ }
97
+ }
98
+ });
99
+ observer.observe({ entryTypes: ['first-input'] });
100
+ this.observers.push(observer);
101
+ } catch (e) {
102
+ // FID API not supported
103
+ }
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Record a performance metric
109
+ *
110
+ * @param name - Metric name
111
+ * @param value - Metric value
112
+ * @param unit - Unit of measurement
113
+ * @param threshold - Warning threshold
114
+ */
115
+ public recordMetric(name: string, value: number, unit: string, threshold?: number): void {
116
+ const status = threshold
117
+ ? value > threshold * 2
118
+ ? 'critical'
119
+ : value > threshold
120
+ ? 'warning'
121
+ : 'good'
122
+ : 'good';
123
+
124
+ const metric: PerformanceMetric = {
125
+ name,
126
+ value,
127
+ unit,
128
+ timestamp: Date.now(),
129
+ threshold,
130
+ status,
131
+ };
132
+
133
+ if (!this.metrics.has(name)) {
134
+ this.metrics.set(name, []);
135
+ }
136
+
137
+ const metrics = this.metrics.get(name)!;
138
+ metrics.push(metric);
139
+
140
+ // Keep only last 100 metrics per name
141
+ if (metrics.length > 100) {
142
+ metrics.shift();
143
+ }
144
+ }
145
+
146
+ /**
147
+ * Get metrics by name
148
+ *
149
+ * @param name - Metric name
150
+ * @returns Array of metrics
151
+ */
152
+ public getMetrics(name: string): PerformanceMetric[] {
153
+ return this.metrics.get(name) || [];
154
+ }
155
+
156
+ /**
157
+ * Get latest metric value
158
+ *
159
+ * @param name - Metric name
160
+ * @returns Latest metric or undefined
161
+ */
162
+ public getLatestMetric(name: string): PerformanceMetric | undefined {
163
+ const metrics = this.getMetrics(name);
164
+ return metrics[metrics.length - 1];
165
+ }
166
+
167
+ /**
168
+ * Get all metrics
169
+ *
170
+ * @returns Map of all metrics
171
+ */
172
+ public getAllMetrics(): Map<string, PerformanceMetric[]> {
173
+ return new Map(this.metrics);
174
+ }
175
+
176
+ /**
177
+ * Clear all metrics
178
+ */
179
+ public clearMetrics(): void {
180
+ this.metrics.clear();
181
+ }
182
+
183
+ /**
184
+ * Calculate dashboard performance metrics
185
+ *
186
+ * @returns Dashboard performance data
187
+ */
188
+ public getDashboardMetrics(): DashboardMetrics {
189
+ const timing = typeof window !== 'undefined' ? window.performance?.timing : null;
190
+ const navigation = typeof window !== 'undefined' ? window.performance?.navigation : null;
191
+
192
+ const loadTime = timing
193
+ ? timing.loadEventEnd - timing.navigationStart
194
+ : this.getLatestMetric('loadTime')?.value || 0;
195
+
196
+ const renderTime = this.getLatestMetric('renderTime')?.value || 0;
197
+ const apiResponseTime = this.getLatestMetric('apiResponseTime')?.value || 0;
198
+ const memoryUsage =
199
+ typeof (performance as any).memory !== 'undefined'
200
+ ? (performance as any).memory.usedJSHeapSize / 1048576
201
+ : 0;
202
+
203
+ const errorRate = this.calculateErrorRate();
204
+
205
+ return {
206
+ loadTime,
207
+ renderTime,
208
+ apiResponseTime,
209
+ memoryUsage,
210
+ errorRate,
211
+ activeUsers: 0, // To be implemented with real data
212
+ };
213
+ }
214
+
215
+ /**
216
+ * Calculate error rate from metrics
217
+ *
218
+ * @returns Error rate percentage
219
+ */
220
+ private calculateErrorRate(): number {
221
+ const errors = this.getMetrics('error');
222
+ if (errors.length === 0) return 0;
223
+
224
+ const recentErrors = errors.filter((e) => e.timestamp > Date.now() - 60000); // Last minute
225
+ return recentErrors.length;
226
+ }
227
+
228
+ /**
229
+ * Simulate real-time metrics
230
+ *
231
+ * @param previous - Previous metrics
232
+ * @returns Simulated real-time metrics
233
+ */
234
+ public simulateRealtimeMetrics(previous?: RealtimeMetrics): RealtimeMetrics {
235
+ const now = Date.now();
236
+
237
+ if (previous) {
238
+ // Simulate changes
239
+ const userChange = Math.floor(Math.random() * 20) - 10;
240
+ const sessionChange = Math.floor(Math.random() * 30) - 15;
241
+ const pageViewChange = Math.floor(Math.random() * 50) - 20;
242
+ const conversionCount = Math.random() > 0.8 ? Math.floor(Math.random() * 3) : 0;
243
+ const revenueAdd = conversionCount * (Math.random() * 100 + 50);
244
+
245
+ return {
246
+ timestamp: now,
247
+ users: Math.max(0, previous.users + userChange),
248
+ sessions: Math.max(0, previous.sessions + sessionChange),
249
+ pageViews: Math.max(0, previous.pageViews + pageViewChange),
250
+ conversions: previous.conversions + conversionCount,
251
+ revenue: previous.revenue + revenueAdd,
252
+ };
253
+ }
254
+
255
+ // Initial values
256
+ return {
257
+ timestamp: now,
258
+ users: Math.floor(Math.random() * 1000) + 500,
259
+ sessions: Math.floor(Math.random() * 1500) + 800,
260
+ pageViews: Math.floor(Math.random() * 5000) + 2000,
261
+ conversions: Math.floor(Math.random() * 50),
262
+ revenue: Math.floor(Math.random() * 5000) + 2000,
263
+ };
264
+ }
265
+
266
+ /**
267
+ * Calculate growth KPI
268
+ *
269
+ * @param current - Current value
270
+ * @param previous - Previous value
271
+ * @returns KPI data
272
+ */
273
+ public calculateKPI(current: number, previous: number): KPIData {
274
+ const growth = previous > 0 ? ((current - previous) / previous) * 100 : 0;
275
+ return {
276
+ current,
277
+ previous,
278
+ growth,
279
+ };
280
+ }
281
+
282
+ /**
283
+ * Measure page load time
284
+ */
285
+ public measurePageLoad(): void {
286
+ if (typeof window === 'undefined' || !window.performance) return;
287
+
288
+ window.addEventListener('load', () => {
289
+ setTimeout(() => {
290
+ const timing = window.performance?.timing;
291
+ if (timing) {
292
+ const loadTime = timing.loadEventEnd - timing.navigationStart;
293
+ this.recordMetric('loadTime', loadTime, 'ms', 3000);
294
+ }
295
+ }, 0);
296
+ });
297
+ }
298
+
299
+ /**
300
+ * Measure API response time
301
+ *
302
+ * @param startTime - Request start time
303
+ */
304
+ public measureAPIResponse(startTime: number): void {
305
+ const duration = Date.now() - startTime;
306
+ this.recordMetric('apiResponseTime', duration, 'ms', 1000);
307
+ }
308
+
309
+ /**
310
+ * Disconnect all observers
311
+ */
312
+ public disconnect(): void {
313
+ this.observers.forEach((observer) => observer.disconnect());
314
+ this.observers = [];
315
+ }
316
+ }
317
+
318
+ /**
319
+ * Create singleton instance
320
+ */
321
+ export const performanceService = new PerformanceService();
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Analytics Services Index
3
+ */
4
+
5
+ export * from './AnalyticsEngineService';
6
+ export * from './PerformanceService';
@@ -219,7 +219,7 @@ export function getDateRangePresets(): DateRangePreset[] {
219
219
  export function aggregateByPeriod(
220
220
  data: Array<{ date: string; [key: string]: number | string }>,
221
221
  period: "day" | "week" | "month" = "day"
222
- ): Array<{ date: string; [key: string]: number }> {
222
+ ): Array<{ date: string; [key: string]: string | number }> {
223
223
  const grouped = new Map<string, Array<typeof data[0]>>();
224
224
 
225
225
  data.forEach((item) => {
@@ -9,12 +9,33 @@ import type {
9
9
  Currency,
10
10
  PlanTier,
11
11
  Subscription,
12
+ SubscriptionStatus,
12
13
  PaymentMethod,
13
14
  Invoice,
14
15
  InvoiceStatus,
15
16
  UsageMetric,
16
17
  } from "../types/billing";
17
18
 
19
+ /**
20
+ * Format number with K/M/B suffixes
21
+ *
22
+ * @param num - Number to format
23
+ * @param decimals - Number of decimal places (default: 1)
24
+ * @returns Formatted string
25
+ */
26
+ export function formatNumber(num: number, decimals: number = 1): string {
27
+ if (num >= 1_000_000_000) {
28
+ return (num / 1_000_000_000).toFixed(decimals) + "B";
29
+ }
30
+ if (num >= 1_000_000) {
31
+ return (num / 1_000_000).toFixed(decimals) + "M";
32
+ }
33
+ if (num >= 1_000) {
34
+ return (num / 1_000).toFixed(decimals) + "K";
35
+ }
36
+ return num.toFixed(decimals);
37
+ }
38
+
18
39
  /**
19
40
  * Format price with currency
20
41
  *
package/src/index.ts ADDED
@@ -0,0 +1,108 @@
1
+ /**
2
+ * @umituz/web-dashboard
3
+ *
4
+ * Dashboard Layout System - Customizable, themeable dashboard layouts
5
+ * with comprehensive analytics services and config-based architecture.
6
+ *
7
+ * @version 3.0.0
8
+ */
9
+
10
+ // Export all domains
11
+ export * from './domains/layouts';
12
+ export * from './domains/settings';
13
+ export * from './domains/billing';
14
+
15
+ // Auth and Onboarding with conflict resolution
16
+ export {
17
+ OnboardingWizard,
18
+ useOnboarding,
19
+ useOnboardingStep,
20
+ } from './domains/onboarding';
21
+
22
+ export type {
23
+ OnboardingStep,
24
+ OnboardingState,
25
+ OnboardingConfig,
26
+ } from './domains/onboarding';
27
+
28
+ export {
29
+ AuthLayout,
30
+ LoginForm,
31
+ RegisterForm,
32
+ useAuth,
33
+ type LoginCredentials,
34
+ type RegisterData,
35
+ type User,
36
+ } from './domains/auth';
37
+
38
+ // Analytics with conflict resolution
39
+ export {
40
+ useAnalytics,
41
+ MetricCard,
42
+ AnalyticsChart,
43
+ AnalyticsCard,
44
+ AnalyticsLayout,
45
+ formatNumber,
46
+ formatPercentage,
47
+ formatCurrency,
48
+ calculateGrowth,
49
+ getTrend,
50
+ createKPI,
51
+ createMetric,
52
+ formatMetricValue,
53
+ calculateConversionRate,
54
+ calculateDropOffRate,
55
+ createDateRangePreset,
56
+ getDateRangePresets,
57
+ aggregateByPeriod,
58
+ calculateMovingAverage,
59
+ detectOutliers,
60
+ roundTo,
61
+ generateColor,
62
+ generateChartColors,
63
+ // Services
64
+ AnalyticsEngineService,
65
+ analyticsEngineService,
66
+ PerformanceService,
67
+ performanceService,
68
+ // Types
69
+ type Metric,
70
+ type TimeSeriesData,
71
+ type ChartData,
72
+ type FunnelStep,
73
+ type FunnelData,
74
+ type CohortAnalysis,
75
+ type UserSegment,
76
+ type KPIData,
77
+ type KPIs,
78
+ type ChartType,
79
+ type ChartConfig,
80
+ type MetricCardProps,
81
+ type AnalyticsCardProps,
82
+ type AnalyticsLayoutProps,
83
+ type DateRangePreset,
84
+ type DateRangeValue,
85
+ type AnalyticsExportOptions,
86
+ type ConversionPath,
87
+ type HeatmapData,
88
+ type UserBehaviorPrediction,
89
+ type UserData,
90
+ type ConversionData,
91
+ type FunnelItem,
92
+ type ActivityItem,
93
+ type PerformanceMetric,
94
+ type DashboardMetrics,
95
+ type RealtimeMetrics,
96
+ } from './domains/analytics';
97
+
98
+ // Config with renamed exports to avoid conflicts
99
+ export {
100
+ DEFAULT_DASHBOARD_CONFIG,
101
+ type AnalyticsServiceType,
102
+ type ExportFormat as DashboardExportFormat,
103
+ type AnalyticsConfig as DashboardAnalyticsConfig,
104
+ type DataConfig,
105
+ type ChartsConfig,
106
+ type PerformanceConfig as DashboardPerformanceConfig,
107
+ type DashboardConfig as DashboardConfigType,
108
+ } from './domain/config';