@umituz/web-dashboard 2.5.2 → 3.1.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.
@@ -0,0 +1,259 @@
1
+ /**
2
+ * Calendar Service
3
+ *
4
+ * Firebase-based calendar service for managing content items
5
+ */
6
+
7
+ import type {
8
+ ContentItem,
9
+ CalendarFilter,
10
+ CreateContentItemParams,
11
+ UpdateContentItemParams,
12
+ ICalendarService,
13
+ } from '../types/calendar.types';
14
+
15
+ /**
16
+ * Database interface for calendar operations
17
+ * Implementations can provide different backends
18
+ */
19
+ interface ICalendarDatabase {
20
+ getItems(userId: string): Promise<ContentItem[]>;
21
+ getItemById(id: string): Promise<ContentItem | null>;
22
+ createItem(userId: string, item: CreateContentItemParams): Promise<ContentItem>;
23
+ updateItem(id: string, updates: UpdateContentItemParams): Promise<void>;
24
+ deleteItem(id: string): Promise<void>;
25
+ }
26
+
27
+ /**
28
+ * Firebase implementation of calendar database
29
+ */
30
+ class FirebaseCalendarDatabase implements ICalendarDatabase {
31
+ async getItems(userId: string): Promise<ContentItem[]> {
32
+ // Lazy load Firebase
33
+ const { collection, query, where, getDocs } = await import('firebase/firestore');
34
+ const { db } = await import('@umituz/web-firebase');
35
+
36
+ const calendarQuery = query(
37
+ collection(db as any, 'calendar_items'),
38
+ where("user_id", "==", userId)
39
+ );
40
+
41
+ const postsQuery = query(
42
+ collection(db as any, "posts"),
43
+ where("userId", "==", userId)
44
+ );
45
+
46
+ const [calendarSnap, postsSnap] = await Promise.all([
47
+ getDocs(calendarQuery),
48
+ getDocs(postsQuery)
49
+ ]);
50
+
51
+ const calendarItems = calendarSnap.docs.map((doc: any) => ({
52
+ id: doc.id,
53
+ ...doc.data()
54
+ } as ContentItem));
55
+
56
+ const postItems = postsSnap.docs.map((doc: any) => {
57
+ const data = doc.data();
58
+ return {
59
+ id: doc.id,
60
+ title: data.title || 'Untitled Post',
61
+ description: data.content || '',
62
+ scheduled_at: data.scheduledAt
63
+ ? (typeof data.scheduledAt === 'string' ? data.scheduledAt : (data.scheduledAt as any)?.toDate?.().toISOString())
64
+ : new Date().toISOString(),
65
+ platforms: data.platform ? [data.platform] : [],
66
+ app_name: data.appName || 'My App',
67
+ status: data.status || 'draft',
68
+ type: 'post'
69
+ } as ContentItem;
70
+ });
71
+
72
+ return [...calendarItems, ...postItems].sort((a, b) =>
73
+ new Date(b.scheduled_at).getTime() - new Date(a.scheduled_at).getTime()
74
+ );
75
+ }
76
+
77
+ async getItemById(id: string): Promise<ContentItem | null> {
78
+ const { doc, getDoc } = await import('firebase/firestore');
79
+ const { db } = await import('@umituz/web-firebase');
80
+
81
+ const docRef = doc(db as any, 'calendar_items', id);
82
+ const snap = await getDoc(docRef);
83
+
84
+ if (!snap.exists()) {
85
+ return null;
86
+ }
87
+
88
+ return {
89
+ id: snap.id,
90
+ ...snap.data()
91
+ } as ContentItem;
92
+ }
93
+
94
+ async createItem(userId: string, item: CreateContentItemParams): Promise<ContentItem> {
95
+ const { collection, addDoc, serverTimestamp } = await import('firebase/firestore');
96
+ const { db } = await import('@umituz/web-firebase');
97
+
98
+ const docRef = await addDoc(collection(db as any, 'calendar_items'), {
99
+ ...item,
100
+ scheduled_at: typeof item.scheduled_at === 'string' ? item.scheduled_at : item.scheduled_at.toISOString(),
101
+ user_id: userId,
102
+ created_at: serverTimestamp(),
103
+ updated_at: serverTimestamp()
104
+ });
105
+
106
+ return {
107
+ id: docRef.id,
108
+ ...item,
109
+ scheduled_at: typeof item.scheduled_at === 'string' ? item.scheduled_at : item.scheduled_at.toISOString(),
110
+ user_id: userId,
111
+ created_at: new Date().toISOString()
112
+ } as ContentItem;
113
+ }
114
+
115
+ async updateItem(id: string, updates: UpdateContentItemParams): Promise<void> {
116
+ const { doc, updateDoc, serverTimestamp } = await import('firebase/firestore');
117
+ const { db } = await import('@umituz/web-firebase');
118
+
119
+ const docRef = doc(db as any, 'calendar_items', id);
120
+
121
+ const updateData: any = { ...updates };
122
+ if (updates.scheduled_at) {
123
+ updateData.scheduled_at = typeof updates.scheduled_at === 'string'
124
+ ? updates.scheduled_at
125
+ : updates.scheduled_at.toISOString();
126
+ }
127
+
128
+ await updateDoc(docRef, {
129
+ ...updateData,
130
+ updated_at: serverTimestamp()
131
+ });
132
+ }
133
+
134
+ async deleteItem(id: string): Promise<void> {
135
+ const { doc, deleteDoc } = await import('firebase/firestore');
136
+ const { db } = await import('@umituz/web-firebase');
137
+
138
+ const docRef = doc(db as any, 'calendar_items', id);
139
+ await deleteDoc(docRef);
140
+ }
141
+ }
142
+
143
+ /**
144
+ * Calendar Service Implementation
145
+ *
146
+ * Provides CRUD operations for calendar content items
147
+ * Uses database interface for backend abstraction
148
+ */
149
+ export class CalendarService implements ICalendarService {
150
+ private static instance: CalendarService;
151
+ private database: ICalendarDatabase;
152
+
153
+ private constructor() {
154
+ // Use Firebase implementation by default
155
+ this.database = new FirebaseCalendarDatabase();
156
+ }
157
+
158
+ public static getInstance(): CalendarService {
159
+ if (!CalendarService.instance) {
160
+ CalendarService.instance = new CalendarService();
161
+ }
162
+ return CalendarService.instance;
163
+ }
164
+
165
+ /**
166
+ * Set database implementation (for testing or custom backends)
167
+ */
168
+ setDatabase(database: ICalendarDatabase): void {
169
+ this.database = database;
170
+ }
171
+
172
+ /**
173
+ * Get all content items for a user
174
+ */
175
+ async getContentItems(userId: string, filter?: CalendarFilter): Promise<ContentItem[]> {
176
+ const items = await this.database.getItems(userId);
177
+
178
+ if (!filter) return items;
179
+
180
+ // Apply filters
181
+ return items.filter(item => {
182
+ // Search filter
183
+ if (filter.search && !item.title.toLowerCase().includes(filter.search.toLowerCase())) {
184
+ return false;
185
+ }
186
+
187
+ // Platform filter
188
+ if (filter.platforms && filter.platforms.length > 0) {
189
+ if (!item.platforms.some(p => filter.platforms?.includes(p))) {
190
+ return false;
191
+ }
192
+ }
193
+
194
+ // Type filter
195
+ if (filter.types && filter.types.length > 0) {
196
+ if (!item.type || !filter.types.includes(item.type)) {
197
+ return false;
198
+ }
199
+ }
200
+
201
+ // Status filter
202
+ if (filter.status && item.status !== filter.status) {
203
+ return false;
204
+ }
205
+
206
+ // Date range filter
207
+ if (filter.dateRange) {
208
+ const itemDate = new Date(item.scheduled_at);
209
+ if (itemDate < filter.dateRange.start || itemDate > filter.dateRange.end) {
210
+ return false;
211
+ }
212
+ }
213
+
214
+ return true;
215
+ });
216
+ }
217
+
218
+ /**
219
+ * Get a single content item by ID
220
+ */
221
+ async getContentItemById(id: string): Promise<ContentItem | null> {
222
+ return this.database.getItemById(id);
223
+ }
224
+
225
+ /**
226
+ * Create a new content item
227
+ */
228
+ async createContentItem(userId: string, item: CreateContentItemParams): Promise<ContentItem> {
229
+ return this.database.createItem(userId, item);
230
+ }
231
+
232
+ /**
233
+ * Update an existing content item
234
+ */
235
+ async updateContentItem(id: string, updates: UpdateContentItemParams): Promise<void> {
236
+ await this.database.updateItem(id, updates);
237
+ }
238
+
239
+ /**
240
+ * Delete a content item
241
+ */
242
+ async deleteContentItem(id: string): Promise<void> {
243
+ await this.database.deleteItem(id);
244
+ }
245
+
246
+ /**
247
+ * Move content item to a new date
248
+ */
249
+ async moveContentItem(id: string, newDate: Date): Promise<void> {
250
+ await this.updateContentItem(id, {
251
+ scheduled_at: newDate
252
+ });
253
+ }
254
+ }
255
+
256
+ /**
257
+ * Singleton instance
258
+ */
259
+ export const calendarService = CalendarService.getInstance();
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Calendar Services Index
3
+ */
4
+
5
+ export * from './CalendarService';
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Calendar Domain Types
3
+ */
4
+
5
+ /**
6
+ * Content item status
7
+ */
8
+ export type ContentStatus = 'draft' | 'scheduled' | 'published' | 'failed';
9
+
10
+ /**
11
+ * Content item type
12
+ */
13
+ export type ContentType = 'post' | 'story' | 'reel' | 'tweet' | 'article';
14
+
15
+ /**
16
+ * Calendar view type
17
+ */
18
+ export type CalendarView = 'month' | 'week' | 'day' | 'timeline';
19
+
20
+ /**
21
+ * Content item
22
+ */
23
+ export interface ContentItem {
24
+ id: string;
25
+ title: string;
26
+ description: string;
27
+ type?: ContentType;
28
+ status: ContentStatus;
29
+ scheduled_at: string;
30
+ platforms: string[];
31
+ app_name: string;
32
+ user_id?: string;
33
+ media_url?: string;
34
+ tags?: string[];
35
+ created_at?: string;
36
+ updated_at?: string;
37
+ }
38
+
39
+ /**
40
+ * Calendar event
41
+ */
42
+ export interface CalendarEvent {
43
+ id: string;
44
+ title: string;
45
+ date: Date;
46
+ type: 'content' | 'campaign' | 'reminder';
47
+ status: string;
48
+ color?: string;
49
+ }
50
+
51
+ /**
52
+ * Calendar filter
53
+ */
54
+ export interface CalendarFilter {
55
+ search?: string;
56
+ platforms?: string[];
57
+ types?: ContentType[];
58
+ status?: ContentStatus;
59
+ dateRange?: {
60
+ start: Date;
61
+ end: Date;
62
+ };
63
+ }
64
+
65
+ /**
66
+ * Calendar configuration
67
+ */
68
+ export interface CalendarConfig {
69
+ /** Default view */
70
+ defaultView?: CalendarView;
71
+ /** Show weekends */
72
+ showWeekends?: boolean;
73
+ /** Start of week (0-6, 0 = Sunday) */
74
+ startOfWeek?: number;
75
+ /** Hour range for day/week view */
76
+ hourRange?: {
77
+ start: number; // 0-23
78
+ end: number; // 0-23
79
+ };
80
+ /** Enable drag and drop */
81
+ enableDragDrop?: boolean;
82
+ /** Show platform filters */
83
+ showPlatformFilters?: boolean;
84
+ /** Available platforms */
85
+ platforms?: string[];
86
+ /** Time slot duration in minutes */
87
+ slotDuration?: number;
88
+ }
89
+
90
+ /**
91
+ * Content item creation params
92
+ */
93
+ export interface CreateContentItemParams {
94
+ title: string;
95
+ description: string;
96
+ scheduled_at: string | Date;
97
+ platforms: string[];
98
+ app_name: string;
99
+ type?: ContentType;
100
+ status?: ContentStatus;
101
+ media_url?: string;
102
+ tags?: string[];
103
+ }
104
+
105
+ /**
106
+ * Content item update params
107
+ */
108
+ export interface UpdateContentItemParams {
109
+ title?: string;
110
+ description?: string;
111
+ scheduled_at?: string | Date;
112
+ platforms?: string[];
113
+ type?: ContentType;
114
+ status?: ContentStatus;
115
+ media_url?: string;
116
+ tags?: string[];
117
+ }
118
+
119
+ /**
120
+ * Calendar service interface
121
+ */
122
+ export interface ICalendarService {
123
+ getContentItems(userId: string, filter?: CalendarFilter): Promise<ContentItem[]>;
124
+ getContentItemById(id: string): Promise<ContentItem | null>;
125
+ createContentItem(userId: string, item: CreateContentItemParams): Promise<ContentItem>;
126
+ updateContentItem(id: string, updates: UpdateContentItemParams): Promise<void>;
127
+ deleteContentItem(id: string): Promise<void>;
128
+ moveContentItem(id: string, newDate: Date): Promise<void>;
129
+ }
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Calendar Domain Utilities
3
+ */
4
+
5
+ import type { CalendarConfig } from '../types/calendar.types';
6
+
7
+ /**
8
+ * Default calendar configuration
9
+ */
10
+ export const DEFAULT_CALENDAR_CONFIG: CalendarConfig = {
11
+ defaultView: 'month',
12
+ showWeekends: true,
13
+ startOfWeek: 0, // Sunday
14
+ hourRange: {
15
+ start: 0,
16
+ end: 23,
17
+ },
18
+ enableDragDrop: true,
19
+ showPlatformFilters: true,
20
+ platforms: ['instagram', 'facebook', 'twitter', 'linkedin', 'tiktok'],
21
+ slotDuration: 30, // 30 minutes
22
+ };
23
+
24
+ /**
25
+ * Get week dates for a given date
26
+ */
27
+ export function getWeekDates(date: Date, startOfWeek: number = 0): Date[] {
28
+ const week = [];
29
+ const current = new Date(date);
30
+
31
+ // Find the first day of the week
32
+ const day = current.getDay();
33
+ const diff = (day < startOfWeek ? 7 : 0) + day - startOfWeek;
34
+ current.setDate(current.getDate() - diff);
35
+
36
+ // Get 7 days
37
+ for (let i = 0; i < 7; i++) {
38
+ week.push(new Date(current));
39
+ current.setDate(current.getDate() + 1);
40
+ }
41
+
42
+ return week;
43
+ }
44
+
45
+ /**
46
+ * Get month days
47
+ */
48
+ export function getMonthDays(date: Date): Date[] {
49
+ const year = date.getFullYear();
50
+ const month = date.getMonth();
51
+ const days: Date[] = [];
52
+
53
+ const firstDay = new Date(year, month, 1);
54
+ const lastDay = new Date(year, month + 1, 0);
55
+
56
+ for (let d = new Date(firstDay); d <= lastDay; d.setDate(d.getDate() + 1)) {
57
+ days.push(new Date(d));
58
+ }
59
+
60
+ return days;
61
+ }
62
+
63
+ /**
64
+ * Check if date is in range
65
+ */
66
+ export function isDateInRange(date: Date, range: { start: Date; end: Date }): boolean {
67
+ return date >= range.start && date <= range.end;
68
+ }
69
+
70
+ /**
71
+ * Format date for display
72
+ */
73
+ export function formatDate(date: Date, format: 'short' | 'long' | 'time' = 'short'): string {
74
+ if (format === 'time') {
75
+ return date.toLocaleTimeString('en-US', {
76
+ hour: '2-digit',
77
+ minute: '2-digit',
78
+ });
79
+ }
80
+
81
+ return date.toLocaleDateString('en-US', {
82
+ month: format === 'long' ? 'long' : 'short',
83
+ day: 'numeric',
84
+ year: 'numeric',
85
+ });
86
+ }
87
+
88
+ /**
89
+ * Check if dates are same day
90
+ */
91
+ export function isSameDay(date1: Date, date2: Date): boolean {
92
+ return (
93
+ date1.getFullYear() === date2.getFullYear() &&
94
+ date1.getMonth() === date2.getMonth() &&
95
+ date1.getDate() === date2.getDate()
96
+ );
97
+ }
98
+
99
+ /**
100
+ * Get date range for a view
101
+ */
102
+ export function getViewRange(view: 'month' | 'week', date: Date): { start: Date; end: Date } {
103
+ if (view === 'month') {
104
+ const start = new Date(date.getFullYear(), date.getMonth(), 1);
105
+ const end = new Date(date.getFullYear(), date.getMonth() + 1, 0);
106
+ return { start, end };
107
+ }
108
+
109
+ // Week view
110
+ const week = getWeekDates(date);
111
+ return {
112
+ start: new Date(week[0].setHours(0, 0, 0, 0)),
113
+ end: new Date(week[6].setHours(23, 59, 59, 999)),
114
+ };
115
+ }
116
+
117
+ /**
118
+ * Generate time slots
119
+ */
120
+ export function generateTimeSlots(startHour: number, endHour: number, slotDuration: number): string[] {
121
+ const slots: string[] = [];
122
+
123
+ for (let hour = startHour; hour < endHour; hour++) {
124
+ for (let minute = 0; minute < 60; minute += slotDuration) {
125
+ const time = `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`;
126
+ slots.push(time);
127
+ }
128
+ }
129
+
130
+ return slots;
131
+ }
package/src/index.ts ADDED
@@ -0,0 +1,140 @@
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
+ // Domains - using selective exports to avoid conflicts
16
+ export * from './domains/layouts';
17
+ export * from './domains/settings';
18
+ export * from './domains/billing';
19
+ export * from './domains/calendar';
20
+ export {
21
+ OnboardingWizard,
22
+ useOnboarding,
23
+ useOnboardingStep,
24
+ } from './domains/onboarding';
25
+
26
+ export type {
27
+ OnboardingStep,
28
+ OnboardingState,
29
+ OnboardingConfig,
30
+ } from './domains/onboarding';
31
+
32
+ export {
33
+ AuthLayout,
34
+ LoginForm,
35
+ RegisterForm,
36
+ useAuth,
37
+ type LoginCredentials,
38
+ type RegisterData,
39
+ type User,
40
+ } from './domains/auth';
41
+
42
+ // Analytics with conflict resolution
43
+ export {
44
+ useAnalytics,
45
+ MetricCard,
46
+ AnalyticsChart,
47
+ AnalyticsCard,
48
+ AnalyticsLayout,
49
+ formatNumber,
50
+ formatPercentage,
51
+ formatCurrency,
52
+ calculateGrowth,
53
+ getTrend,
54
+ createKPI,
55
+ createMetric,
56
+ formatMetricValue,
57
+ calculateConversionRate,
58
+ calculateDropOffRate,
59
+ createDateRangePreset,
60
+ getDateRangePresets,
61
+ aggregateByPeriod,
62
+ calculateMovingAverage,
63
+ detectOutliers,
64
+ roundTo,
65
+ generateColor,
66
+ generateChartColors,
67
+ // Services
68
+ AnalyticsEngineService,
69
+ analyticsEngineService,
70
+ PerformanceService,
71
+ performanceService,
72
+ // Types
73
+ type Metric,
74
+ type TimeSeriesData,
75
+ type ChartData,
76
+ type FunnelStep,
77
+ type FunnelData,
78
+ type CohortAnalysis,
79
+ type UserSegment,
80
+ type KPIData,
81
+ type KPIs,
82
+ type ChartType,
83
+ type ChartConfig,
84
+ type MetricCardProps,
85
+ type AnalyticsCardProps,
86
+ type AnalyticsLayoutProps,
87
+ type DateRangePreset,
88
+ type DateRangeValue,
89
+ type AnalyticsExportOptions,
90
+ type ConversionPath,
91
+ type HeatmapData,
92
+ type UserBehaviorPrediction,
93
+ type UserData,
94
+ type ConversionData,
95
+ type FunnelItem,
96
+ type ActivityItem,
97
+ type PerformanceMetric,
98
+ type DashboardMetrics,
99
+ type RealtimeMetrics,
100
+ } from './domains/analytics';
101
+
102
+ // Calendar
103
+ export {
104
+ useCalendar,
105
+ calendarService,
106
+ // Services
107
+ CalendarService,
108
+ // Utils
109
+ getWeekDates,
110
+ getMonthDays,
111
+ isDateInRange,
112
+ formatDate,
113
+ isSameDay,
114
+ getViewRange,
115
+ generateTimeSlots,
116
+ // Types
117
+ type ContentItem,
118
+ type CalendarEvent,
119
+ type CalendarFilter,
120
+ type CalendarConfig,
121
+ type ContentStatus,
122
+ type ContentType,
123
+ type CalendarView,
124
+ type CreateContentItemParams,
125
+ type UpdateContentItemParams,
126
+ type ICalendarService,
127
+ } from './domains/calendar';
128
+
129
+ // Config with renamed exports to avoid conflicts
130
+ export {
131
+ DEFAULT_DASHBOARD_CONFIG,
132
+ DEFAULT_CALENDAR_CONFIG,
133
+ type AnalyticsServiceType,
134
+ type ExportFormat as DashboardExportFormat,
135
+ type AnalyticsConfig as DashboardAnalyticsConfig,
136
+ type DataConfig,
137
+ type ChartsConfig,
138
+ type PerformanceConfig as DashboardPerformanceConfig,
139
+ type DashboardConfig as DashboardConfigType,
140
+ } from './domain/config';