@umituz/web-dashboard 2.5.2 → 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 +11 -2
- package/src/domain/config/DashboardConfig.ts +116 -0
- package/src/domain/config/index.ts +5 -0
- package/src/domains/analytics/hooks/useAnalytics.ts +101 -5
- package/src/domains/analytics/index.ts +20 -0
- package/src/domains/analytics/services/AnalyticsEngineService.ts +319 -0
- package/src/domains/analytics/services/PerformanceService.ts +321 -0
- package/src/domains/analytics/services/index.ts +6 -0
- package/src/domains/analytics/utils/analytics.ts +1 -1
- package/src/index.ts +108 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/web-dashboard",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Dashboard Layout System -
|
|
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
|
+
};
|
|
@@ -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 {
|
|
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 (
|
|
166
|
-
const interval = setInterval(fetchAnalytics,
|
|
184
|
+
if (effectiveRefreshInterval > 0) {
|
|
185
|
+
const interval = setInterval(fetchAnalytics, effectiveRefreshInterval);
|
|
167
186
|
return () => clearInterval(interval);
|
|
168
187
|
}
|
|
169
|
-
}, [fetchAnalytics,
|
|
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();
|
|
@@ -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) => {
|
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';
|