shared-features 0.0.8 → 0.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.
- package/README.md +205 -2
- package/dist/{admin-notifications-D9n9h-eY.cjs → admin-notifications-D1GgYCJW.cjs} +20 -20
- package/dist/{admin-notifications-D9n9h-eY.cjs.map → admin-notifications-D1GgYCJW.cjs.map} +1 -1
- package/dist/{admin-notifications-p1dy3zIP.js → admin-notifications-NI7I76uY.js} +13 -13
- package/dist/{admin-notifications-p1dy3zIP.js.map → admin-notifications-NI7I76uY.js.map} +1 -1
- package/dist/{broadcasts-3_WfQMNL.cjs → broadcasts-BMoTZIuX.cjs} +10 -10
- package/dist/{broadcasts-3_WfQMNL.cjs.map → broadcasts-BMoTZIuX.cjs.map} +1 -1
- package/dist/{broadcasts-DgZUzqMf.js → broadcasts-DnzZkCoy.js} +12 -12
- package/dist/{broadcasts-DgZUzqMf.js.map → broadcasts-DnzZkCoy.js.map} +1 -1
- package/dist/commonFeatures-Bdt0UZox.js +1255 -0
- package/dist/commonFeatures-Bdt0UZox.js.map +1 -0
- package/dist/commonFeatures-CiqxxOin.cjs +1276 -0
- package/dist/commonFeatures-CiqxxOin.cjs.map +1 -0
- package/dist/commonFeatures-Cr5g1E4M.cjs +200 -0
- package/dist/commonFeatures-Cr5g1E4M.cjs.map +1 -0
- package/dist/commonFeatures-HT-UO7HW.js +201 -0
- package/dist/commonFeatures-HT-UO7HW.js.map +1 -0
- package/dist/components/common/index.d.ts +53 -0
- package/dist/components/common/index.d.ts.map +1 -0
- package/dist/components/index.cjs +31 -23
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +21 -13
- package/dist/firebase/config.d.ts +34 -0
- package/dist/firebase/config.d.ts.map +1 -1
- package/dist/hooks/index.cjs +26 -13
- package/dist/hooks/index.cjs.map +1 -1
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +24 -11
- package/dist/hooks/useCommonFeatures.d.ts +74 -0
- package/dist/hooks/useCommonFeatures.d.ts.map +1 -0
- package/dist/hooks/useFeatureFlags.d.ts +134 -0
- package/dist/hooks/useFeatureFlags.d.ts.map +1 -0
- package/dist/{AnnouncementModal-Bqy0pn3V.cjs → index-Dt5YjYnK.cjs} +209 -14
- package/dist/index-Dt5YjYnK.cjs.map +1 -0
- package/dist/{AnnouncementModal-sxH4K5gy.js → index-Dv34aG2I.js} +212 -17
- package/dist/index-Dv34aG2I.js.map +1 -0
- package/dist/index.cjs +125 -60
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +10 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +173 -108
- package/dist/index.js.map +1 -1
- package/dist/notifications/index.js +14 -14
- package/dist/services/commonFeatures.d.ts +22 -0
- package/dist/services/commonFeatures.d.ts.map +1 -0
- package/dist/services/featureFlags.d.ts +71 -0
- package/dist/services/featureFlags.d.ts.map +1 -0
- package/dist/services/index.cjs +49 -17
- package/dist/services/index.cjs.map +1 -1
- package/dist/services/index.d.ts +2 -0
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +75 -43
- package/dist/services/index.js.map +1 -1
- package/dist/types/commonFeatures.d.ts +194 -0
- package/dist/types/commonFeatures.d.ts.map +1 -0
- package/dist/types/featureFlags.d.ts +203 -0
- package/dist/types/featureFlags.d.ts.map +1 -0
- package/dist/types/index.cjs +15 -0
- package/dist/types/index.cjs.map +1 -1
- package/dist/types/index.d.ts +3 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +15 -0
- package/dist/types/index.js.map +1 -1
- package/dist/useCommonFeatures-CgyDq6LZ.js +489 -0
- package/dist/useCommonFeatures-CgyDq6LZ.js.map +1 -0
- package/dist/useCommonFeatures-DnDlhmri.cjs +488 -0
- package/dist/useCommonFeatures-DnDlhmri.cjs.map +1 -0
- package/dist/useFeatureFlags-BRJSyH9M.js +368 -0
- package/dist/useFeatureFlags-BRJSyH9M.js.map +1 -0
- package/dist/useFeatureFlags-DXqBJ5Mh.cjs +367 -0
- package/dist/useFeatureFlags-DXqBJ5Mh.cjs.map +1 -0
- package/dist/{useNotificationEvents-D8DVxah1.js → useNotificationEvents-DAmR7FYF.js} +14 -14
- package/dist/{useNotificationEvents-D8DVxah1.js.map → useNotificationEvents-DAmR7FYF.js.map} +1 -1
- package/package.json +15 -8
- package/dist/AnnouncementModal-Bqy0pn3V.cjs.map +0 -1
- package/dist/AnnouncementModal-sxH4K5gy.js.map +0 -1
- package/dist/analytics-40-S_fHC.js +0 -440
- package/dist/analytics-40-S_fHC.js.map +0 -1
- package/dist/analytics-lEzOx2vl.cjs +0 -461
- package/dist/analytics-lEzOx2vl.cjs.map +0 -1
- package/dist/useBroadcasts-DzpCcbC8.js +0 -161
- package/dist/useBroadcasts-DzpCcbC8.js.map +0 -1
- package/dist/useBroadcasts-FP6ZrcY_.cjs +0 -160
- package/dist/useBroadcasts-FP6ZrcY_.cjs.map +0 -1
- package/dist/useCampaigns-BOZ9dDsG.cjs +0 -152
- package/dist/useCampaigns-BOZ9dDsG.cjs.map +0 -1
- package/dist/useCampaigns-D46b9zuf.js +0 -153
- package/dist/useCampaigns-D46b9zuf.js.map +0 -1
package/README.md
CHANGED
|
@@ -6,12 +6,13 @@ Centralized common features for Zaions projects. Manage ads, notifications, cont
|
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## Three Core Systems
|
|
10
10
|
|
|
11
|
-
This package provides **
|
|
11
|
+
This package provides **three systems** for cross-project feature management:
|
|
12
12
|
|
|
13
13
|
| System | Purpose | Firestore Collections | Admin Location |
|
|
14
14
|
|--------|---------|----------------------|----------------|
|
|
15
|
+
| **Feature Flags** | Version management, feature toggles | `zaions_feature_flags` | `/admin/settings` |
|
|
15
16
|
| **Advertising Campaigns** | Promote Zaions products across apps | `zaions_campaigns`, `zaions_products`, `zaions_impressions` | `/admin/campaigns` |
|
|
16
17
|
| **Broadcasts/Notifications** | In-app notifications, announcements, alerts | `zaions_broadcasts`, `zaions_broadcast_events`, `zaions_notification_templates` | `/admin/notifications` |
|
|
17
18
|
|
|
@@ -98,12 +99,156 @@ if (import.meta.env.VITE_SHARED_FEATURES_API_KEY) {
|
|
|
98
99
|
projectName: 'Your Project Name', // e.g., 'ZTools', '2FA Studio'
|
|
99
100
|
platform: 'web', // or 'android', 'ios', 'extension'
|
|
100
101
|
debug: import.meta.env.DEV, // optional
|
|
102
|
+
// Optional: Lock to specific feature versions
|
|
103
|
+
featureVersions: {
|
|
104
|
+
campaigns: 1,
|
|
105
|
+
broadcasts: 1,
|
|
106
|
+
},
|
|
101
107
|
});
|
|
102
108
|
}
|
|
103
109
|
```
|
|
104
110
|
|
|
105
111
|
---
|
|
106
112
|
|
|
113
|
+
# FEATURE FLAGS SYSTEM
|
|
114
|
+
|
|
115
|
+
Manage feature availability, versioning, and breaking changes across all consumer projects.
|
|
116
|
+
|
|
117
|
+
## Why Feature Flags?
|
|
118
|
+
|
|
119
|
+
- **Version Control**: Roll out breaking changes gradually
|
|
120
|
+
- **Feature Toggles**: Enable/disable features globally
|
|
121
|
+
- **Deprecation Warnings**: Warn consumers about outdated versions
|
|
122
|
+
- **Maintenance Mode**: Show maintenance messages across all apps
|
|
123
|
+
- **Platform/Project Targeting**: Enable features for specific platforms or projects
|
|
124
|
+
|
|
125
|
+
## Firestore Collection
|
|
126
|
+
|
|
127
|
+
| Collection | Purpose | Access |
|
|
128
|
+
|------------|---------|--------|
|
|
129
|
+
| `zaions_feature_flags` | Global feature configuration (singleton) | Public read, Admin write |
|
|
130
|
+
|
|
131
|
+
## Checking Feature Availability
|
|
132
|
+
|
|
133
|
+
### Check Overall Status
|
|
134
|
+
|
|
135
|
+
```tsx
|
|
136
|
+
import { useFeatureFlags } from 'shared-features';
|
|
137
|
+
|
|
138
|
+
function App() {
|
|
139
|
+
const { status, loading, isFeatureAvailable, hasDeprecatedFeatures } = useFeatureFlags();
|
|
140
|
+
|
|
141
|
+
if (loading) return <Spinner />;
|
|
142
|
+
|
|
143
|
+
// Handle maintenance mode
|
|
144
|
+
if (status?.maintenanceMode) {
|
|
145
|
+
return <MaintenancePage message={status.maintenanceMessage} />;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Warn about deprecated features
|
|
149
|
+
if (hasDeprecatedFeatures) {
|
|
150
|
+
console.warn('Some features are deprecated:', status?.deprecatedFeatures);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Check specific feature
|
|
154
|
+
if (isFeatureAvailable('contactInfo')) {
|
|
155
|
+
return <ContactInfo />;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return <App />;
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Check Single Feature
|
|
163
|
+
|
|
164
|
+
```tsx
|
|
165
|
+
import { useFeature } from 'shared-features';
|
|
166
|
+
|
|
167
|
+
function ContactSection() {
|
|
168
|
+
const { available, loading, deprecated, deprecationWarning } = useFeature('contactInfo');
|
|
169
|
+
|
|
170
|
+
if (loading) return <Spinner />;
|
|
171
|
+
if (!available) return <LegacyContactInfo />;
|
|
172
|
+
|
|
173
|
+
if (deprecated) {
|
|
174
|
+
console.warn(deprecationWarning);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return <NewContactInfo />;
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Conditional Rendering with Feature Gates
|
|
182
|
+
|
|
183
|
+
```tsx
|
|
184
|
+
import { useFeatureGate } from 'shared-features';
|
|
185
|
+
|
|
186
|
+
function MyComponent() {
|
|
187
|
+
const { shouldRender, FallbackOrChildren } = useFeatureGate('socialLinks');
|
|
188
|
+
|
|
189
|
+
return (
|
|
190
|
+
<FallbackOrChildren fallback={<OldSocialLinks />}>
|
|
191
|
+
<NewSocialLinks />
|
|
192
|
+
</FallbackOrChildren>
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Real-time Updates
|
|
198
|
+
|
|
199
|
+
```tsx
|
|
200
|
+
import { useFeatureFlagsSubscription } from 'shared-features';
|
|
201
|
+
|
|
202
|
+
function App() {
|
|
203
|
+
useFeatureFlagsSubscription((status) => {
|
|
204
|
+
if (status?.maintenanceMode) {
|
|
205
|
+
showMaintenanceBanner(status.maintenanceMessage);
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
return <YourApp />;
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## Available Features
|
|
214
|
+
|
|
215
|
+
| Feature ID | Description | Status |
|
|
216
|
+
|------------|-------------|--------|
|
|
217
|
+
| `campaigns` | Advertising campaigns | ✅ Enabled |
|
|
218
|
+
| `broadcasts` | Broadcast notifications | ✅ Enabled |
|
|
219
|
+
| `contactInfo` | Contact information | ⏳ Coming Soon |
|
|
220
|
+
| `developerInfo` | Developer information | ⏳ Coming Soon |
|
|
221
|
+
| `socialLinks` | Social media links | ⏳ Coming Soon |
|
|
222
|
+
| `paymentOptions` | Payment methods | ⏳ Coming Soon |
|
|
223
|
+
| `addressInfo` | Address information | ⏳ Coming Soon |
|
|
224
|
+
| `services` | Professional services | ⏳ Coming Soon |
|
|
225
|
+
| `skills` | Skills display | ⏳ Coming Soon |
|
|
226
|
+
| `testimonials` | Client testimonials | ⏳ Coming Soon |
|
|
227
|
+
| `projects` | Portfolio projects | ⏳ Coming Soon |
|
|
228
|
+
|
|
229
|
+
## Feature Versioning
|
|
230
|
+
|
|
231
|
+
When breaking changes are introduced:
|
|
232
|
+
|
|
233
|
+
1. Admin bumps feature version in `zaions_feature_flags`
|
|
234
|
+
2. Consumers using old version get deprecation warnings
|
|
235
|
+
3. Once `minVersion` is bumped, old consumers get `upgradeRequired: true`
|
|
236
|
+
4. Consumers update their code and bump `featureVersions` in config
|
|
237
|
+
|
|
238
|
+
```typescript
|
|
239
|
+
// Consumer specifies supported versions
|
|
240
|
+
initSharedFeatures({
|
|
241
|
+
// ... other config
|
|
242
|
+
featureVersions: {
|
|
243
|
+
campaigns: 1, // Using v1 API
|
|
244
|
+
broadcasts: 1, // Using v1 API
|
|
245
|
+
contactInfo: 2, // Updated to v2 API
|
|
246
|
+
},
|
|
247
|
+
});
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
107
252
|
# ADVERTISING CAMPAIGNS SYSTEM
|
|
108
253
|
|
|
109
254
|
Cross-promote Zaions products (ZTools, FilesHub, etc.) across all projects.
|
|
@@ -345,9 +490,67 @@ interface SharedFeaturesConfig {
|
|
|
345
490
|
projectName: string; // e.g., 'ZTools'
|
|
346
491
|
platform: 'web' | 'android' | 'ios' | 'extension';
|
|
347
492
|
debug?: boolean;
|
|
493
|
+
featureVersions?: ConsumerFeatureVersions; // Optional version preferences
|
|
494
|
+
}
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
## Feature Flag Hooks
|
|
498
|
+
|
|
499
|
+
### `useFeatureFlags(options?)`
|
|
500
|
+
|
|
501
|
+
Check overall feature flags status.
|
|
502
|
+
|
|
503
|
+
```typescript
|
|
504
|
+
interface UseFeatureFlagsOptions {
|
|
505
|
+
autoRefresh?: boolean; // Auto-refresh flags periodically
|
|
506
|
+
refreshInterval?: number; // Refresh interval in ms (default: 5 min)
|
|
507
|
+
autoFetch?: boolean; // Fetch on mount (default: true)
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
interface UseFeatureFlagsResult {
|
|
511
|
+
status: SharedFeaturesStatus | null;
|
|
512
|
+
loading: boolean;
|
|
513
|
+
error: string | null;
|
|
514
|
+
refetch: () => Promise<void>;
|
|
515
|
+
isFeatureAvailable: (featureId: FeatureId) => boolean;
|
|
516
|
+
getFeatureAvailability: (featureId: FeatureId) => FeatureAvailability | null;
|
|
517
|
+
hasDeprecatedFeatures: boolean;
|
|
518
|
+
hasUpgradeRequired: boolean;
|
|
348
519
|
}
|
|
349
520
|
```
|
|
350
521
|
|
|
522
|
+
### `useFeature(featureId)`
|
|
523
|
+
|
|
524
|
+
Check a single feature's availability.
|
|
525
|
+
|
|
526
|
+
```typescript
|
|
527
|
+
const {
|
|
528
|
+
available, // Feature can be used
|
|
529
|
+
loading, // Check in progress
|
|
530
|
+
enabled, // Feature is enabled (but might need upgrade)
|
|
531
|
+
deprecated, // Using deprecated version
|
|
532
|
+
upgradeRequired, // Must upgrade to use
|
|
533
|
+
deprecationWarning, // Warning message
|
|
534
|
+
unavailableReason, // Why unavailable
|
|
535
|
+
} = useFeature('contactInfo');
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
### `useFeatureGate(featureId)`
|
|
539
|
+
|
|
540
|
+
Conditional rendering helper.
|
|
541
|
+
|
|
542
|
+
```typescript
|
|
543
|
+
const { shouldRender, loading, deprecated, FallbackOrChildren } = useFeatureGate('socialLinks');
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
### `useFeatureFlagsSubscription(callback)`
|
|
547
|
+
|
|
548
|
+
Real-time feature flag updates.
|
|
549
|
+
|
|
550
|
+
### `useSharedFeaturesOperational()`
|
|
551
|
+
|
|
552
|
+
Quick check if shared-features is operational.
|
|
553
|
+
|
|
351
554
|
## Advertising Hooks
|
|
352
555
|
|
|
353
556
|
### `useCampaigns(options)`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const firestore = require("firebase/firestore");
|
|
3
|
-
const
|
|
3
|
+
const commonFeatures = require("./commonFeatures-CiqxxOin.cjs");
|
|
4
4
|
const COLLECTION_BROADCASTS = "zaions_broadcasts";
|
|
5
5
|
const COLLECTION_TEMPLATES = "zaions_notification_templates";
|
|
6
6
|
const COLLECTION_BROADCAST_EVENTS = "zaions_broadcast_events";
|
|
@@ -51,7 +51,7 @@ function docToTemplate(docId, data) {
|
|
|
51
51
|
};
|
|
52
52
|
}
|
|
53
53
|
async function createBroadcast(input, adminUserId) {
|
|
54
|
-
const db =
|
|
54
|
+
const db = commonFeatures.getSharedFeaturesDb();
|
|
55
55
|
const broadcastData = {
|
|
56
56
|
...input,
|
|
57
57
|
status: "draft",
|
|
@@ -70,7 +70,7 @@ async function createBroadcast(input, adminUserId) {
|
|
|
70
70
|
return docRef.id;
|
|
71
71
|
}
|
|
72
72
|
async function updateBroadcast(input, adminUserId) {
|
|
73
|
-
const db =
|
|
73
|
+
const db = commonFeatures.getSharedFeaturesDb();
|
|
74
74
|
const updateData = {
|
|
75
75
|
...input,
|
|
76
76
|
updatedBy: adminUserId,
|
|
@@ -86,11 +86,11 @@ async function updateBroadcast(input, adminUserId) {
|
|
|
86
86
|
await firestore.updateDoc(firestore.doc(db, COLLECTION_BROADCASTS, input.id), updateData);
|
|
87
87
|
}
|
|
88
88
|
async function deleteBroadcast(broadcastId) {
|
|
89
|
-
const db =
|
|
89
|
+
const db = commonFeatures.getSharedFeaturesDb();
|
|
90
90
|
await firestore.deleteDoc(firestore.doc(db, COLLECTION_BROADCASTS, broadcastId));
|
|
91
91
|
}
|
|
92
92
|
async function getAllBroadcasts() {
|
|
93
|
-
const db =
|
|
93
|
+
const db = commonFeatures.getSharedFeaturesDb();
|
|
94
94
|
const q = firestore.query(
|
|
95
95
|
firestore.collection(db, COLLECTION_BROADCASTS),
|
|
96
96
|
firestore.orderBy("createdAt", "desc")
|
|
@@ -99,7 +99,7 @@ async function getAllBroadcasts() {
|
|
|
99
99
|
return snapshot.docs.map((d) => docToBroadcast(d.id, d.data()));
|
|
100
100
|
}
|
|
101
101
|
async function getBroadcastsByStatus(status) {
|
|
102
|
-
const db =
|
|
102
|
+
const db = commonFeatures.getSharedFeaturesDb();
|
|
103
103
|
const q = firestore.query(
|
|
104
104
|
firestore.collection(db, COLLECTION_BROADCASTS),
|
|
105
105
|
firestore.where("status", "==", status),
|
|
@@ -109,13 +109,13 @@ async function getBroadcastsByStatus(status) {
|
|
|
109
109
|
return snapshot.docs.map((d) => docToBroadcast(d.id, d.data()));
|
|
110
110
|
}
|
|
111
111
|
async function getBroadcastById(broadcastId) {
|
|
112
|
-
const db =
|
|
112
|
+
const db = commonFeatures.getSharedFeaturesDb();
|
|
113
113
|
const docSnap = await firestore.getDoc(firestore.doc(db, COLLECTION_BROADCASTS, broadcastId));
|
|
114
114
|
if (!docSnap.exists()) return null;
|
|
115
115
|
return docToBroadcast(docSnap.id, docSnap.data());
|
|
116
116
|
}
|
|
117
117
|
async function publishBroadcast(broadcastId, adminUserId) {
|
|
118
|
-
const db =
|
|
118
|
+
const db = commonFeatures.getSharedFeaturesDb();
|
|
119
119
|
await firestore.updateDoc(firestore.doc(db, COLLECTION_BROADCASTS, broadcastId), {
|
|
120
120
|
status: "active",
|
|
121
121
|
updatedBy: adminUserId,
|
|
@@ -123,7 +123,7 @@ async function publishBroadcast(broadcastId, adminUserId) {
|
|
|
123
123
|
});
|
|
124
124
|
}
|
|
125
125
|
async function scheduleBroadcast(broadcastId, scheduledDate, adminUserId) {
|
|
126
|
-
const db =
|
|
126
|
+
const db = commonFeatures.getSharedFeaturesDb();
|
|
127
127
|
await firestore.updateDoc(firestore.doc(db, COLLECTION_BROADCASTS, broadcastId), {
|
|
128
128
|
status: "scheduled",
|
|
129
129
|
startDate: firestore.Timestamp.fromDate(scheduledDate),
|
|
@@ -132,7 +132,7 @@ async function scheduleBroadcast(broadcastId, scheduledDate, adminUserId) {
|
|
|
132
132
|
});
|
|
133
133
|
}
|
|
134
134
|
async function pauseBroadcast(broadcastId, adminUserId) {
|
|
135
|
-
const db =
|
|
135
|
+
const db = commonFeatures.getSharedFeaturesDb();
|
|
136
136
|
await firestore.updateDoc(firestore.doc(db, COLLECTION_BROADCASTS, broadcastId), {
|
|
137
137
|
status: "draft",
|
|
138
138
|
// Move back to draft
|
|
@@ -141,7 +141,7 @@ async function pauseBroadcast(broadcastId, adminUserId) {
|
|
|
141
141
|
});
|
|
142
142
|
}
|
|
143
143
|
async function endBroadcast(broadcastId, adminUserId) {
|
|
144
|
-
const db =
|
|
144
|
+
const db = commonFeatures.getSharedFeaturesDb();
|
|
145
145
|
await firestore.updateDoc(firestore.doc(db, COLLECTION_BROADCASTS, broadcastId), {
|
|
146
146
|
status: "ended",
|
|
147
147
|
endDate: firestore.serverTimestamp(),
|
|
@@ -150,7 +150,7 @@ async function endBroadcast(broadcastId, adminUserId) {
|
|
|
150
150
|
});
|
|
151
151
|
}
|
|
152
152
|
async function createTemplate(input) {
|
|
153
|
-
const db =
|
|
153
|
+
const db = commonFeatures.getSharedFeaturesDb();
|
|
154
154
|
const templateData = {
|
|
155
155
|
...input,
|
|
156
156
|
createdAt: firestore.serverTimestamp(),
|
|
@@ -163,18 +163,18 @@ async function createTemplate(input) {
|
|
|
163
163
|
return docRef.id;
|
|
164
164
|
}
|
|
165
165
|
async function updateTemplate(templateId, input) {
|
|
166
|
-
const db =
|
|
166
|
+
const db = commonFeatures.getSharedFeaturesDb();
|
|
167
167
|
await firestore.updateDoc(firestore.doc(db, COLLECTION_TEMPLATES, templateId), {
|
|
168
168
|
...input,
|
|
169
169
|
updatedAt: firestore.serverTimestamp()
|
|
170
170
|
});
|
|
171
171
|
}
|
|
172
172
|
async function deleteTemplate(templateId) {
|
|
173
|
-
const db =
|
|
173
|
+
const db = commonFeatures.getSharedFeaturesDb();
|
|
174
174
|
await firestore.deleteDoc(firestore.doc(db, COLLECTION_TEMPLATES, templateId));
|
|
175
175
|
}
|
|
176
176
|
async function getAllTemplates() {
|
|
177
|
-
const db =
|
|
177
|
+
const db = commonFeatures.getSharedFeaturesDb();
|
|
178
178
|
const q = firestore.query(
|
|
179
179
|
firestore.collection(db, COLLECTION_TEMPLATES),
|
|
180
180
|
firestore.orderBy("name", "asc")
|
|
@@ -183,13 +183,13 @@ async function getAllTemplates() {
|
|
|
183
183
|
return snapshot.docs.map((d) => docToTemplate(d.id, d.data()));
|
|
184
184
|
}
|
|
185
185
|
async function getTemplateById(templateId) {
|
|
186
|
-
const db =
|
|
186
|
+
const db = commonFeatures.getSharedFeaturesDb();
|
|
187
187
|
const docSnap = await firestore.getDoc(firestore.doc(db, COLLECTION_TEMPLATES, templateId));
|
|
188
188
|
if (!docSnap.exists()) return null;
|
|
189
189
|
return docToTemplate(docSnap.id, docSnap.data());
|
|
190
190
|
}
|
|
191
191
|
async function getFirestoreTemplateByEventType(eventType) {
|
|
192
|
-
const db =
|
|
192
|
+
const db = commonFeatures.getSharedFeaturesDb();
|
|
193
193
|
const q = firestore.query(
|
|
194
194
|
firestore.collection(db, COLLECTION_TEMPLATES),
|
|
195
195
|
firestore.where("eventType", "==", eventType)
|
|
@@ -201,7 +201,7 @@ async function getFirestoreTemplateByEventType(eventType) {
|
|
|
201
201
|
return docToTemplate(docSnap.id, docSnap.data());
|
|
202
202
|
}
|
|
203
203
|
async function getBroadcastAnalytics(broadcastId) {
|
|
204
|
-
const db =
|
|
204
|
+
const db = commonFeatures.getSharedFeaturesDb();
|
|
205
205
|
const broadcast = await getBroadcastById(broadcastId);
|
|
206
206
|
if (!broadcast) return null;
|
|
207
207
|
const eventsQuery = firestore.query(
|
|
@@ -264,7 +264,7 @@ async function getBroadcastAnalytics(broadcastId) {
|
|
|
264
264
|
};
|
|
265
265
|
}
|
|
266
266
|
async function getOverallAnalytics(startDate, endDate) {
|
|
267
|
-
const db =
|
|
267
|
+
const db = commonFeatures.getSharedFeaturesDb();
|
|
268
268
|
const eventsQuery = firestore.query(
|
|
269
269
|
firestore.collection(db, COLLECTION_BROADCAST_EVENTS),
|
|
270
270
|
firestore.where("timestamp", ">=", firestore.Timestamp.fromDate(startDate)),
|
|
@@ -359,4 +359,4 @@ exports.publishBroadcast = publishBroadcast;
|
|
|
359
359
|
exports.scheduleBroadcast = scheduleBroadcast;
|
|
360
360
|
exports.updateBroadcast = updateBroadcast;
|
|
361
361
|
exports.updateTemplate = updateTemplate;
|
|
362
|
-
//# sourceMappingURL=admin-notifications-
|
|
362
|
+
//# sourceMappingURL=admin-notifications-D1GgYCJW.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin-notifications-D9n9h-eY.cjs","sources":["../src/services/admin-notifications.ts"],"sourcesContent":["/**\n * Admin Notifications Service\n *\n * Service for managing broadcasts and templates from the admin panel.\n * Used in aoneahsan.com admin panel to manage cross-project notifications.\n *\n * @author Ahsan Mahmood <aoneahsan@gmail.com>\n */\n\nimport {\n collection,\n doc,\n getDocs,\n getDoc,\n updateDoc,\n deleteDoc,\n addDoc,\n query,\n where,\n orderBy,\n serverTimestamp,\n Timestamp,\n} from 'firebase/firestore';\nimport { getSharedFeaturesDb } from '../firebase/init';\nimport type {\n BroadcastNotification,\n BroadcastStatus,\n CreateBroadcastInput,\n UpdateBroadcastInput,\n NotificationTemplate,\n CreateTemplateInput,\n BroadcastAnalytics,\n NotificationAnalytics,\n} from '../types/notifications';\n\n// ============================================================================\n// CONSTANTS\n// ============================================================================\n\nconst COLLECTION_BROADCASTS = 'zaions_broadcasts';\nconst COLLECTION_TEMPLATES = 'zaions_notification_templates';\nconst COLLECTION_BROADCAST_EVENTS = 'zaions_broadcast_events';\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\n/**\n * Convert Firestore document to BroadcastNotification\n */\nfunction docToBroadcast(\n docId: string,\n data: Record<string, unknown>\n): BroadcastNotification {\n return {\n id: docId,\n title: data.title as string,\n message: data.message as string,\n type: data.type as BroadcastNotification['type'],\n category: data.category as BroadcastNotification['category'],\n isRead: false,\n isImportant: data.isImportant as boolean | undefined,\n actionUrl: data.actionUrl as string | undefined,\n actionText: data.actionText as string | undefined,\n createdAt: data.createdAt as Timestamp,\n metadata: data.metadata as Record<string, unknown> | undefined,\n targetProjects: (data.targetProjects as string[]) || [],\n targetPlatforms: (data.targetPlatforms as BroadcastNotification['targetPlatforms']) || [],\n targetAudience: (data.targetAudience as BroadcastNotification['targetAudience']) || 'all',\n status: data.status as BroadcastStatus,\n startDate: data.startDate as Timestamp,\n endDate: data.endDate as Timestamp | null | undefined,\n priority: (data.priority as number) || 50,\n dismissible: data.dismissible !== false,\n variant: (data.variant as BroadcastNotification['variant']) || 'banner',\n impressions: (data.impressions as number) || 0,\n clicks: (data.clicks as number) || 0,\n createdBy: data.createdBy as string,\n updatedBy: data.updatedBy as string | undefined,\n };\n}\n\n/**\n * Convert Firestore document to NotificationTemplate\n */\nfunction docToTemplate(\n docId: string,\n data: Record<string, unknown>\n): NotificationTemplate {\n return {\n id: docId,\n name: data.name as string,\n eventType: data.eventType as string,\n category: data.category as NotificationTemplate['category'],\n title: data.title as string,\n message: data.message as string,\n variables: (data.variables as string[]) || [],\n type: data.type as NotificationTemplate['type'],\n isImportant: data.isImportant as boolean,\n actionUrl: data.actionUrl as string | undefined,\n actionText: data.actionText as string | undefined,\n enabled: data.enabled !== false,\n createdAt: (data.createdAt as Timestamp)?.toDate() || new Date(),\n updatedAt: (data.updatedAt as Timestamp)?.toDate() || new Date(),\n };\n}\n\n// ============================================================================\n// BROADCAST CRUD\n// ============================================================================\n\n/**\n * Create a new broadcast\n */\nexport async function createBroadcast(\n input: CreateBroadcastInput,\n adminUserId: string\n): Promise<string> {\n const db = getSharedFeaturesDb();\n\n const broadcastData = {\n ...input,\n status: 'draft' as BroadcastStatus,\n isRead: false,\n impressions: 0,\n clicks: 0,\n createdBy: adminUserId,\n createdAt: serverTimestamp(),\n startDate: Timestamp.fromDate(input.startDate),\n endDate: input.endDate ? Timestamp.fromDate(input.endDate) : null,\n };\n\n const docRef = await addDoc(\n collection(db, COLLECTION_BROADCASTS),\n broadcastData\n );\n\n return docRef.id;\n}\n\n/**\n * Update an existing broadcast\n */\nexport async function updateBroadcast(\n input: UpdateBroadcastInput,\n adminUserId: string\n): Promise<void> {\n const db = getSharedFeaturesDb();\n\n const updateData: Record<string, unknown> = {\n ...input,\n updatedBy: adminUserId,\n updatedAt: serverTimestamp(),\n };\n\n // Convert dates if provided\n if (input.startDate) {\n updateData.startDate = Timestamp.fromDate(input.startDate);\n }\n if (input.endDate !== undefined) {\n updateData.endDate = input.endDate ? Timestamp.fromDate(input.endDate) : null;\n }\n\n // Remove id from update data\n delete updateData.id;\n\n await updateDoc(doc(db, COLLECTION_BROADCASTS, input.id), updateData);\n}\n\n/**\n * Delete a broadcast\n */\nexport async function deleteBroadcast(broadcastId: string): Promise<void> {\n const db = getSharedFeaturesDb();\n await deleteDoc(doc(db, COLLECTION_BROADCASTS, broadcastId));\n}\n\n/**\n * Get all broadcasts (for admin listing)\n */\nexport async function getAllBroadcasts(): Promise<BroadcastNotification[]> {\n const db = getSharedFeaturesDb();\n\n const q = query(\n collection(db, COLLECTION_BROADCASTS),\n orderBy('createdAt', 'desc')\n );\n\n const snapshot = await getDocs(q);\n return snapshot.docs.map((d) => docToBroadcast(d.id, d.data()));\n}\n\n/**\n * Get broadcasts by status\n */\nexport async function getBroadcastsByStatus(\n status: BroadcastStatus\n): Promise<BroadcastNotification[]> {\n const db = getSharedFeaturesDb();\n\n const q = query(\n collection(db, COLLECTION_BROADCASTS),\n where('status', '==', status),\n orderBy('createdAt', 'desc')\n );\n\n const snapshot = await getDocs(q);\n return snapshot.docs.map((d) => docToBroadcast(d.id, d.data()));\n}\n\n/**\n * Get a single broadcast by ID\n */\nexport async function getBroadcastById(\n broadcastId: string\n): Promise<BroadcastNotification | null> {\n const db = getSharedFeaturesDb();\n const docSnap = await getDoc(doc(db, COLLECTION_BROADCASTS, broadcastId));\n\n if (!docSnap.exists()) return null;\n return docToBroadcast(docSnap.id, docSnap.data());\n}\n\n// ============================================================================\n// BROADCAST STATUS MANAGEMENT\n// ============================================================================\n\n/**\n * Publish a draft broadcast (set to active)\n */\nexport async function publishBroadcast(\n broadcastId: string,\n adminUserId: string\n): Promise<void> {\n const db = getSharedFeaturesDb();\n\n await updateDoc(doc(db, COLLECTION_BROADCASTS, broadcastId), {\n status: 'active',\n updatedBy: adminUserId,\n updatedAt: serverTimestamp(),\n });\n}\n\n/**\n * Schedule a broadcast for later\n */\nexport async function scheduleBroadcast(\n broadcastId: string,\n scheduledDate: Date,\n adminUserId: string\n): Promise<void> {\n const db = getSharedFeaturesDb();\n\n await updateDoc(doc(db, COLLECTION_BROADCASTS, broadcastId), {\n status: 'scheduled',\n startDate: Timestamp.fromDate(scheduledDate),\n updatedBy: adminUserId,\n updatedAt: serverTimestamp(),\n });\n}\n\n/**\n * Pause an active broadcast\n */\nexport async function pauseBroadcast(\n broadcastId: string,\n adminUserId: string\n): Promise<void> {\n const db = getSharedFeaturesDb();\n\n await updateDoc(doc(db, COLLECTION_BROADCASTS, broadcastId), {\n status: 'draft', // Move back to draft\n updatedBy: adminUserId,\n updatedAt: serverTimestamp(),\n });\n}\n\n/**\n * End a broadcast\n */\nexport async function endBroadcast(\n broadcastId: string,\n adminUserId: string\n): Promise<void> {\n const db = getSharedFeaturesDb();\n\n await updateDoc(doc(db, COLLECTION_BROADCASTS, broadcastId), {\n status: 'ended',\n endDate: serverTimestamp(),\n updatedBy: adminUserId,\n updatedAt: serverTimestamp(),\n });\n}\n\n// ============================================================================\n// TEMPLATE CRUD\n// ============================================================================\n\n/**\n * Create a new template\n */\nexport async function createTemplate(\n input: CreateTemplateInput\n): Promise<string> {\n const db = getSharedFeaturesDb();\n\n const templateData = {\n ...input,\n createdAt: serverTimestamp(),\n updatedAt: serverTimestamp(),\n };\n\n const docRef = await addDoc(\n collection(db, COLLECTION_TEMPLATES),\n templateData\n );\n\n return docRef.id;\n}\n\n/**\n * Update an existing template\n */\nexport async function updateTemplate(\n templateId: string,\n input: Partial<CreateTemplateInput>\n): Promise<void> {\n const db = getSharedFeaturesDb();\n\n await updateDoc(doc(db, COLLECTION_TEMPLATES, templateId), {\n ...input,\n updatedAt: serverTimestamp(),\n });\n}\n\n/**\n * Delete a template\n */\nexport async function deleteTemplate(templateId: string): Promise<void> {\n const db = getSharedFeaturesDb();\n await deleteDoc(doc(db, COLLECTION_TEMPLATES, templateId));\n}\n\n/**\n * Get all templates\n */\nexport async function getAllTemplates(): Promise<NotificationTemplate[]> {\n const db = getSharedFeaturesDb();\n\n const q = query(\n collection(db, COLLECTION_TEMPLATES),\n orderBy('name', 'asc')\n );\n\n const snapshot = await getDocs(q);\n return snapshot.docs.map((d) => docToTemplate(d.id, d.data()));\n}\n\n/**\n * Get template by ID\n */\nexport async function getTemplateById(\n templateId: string\n): Promise<NotificationTemplate | null> {\n const db = getSharedFeaturesDb();\n const docSnap = await getDoc(doc(db, COLLECTION_TEMPLATES, templateId));\n\n if (!docSnap.exists()) return null;\n return docToTemplate(docSnap.id, docSnap.data());\n}\n\n/**\n * Get template by event type from Firestore\n */\nexport async function getFirestoreTemplateByEventType(\n eventType: string\n): Promise<NotificationTemplate | null> {\n const db = getSharedFeaturesDb();\n\n const q = query(\n collection(db, COLLECTION_TEMPLATES),\n where('eventType', '==', eventType)\n );\n\n const snapshot = await getDocs(q);\n if (snapshot.empty) return null;\n\n const docSnap = snapshot.docs[0];\n if (!docSnap) return null;\n\n return docToTemplate(docSnap.id, docSnap.data());\n}\n\n// ============================================================================\n// ANALYTICS\n// ============================================================================\n\n/**\n * Get analytics for a specific broadcast\n */\nexport async function getBroadcastAnalytics(\n broadcastId: string\n): Promise<BroadcastAnalytics | null> {\n const db = getSharedFeaturesDb();\n\n // Get broadcast\n const broadcast = await getBroadcastById(broadcastId);\n if (!broadcast) return null;\n\n // Get events\n const eventsQuery = query(\n collection(db, COLLECTION_BROADCAST_EVENTS),\n where('broadcastId', '==', broadcastId)\n );\n\n const eventsSnapshot = await getDocs(eventsQuery);\n const events = eventsSnapshot.docs.map((d) => d.data());\n\n // Calculate analytics\n const impressions = events.filter((e) => e.action === 'impression').length;\n const clicks = events.filter((e) => e.action === 'click').length;\n const dismissals = events.filter((e) => e.action === 'dismiss').length;\n\n // Group by platform\n const byPlatform: BroadcastAnalytics['byPlatform'] = {\n web: { impressions: 0, clicks: 0 },\n android: { impressions: 0, clicks: 0 },\n ios: { impressions: 0, clicks: 0 },\n };\n\n events.forEach((e) => {\n const platform = e.platform as keyof typeof byPlatform;\n if (byPlatform[platform]) {\n if (e.action === 'impression') byPlatform[platform].impressions++;\n if (e.action === 'click') byPlatform[platform].clicks++;\n }\n });\n\n // Group by project\n const byProject: BroadcastAnalytics['byProject'] = {};\n events.forEach((e) => {\n const projectId = e.projectId as string;\n if (!byProject[projectId]) {\n byProject[projectId] = { impressions: 0, clicks: 0 };\n }\n if (e.action === 'impression') byProject[projectId].impressions++;\n if (e.action === 'click') byProject[projectId].clicks++;\n });\n\n // Group by date\n const byDateMap: Record<string, { impressions: number; clicks: number }> = {};\n events.forEach((e) => {\n const dateStr = (e.timestamp as Timestamp).toDate().toISOString().split('T')[0];\n if (dateStr) {\n if (!byDateMap[dateStr]) {\n byDateMap[dateStr] = { impressions: 0, clicks: 0 };\n }\n if (e.action === 'impression') byDateMap[dateStr].impressions++;\n if (e.action === 'click') byDateMap[dateStr].clicks++;\n }\n });\n\n const byDate = Object.entries(byDateMap).map(([date, data]) => ({\n date,\n impressions: data.impressions,\n clicks: data.clicks,\n }));\n\n return {\n broadcastId,\n title: broadcast.title,\n status: broadcast.status,\n impressions,\n clicks,\n dismissals,\n ctr: impressions > 0 ? clicks / impressions : 0,\n byPlatform,\n byProject,\n byDate,\n };\n}\n\n/**\n * Get overall notification analytics\n */\nexport async function getOverallAnalytics(\n startDate: Date,\n endDate: Date\n): Promise<NotificationAnalytics> {\n const db = getSharedFeaturesDb();\n\n // Get all broadcast events in date range\n const eventsQuery = query(\n collection(db, COLLECTION_BROADCAST_EVENTS),\n where('timestamp', '>=', Timestamp.fromDate(startDate)),\n where('timestamp', '<=', Timestamp.fromDate(endDate))\n );\n\n const eventsSnapshot = await getDocs(eventsQuery);\n const events = eventsSnapshot.docs.map((d) => d.data());\n\n // Calculate totals\n const totalSent = events.filter((e) => e.action === 'impression').length;\n const totalRead = events.filter((e) => e.action === 'impression').length; // Impressions = read for broadcasts\n const totalClicked = events.filter((e) => e.action === 'click').length;\n\n // Initialize category and type breakdowns\n const byCategory: NotificationAnalytics['byCategory'] = {\n system: { sent: 0, read: 0, clicked: 0 },\n account: { sent: 0, read: 0, clicked: 0 },\n activity: { sent: 0, read: 0, clicked: 0 },\n report: { sent: 0, read: 0, clicked: 0 },\n promotional: { sent: 0, read: 0, clicked: 0 },\n social: { sent: 0, read: 0, clicked: 0 },\n };\n\n const byType: NotificationAnalytics['byType'] = {\n info: { sent: 0, read: 0, clicked: 0 },\n success: { sent: 0, read: 0, clicked: 0 },\n warning: { sent: 0, read: 0, clicked: 0 },\n error: { sent: 0, read: 0, clicked: 0 },\n reminder: { sent: 0, read: 0, clicked: 0 },\n milestone: { sent: 0, read: 0, clicked: 0 },\n announcement: { sent: 0, read: 0, clicked: 0 },\n };\n\n // Group by date\n const byDateMap: Record<string, { sent: number; read: number; clicked: number }> = {};\n events.forEach((e) => {\n const dateStr = (e.timestamp as Timestamp).toDate().toISOString().split('T')[0];\n if (dateStr) {\n if (!byDateMap[dateStr]) {\n byDateMap[dateStr] = { sent: 0, read: 0, clicked: 0 };\n }\n if (e.action === 'impression') {\n byDateMap[dateStr].sent++;\n byDateMap[dateStr].read++;\n }\n if (e.action === 'click') byDateMap[dateStr].clicked++;\n }\n });\n\n const byDate = Object.entries(byDateMap)\n .map(([date, data]) => ({ date, ...data }))\n .sort((a, b) => a.date.localeCompare(b.date));\n\n return {\n totalSent,\n totalRead,\n totalClicked,\n readRate: totalSent > 0 ? totalRead / totalSent : 0,\n clickRate: totalSent > 0 ? totalClicked / totalSent : 0,\n byCategory,\n byType,\n byDate,\n };\n}\n\n// ============================================================================\n// EXPORT SERVICE OBJECT\n// ============================================================================\n\nexport const adminNotificationService = {\n // Broadcasts\n createBroadcast,\n updateBroadcast,\n deleteBroadcast,\n getAllBroadcasts,\n getBroadcastsByStatus,\n getBroadcastById,\n publishBroadcast,\n scheduleBroadcast,\n pauseBroadcast,\n endBroadcast,\n\n // Templates\n createTemplate,\n updateTemplate,\n deleteTemplate,\n getAllTemplates,\n getTemplateById,\n getFirestoreTemplateByEventType,\n\n // Analytics\n getBroadcastAnalytics,\n getOverallAnalytics,\n};\n\nexport default adminNotificationService;\n"],"names":["getSharedFeaturesDb","serverTimestamp","Timestamp","addDoc","collection","updateDoc","doc","deleteDoc","query","orderBy","getDocs","where","getDoc"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"admin-notifications-D1GgYCJW.cjs","sources":["../src/services/admin-notifications.ts"],"sourcesContent":["/**\n * Admin Notifications Service\n *\n * Service for managing broadcasts and templates from the admin panel.\n * Used in aoneahsan.com admin panel to manage cross-project notifications.\n *\n * @author Ahsan Mahmood <aoneahsan@gmail.com>\n */\n\nimport {\n collection,\n doc,\n getDocs,\n getDoc,\n updateDoc,\n deleteDoc,\n addDoc,\n query,\n where,\n orderBy,\n serverTimestamp,\n Timestamp,\n} from 'firebase/firestore';\nimport { getSharedFeaturesDb } from '../firebase/init';\nimport type {\n BroadcastNotification,\n BroadcastStatus,\n CreateBroadcastInput,\n UpdateBroadcastInput,\n NotificationTemplate,\n CreateTemplateInput,\n BroadcastAnalytics,\n NotificationAnalytics,\n} from '../types/notifications';\n\n// ============================================================================\n// CONSTANTS\n// ============================================================================\n\nconst COLLECTION_BROADCASTS = 'zaions_broadcasts';\nconst COLLECTION_TEMPLATES = 'zaions_notification_templates';\nconst COLLECTION_BROADCAST_EVENTS = 'zaions_broadcast_events';\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\n/**\n * Convert Firestore document to BroadcastNotification\n */\nfunction docToBroadcast(\n docId: string,\n data: Record<string, unknown>\n): BroadcastNotification {\n return {\n id: docId,\n title: data.title as string,\n message: data.message as string,\n type: data.type as BroadcastNotification['type'],\n category: data.category as BroadcastNotification['category'],\n isRead: false,\n isImportant: data.isImportant as boolean | undefined,\n actionUrl: data.actionUrl as string | undefined,\n actionText: data.actionText as string | undefined,\n createdAt: data.createdAt as Timestamp,\n metadata: data.metadata as Record<string, unknown> | undefined,\n targetProjects: (data.targetProjects as string[]) || [],\n targetPlatforms: (data.targetPlatforms as BroadcastNotification['targetPlatforms']) || [],\n targetAudience: (data.targetAudience as BroadcastNotification['targetAudience']) || 'all',\n status: data.status as BroadcastStatus,\n startDate: data.startDate as Timestamp,\n endDate: data.endDate as Timestamp | null | undefined,\n priority: (data.priority as number) || 50,\n dismissible: data.dismissible !== false,\n variant: (data.variant as BroadcastNotification['variant']) || 'banner',\n impressions: (data.impressions as number) || 0,\n clicks: (data.clicks as number) || 0,\n createdBy: data.createdBy as string,\n updatedBy: data.updatedBy as string | undefined,\n };\n}\n\n/**\n * Convert Firestore document to NotificationTemplate\n */\nfunction docToTemplate(\n docId: string,\n data: Record<string, unknown>\n): NotificationTemplate {\n return {\n id: docId,\n name: data.name as string,\n eventType: data.eventType as string,\n category: data.category as NotificationTemplate['category'],\n title: data.title as string,\n message: data.message as string,\n variables: (data.variables as string[]) || [],\n type: data.type as NotificationTemplate['type'],\n isImportant: data.isImportant as boolean,\n actionUrl: data.actionUrl as string | undefined,\n actionText: data.actionText as string | undefined,\n enabled: data.enabled !== false,\n createdAt: (data.createdAt as Timestamp)?.toDate() || new Date(),\n updatedAt: (data.updatedAt as Timestamp)?.toDate() || new Date(),\n };\n}\n\n// ============================================================================\n// BROADCAST CRUD\n// ============================================================================\n\n/**\n * Create a new broadcast\n */\nexport async function createBroadcast(\n input: CreateBroadcastInput,\n adminUserId: string\n): Promise<string> {\n const db = getSharedFeaturesDb();\n\n const broadcastData = {\n ...input,\n status: 'draft' as BroadcastStatus,\n isRead: false,\n impressions: 0,\n clicks: 0,\n createdBy: adminUserId,\n createdAt: serverTimestamp(),\n startDate: Timestamp.fromDate(input.startDate),\n endDate: input.endDate ? Timestamp.fromDate(input.endDate) : null,\n };\n\n const docRef = await addDoc(\n collection(db, COLLECTION_BROADCASTS),\n broadcastData\n );\n\n return docRef.id;\n}\n\n/**\n * Update an existing broadcast\n */\nexport async function updateBroadcast(\n input: UpdateBroadcastInput,\n adminUserId: string\n): Promise<void> {\n const db = getSharedFeaturesDb();\n\n const updateData: Record<string, unknown> = {\n ...input,\n updatedBy: adminUserId,\n updatedAt: serverTimestamp(),\n };\n\n // Convert dates if provided\n if (input.startDate) {\n updateData.startDate = Timestamp.fromDate(input.startDate);\n }\n if (input.endDate !== undefined) {\n updateData.endDate = input.endDate ? Timestamp.fromDate(input.endDate) : null;\n }\n\n // Remove id from update data\n delete updateData.id;\n\n await updateDoc(doc(db, COLLECTION_BROADCASTS, input.id), updateData);\n}\n\n/**\n * Delete a broadcast\n */\nexport async function deleteBroadcast(broadcastId: string): Promise<void> {\n const db = getSharedFeaturesDb();\n await deleteDoc(doc(db, COLLECTION_BROADCASTS, broadcastId));\n}\n\n/**\n * Get all broadcasts (for admin listing)\n */\nexport async function getAllBroadcasts(): Promise<BroadcastNotification[]> {\n const db = getSharedFeaturesDb();\n\n const q = query(\n collection(db, COLLECTION_BROADCASTS),\n orderBy('createdAt', 'desc')\n );\n\n const snapshot = await getDocs(q);\n return snapshot.docs.map((d) => docToBroadcast(d.id, d.data()));\n}\n\n/**\n * Get broadcasts by status\n */\nexport async function getBroadcastsByStatus(\n status: BroadcastStatus\n): Promise<BroadcastNotification[]> {\n const db = getSharedFeaturesDb();\n\n const q = query(\n collection(db, COLLECTION_BROADCASTS),\n where('status', '==', status),\n orderBy('createdAt', 'desc')\n );\n\n const snapshot = await getDocs(q);\n return snapshot.docs.map((d) => docToBroadcast(d.id, d.data()));\n}\n\n/**\n * Get a single broadcast by ID\n */\nexport async function getBroadcastById(\n broadcastId: string\n): Promise<BroadcastNotification | null> {\n const db = getSharedFeaturesDb();\n const docSnap = await getDoc(doc(db, COLLECTION_BROADCASTS, broadcastId));\n\n if (!docSnap.exists()) return null;\n return docToBroadcast(docSnap.id, docSnap.data());\n}\n\n// ============================================================================\n// BROADCAST STATUS MANAGEMENT\n// ============================================================================\n\n/**\n * Publish a draft broadcast (set to active)\n */\nexport async function publishBroadcast(\n broadcastId: string,\n adminUserId: string\n): Promise<void> {\n const db = getSharedFeaturesDb();\n\n await updateDoc(doc(db, COLLECTION_BROADCASTS, broadcastId), {\n status: 'active',\n updatedBy: adminUserId,\n updatedAt: serverTimestamp(),\n });\n}\n\n/**\n * Schedule a broadcast for later\n */\nexport async function scheduleBroadcast(\n broadcastId: string,\n scheduledDate: Date,\n adminUserId: string\n): Promise<void> {\n const db = getSharedFeaturesDb();\n\n await updateDoc(doc(db, COLLECTION_BROADCASTS, broadcastId), {\n status: 'scheduled',\n startDate: Timestamp.fromDate(scheduledDate),\n updatedBy: adminUserId,\n updatedAt: serverTimestamp(),\n });\n}\n\n/**\n * Pause an active broadcast\n */\nexport async function pauseBroadcast(\n broadcastId: string,\n adminUserId: string\n): Promise<void> {\n const db = getSharedFeaturesDb();\n\n await updateDoc(doc(db, COLLECTION_BROADCASTS, broadcastId), {\n status: 'draft', // Move back to draft\n updatedBy: adminUserId,\n updatedAt: serverTimestamp(),\n });\n}\n\n/**\n * End a broadcast\n */\nexport async function endBroadcast(\n broadcastId: string,\n adminUserId: string\n): Promise<void> {\n const db = getSharedFeaturesDb();\n\n await updateDoc(doc(db, COLLECTION_BROADCASTS, broadcastId), {\n status: 'ended',\n endDate: serverTimestamp(),\n updatedBy: adminUserId,\n updatedAt: serverTimestamp(),\n });\n}\n\n// ============================================================================\n// TEMPLATE CRUD\n// ============================================================================\n\n/**\n * Create a new template\n */\nexport async function createTemplate(\n input: CreateTemplateInput\n): Promise<string> {\n const db = getSharedFeaturesDb();\n\n const templateData = {\n ...input,\n createdAt: serverTimestamp(),\n updatedAt: serverTimestamp(),\n };\n\n const docRef = await addDoc(\n collection(db, COLLECTION_TEMPLATES),\n templateData\n );\n\n return docRef.id;\n}\n\n/**\n * Update an existing template\n */\nexport async function updateTemplate(\n templateId: string,\n input: Partial<CreateTemplateInput>\n): Promise<void> {\n const db = getSharedFeaturesDb();\n\n await updateDoc(doc(db, COLLECTION_TEMPLATES, templateId), {\n ...input,\n updatedAt: serverTimestamp(),\n });\n}\n\n/**\n * Delete a template\n */\nexport async function deleteTemplate(templateId: string): Promise<void> {\n const db = getSharedFeaturesDb();\n await deleteDoc(doc(db, COLLECTION_TEMPLATES, templateId));\n}\n\n/**\n * Get all templates\n */\nexport async function getAllTemplates(): Promise<NotificationTemplate[]> {\n const db = getSharedFeaturesDb();\n\n const q = query(\n collection(db, COLLECTION_TEMPLATES),\n orderBy('name', 'asc')\n );\n\n const snapshot = await getDocs(q);\n return snapshot.docs.map((d) => docToTemplate(d.id, d.data()));\n}\n\n/**\n * Get template by ID\n */\nexport async function getTemplateById(\n templateId: string\n): Promise<NotificationTemplate | null> {\n const db = getSharedFeaturesDb();\n const docSnap = await getDoc(doc(db, COLLECTION_TEMPLATES, templateId));\n\n if (!docSnap.exists()) return null;\n return docToTemplate(docSnap.id, docSnap.data());\n}\n\n/**\n * Get template by event type from Firestore\n */\nexport async function getFirestoreTemplateByEventType(\n eventType: string\n): Promise<NotificationTemplate | null> {\n const db = getSharedFeaturesDb();\n\n const q = query(\n collection(db, COLLECTION_TEMPLATES),\n where('eventType', '==', eventType)\n );\n\n const snapshot = await getDocs(q);\n if (snapshot.empty) return null;\n\n const docSnap = snapshot.docs[0];\n if (!docSnap) return null;\n\n return docToTemplate(docSnap.id, docSnap.data());\n}\n\n// ============================================================================\n// ANALYTICS\n// ============================================================================\n\n/**\n * Get analytics for a specific broadcast\n */\nexport async function getBroadcastAnalytics(\n broadcastId: string\n): Promise<BroadcastAnalytics | null> {\n const db = getSharedFeaturesDb();\n\n // Get broadcast\n const broadcast = await getBroadcastById(broadcastId);\n if (!broadcast) return null;\n\n // Get events\n const eventsQuery = query(\n collection(db, COLLECTION_BROADCAST_EVENTS),\n where('broadcastId', '==', broadcastId)\n );\n\n const eventsSnapshot = await getDocs(eventsQuery);\n const events = eventsSnapshot.docs.map((d) => d.data());\n\n // Calculate analytics\n const impressions = events.filter((e) => e.action === 'impression').length;\n const clicks = events.filter((e) => e.action === 'click').length;\n const dismissals = events.filter((e) => e.action === 'dismiss').length;\n\n // Group by platform\n const byPlatform: BroadcastAnalytics['byPlatform'] = {\n web: { impressions: 0, clicks: 0 },\n android: { impressions: 0, clicks: 0 },\n ios: { impressions: 0, clicks: 0 },\n };\n\n events.forEach((e) => {\n const platform = e.platform as keyof typeof byPlatform;\n if (byPlatform[platform]) {\n if (e.action === 'impression') byPlatform[platform].impressions++;\n if (e.action === 'click') byPlatform[platform].clicks++;\n }\n });\n\n // Group by project\n const byProject: BroadcastAnalytics['byProject'] = {};\n events.forEach((e) => {\n const projectId = e.projectId as string;\n if (!byProject[projectId]) {\n byProject[projectId] = { impressions: 0, clicks: 0 };\n }\n if (e.action === 'impression') byProject[projectId].impressions++;\n if (e.action === 'click') byProject[projectId].clicks++;\n });\n\n // Group by date\n const byDateMap: Record<string, { impressions: number; clicks: number }> = {};\n events.forEach((e) => {\n const dateStr = (e.timestamp as Timestamp).toDate().toISOString().split('T')[0];\n if (dateStr) {\n if (!byDateMap[dateStr]) {\n byDateMap[dateStr] = { impressions: 0, clicks: 0 };\n }\n if (e.action === 'impression') byDateMap[dateStr].impressions++;\n if (e.action === 'click') byDateMap[dateStr].clicks++;\n }\n });\n\n const byDate = Object.entries(byDateMap).map(([date, data]) => ({\n date,\n impressions: data.impressions,\n clicks: data.clicks,\n }));\n\n return {\n broadcastId,\n title: broadcast.title,\n status: broadcast.status,\n impressions,\n clicks,\n dismissals,\n ctr: impressions > 0 ? clicks / impressions : 0,\n byPlatform,\n byProject,\n byDate,\n };\n}\n\n/**\n * Get overall notification analytics\n */\nexport async function getOverallAnalytics(\n startDate: Date,\n endDate: Date\n): Promise<NotificationAnalytics> {\n const db = getSharedFeaturesDb();\n\n // Get all broadcast events in date range\n const eventsQuery = query(\n collection(db, COLLECTION_BROADCAST_EVENTS),\n where('timestamp', '>=', Timestamp.fromDate(startDate)),\n where('timestamp', '<=', Timestamp.fromDate(endDate))\n );\n\n const eventsSnapshot = await getDocs(eventsQuery);\n const events = eventsSnapshot.docs.map((d) => d.data());\n\n // Calculate totals\n const totalSent = events.filter((e) => e.action === 'impression').length;\n const totalRead = events.filter((e) => e.action === 'impression').length; // Impressions = read for broadcasts\n const totalClicked = events.filter((e) => e.action === 'click').length;\n\n // Initialize category and type breakdowns\n const byCategory: NotificationAnalytics['byCategory'] = {\n system: { sent: 0, read: 0, clicked: 0 },\n account: { sent: 0, read: 0, clicked: 0 },\n activity: { sent: 0, read: 0, clicked: 0 },\n report: { sent: 0, read: 0, clicked: 0 },\n promotional: { sent: 0, read: 0, clicked: 0 },\n social: { sent: 0, read: 0, clicked: 0 },\n };\n\n const byType: NotificationAnalytics['byType'] = {\n info: { sent: 0, read: 0, clicked: 0 },\n success: { sent: 0, read: 0, clicked: 0 },\n warning: { sent: 0, read: 0, clicked: 0 },\n error: { sent: 0, read: 0, clicked: 0 },\n reminder: { sent: 0, read: 0, clicked: 0 },\n milestone: { sent: 0, read: 0, clicked: 0 },\n announcement: { sent: 0, read: 0, clicked: 0 },\n };\n\n // Group by date\n const byDateMap: Record<string, { sent: number; read: number; clicked: number }> = {};\n events.forEach((e) => {\n const dateStr = (e.timestamp as Timestamp).toDate().toISOString().split('T')[0];\n if (dateStr) {\n if (!byDateMap[dateStr]) {\n byDateMap[dateStr] = { sent: 0, read: 0, clicked: 0 };\n }\n if (e.action === 'impression') {\n byDateMap[dateStr].sent++;\n byDateMap[dateStr].read++;\n }\n if (e.action === 'click') byDateMap[dateStr].clicked++;\n }\n });\n\n const byDate = Object.entries(byDateMap)\n .map(([date, data]) => ({ date, ...data }))\n .sort((a, b) => a.date.localeCompare(b.date));\n\n return {\n totalSent,\n totalRead,\n totalClicked,\n readRate: totalSent > 0 ? totalRead / totalSent : 0,\n clickRate: totalSent > 0 ? totalClicked / totalSent : 0,\n byCategory,\n byType,\n byDate,\n };\n}\n\n// ============================================================================\n// EXPORT SERVICE OBJECT\n// ============================================================================\n\nexport const adminNotificationService = {\n // Broadcasts\n createBroadcast,\n updateBroadcast,\n deleteBroadcast,\n getAllBroadcasts,\n getBroadcastsByStatus,\n getBroadcastById,\n publishBroadcast,\n scheduleBroadcast,\n pauseBroadcast,\n endBroadcast,\n\n // Templates\n createTemplate,\n updateTemplate,\n deleteTemplate,\n getAllTemplates,\n getTemplateById,\n getFirestoreTemplateByEventType,\n\n // Analytics\n getBroadcastAnalytics,\n getOverallAnalytics,\n};\n\nexport default adminNotificationService;\n"],"names":["getSharedFeaturesDb","serverTimestamp","Timestamp","addDoc","collection","updateDoc","doc","deleteDoc","query","orderBy","getDocs","where","getDoc"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { query, collection, where, Timestamp, getDocs, getDoc, doc, orderBy, deleteDoc, updateDoc, serverTimestamp, addDoc } from "firebase/firestore";
|
|
2
|
-
import {
|
|
2
|
+
import { I as getSharedFeaturesDb } from "./commonFeatures-Bdt0UZox.js";
|
|
3
3
|
const COLLECTION_BROADCASTS = "zaions_broadcasts";
|
|
4
4
|
const COLLECTION_TEMPLATES = "zaions_notification_templates";
|
|
5
5
|
const COLLECTION_BROADCAST_EVENTS = "zaions_broadcast_events";
|
|
@@ -342,22 +342,22 @@ const adminNotificationService = {
|
|
|
342
342
|
};
|
|
343
343
|
export {
|
|
344
344
|
adminNotificationService as a,
|
|
345
|
-
|
|
345
|
+
createTemplate as b,
|
|
346
346
|
createBroadcast as c,
|
|
347
347
|
deleteBroadcast as d,
|
|
348
|
-
|
|
348
|
+
deleteTemplate as e,
|
|
349
349
|
endBroadcast as f,
|
|
350
350
|
getAllBroadcasts as g,
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
351
|
+
getAllTemplates as h,
|
|
352
|
+
getBroadcastAnalytics as i,
|
|
353
|
+
getBroadcastsByStatus as j,
|
|
354
|
+
getFirestoreTemplateByEventType as k,
|
|
355
|
+
getOverallAnalytics as l,
|
|
356
|
+
getTemplateById as m,
|
|
357
|
+
publishBroadcast as n,
|
|
358
|
+
updateTemplate as o,
|
|
359
|
+
pauseBroadcast as p,
|
|
360
360
|
scheduleBroadcast as s,
|
|
361
361
|
updateBroadcast as u
|
|
362
362
|
};
|
|
363
|
-
//# sourceMappingURL=admin-notifications-
|
|
363
|
+
//# sourceMappingURL=admin-notifications-NI7I76uY.js.map
|