shared-features 0.0.7 → 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.
Files changed (94) hide show
  1. package/AI-INTEGRATION-GUIDE.md +315 -0
  2. package/README.md +207 -2
  3. package/dist/{admin-notifications-D9n9h-eY.cjs → admin-notifications-D1GgYCJW.cjs} +20 -20
  4. package/dist/{admin-notifications-D9n9h-eY.cjs.map → admin-notifications-D1GgYCJW.cjs.map} +1 -1
  5. package/dist/{admin-notifications-p1dy3zIP.js → admin-notifications-NI7I76uY.js} +13 -13
  6. package/dist/{admin-notifications-p1dy3zIP.js.map → admin-notifications-NI7I76uY.js.map} +1 -1
  7. package/dist/{broadcasts-3_WfQMNL.cjs → broadcasts-BMoTZIuX.cjs} +10 -10
  8. package/dist/{broadcasts-3_WfQMNL.cjs.map → broadcasts-BMoTZIuX.cjs.map} +1 -1
  9. package/dist/{broadcasts-DgZUzqMf.js → broadcasts-DnzZkCoy.js} +12 -12
  10. package/dist/{broadcasts-DgZUzqMf.js.map → broadcasts-DnzZkCoy.js.map} +1 -1
  11. package/dist/commonFeatures-Bdt0UZox.js +1255 -0
  12. package/dist/commonFeatures-Bdt0UZox.js.map +1 -0
  13. package/dist/commonFeatures-CiqxxOin.cjs +1276 -0
  14. package/dist/commonFeatures-CiqxxOin.cjs.map +1 -0
  15. package/dist/commonFeatures-Cr5g1E4M.cjs +200 -0
  16. package/dist/commonFeatures-Cr5g1E4M.cjs.map +1 -0
  17. package/dist/commonFeatures-HT-UO7HW.js +201 -0
  18. package/dist/commonFeatures-HT-UO7HW.js.map +1 -0
  19. package/dist/components/common/index.d.ts +53 -0
  20. package/dist/components/common/index.d.ts.map +1 -0
  21. package/dist/components/index.cjs +31 -23
  22. package/dist/components/index.cjs.map +1 -1
  23. package/dist/components/index.d.ts +1 -0
  24. package/dist/components/index.d.ts.map +1 -1
  25. package/dist/components/index.js +21 -13
  26. package/dist/config/support.d.ts +10 -0
  27. package/dist/config/support.d.ts.map +1 -0
  28. package/dist/firebase/config.d.ts +34 -0
  29. package/dist/firebase/config.d.ts.map +1 -1
  30. package/dist/hooks/index.cjs +26 -13
  31. package/dist/hooks/index.cjs.map +1 -1
  32. package/dist/hooks/index.d.ts +2 -0
  33. package/dist/hooks/index.d.ts.map +1 -1
  34. package/dist/hooks/index.js +24 -11
  35. package/dist/hooks/useCommonFeatures.d.ts +74 -0
  36. package/dist/hooks/useCommonFeatures.d.ts.map +1 -0
  37. package/dist/hooks/useFeatureFlags.d.ts +134 -0
  38. package/dist/hooks/useFeatureFlags.d.ts.map +1 -0
  39. package/dist/{AnnouncementModal-Bqy0pn3V.cjs → index-Dt5YjYnK.cjs} +209 -14
  40. package/dist/index-Dt5YjYnK.cjs.map +1 -0
  41. package/dist/{AnnouncementModal-sxH4K5gy.js → index-Dv34aG2I.js} +212 -17
  42. package/dist/index-Dv34aG2I.js.map +1 -0
  43. package/dist/index.cjs +125 -60
  44. package/dist/index.cjs.map +1 -1
  45. package/dist/index.d.ts +10 -5
  46. package/dist/index.d.ts.map +1 -1
  47. package/dist/index.js +173 -108
  48. package/dist/index.js.map +1 -1
  49. package/dist/notifications/index.js +14 -14
  50. package/dist/services/commonFeatures.d.ts +22 -0
  51. package/dist/services/commonFeatures.d.ts.map +1 -0
  52. package/dist/services/featureFlags.d.ts +71 -0
  53. package/dist/services/featureFlags.d.ts.map +1 -0
  54. package/dist/services/index.cjs +49 -17
  55. package/dist/services/index.cjs.map +1 -1
  56. package/dist/services/index.d.ts +2 -0
  57. package/dist/services/index.d.ts.map +1 -1
  58. package/dist/services/index.js +75 -43
  59. package/dist/services/index.js.map +1 -1
  60. package/dist/types/commonFeatures.d.ts +194 -0
  61. package/dist/types/commonFeatures.d.ts.map +1 -0
  62. package/dist/types/featureFlags.d.ts +203 -0
  63. package/dist/types/featureFlags.d.ts.map +1 -0
  64. package/dist/types/index.cjs +15 -0
  65. package/dist/types/index.cjs.map +1 -1
  66. package/dist/types/index.d.ts +3 -1
  67. package/dist/types/index.d.ts.map +1 -1
  68. package/dist/types/index.js +15 -0
  69. package/dist/types/index.js.map +1 -1
  70. package/dist/useCommonFeatures-CgyDq6LZ.js +489 -0
  71. package/dist/useCommonFeatures-CgyDq6LZ.js.map +1 -0
  72. package/dist/useCommonFeatures-DnDlhmri.cjs +488 -0
  73. package/dist/useCommonFeatures-DnDlhmri.cjs.map +1 -0
  74. package/dist/useFeatureFlags-BRJSyH9M.js +368 -0
  75. package/dist/useFeatureFlags-BRJSyH9M.js.map +1 -0
  76. package/dist/useFeatureFlags-DXqBJ5Mh.cjs +367 -0
  77. package/dist/useFeatureFlags-DXqBJ5Mh.cjs.map +1 -0
  78. package/dist/{useNotificationEvents-D8DVxah1.js → useNotificationEvents-DAmR7FYF.js} +14 -14
  79. package/dist/{useNotificationEvents-D8DVxah1.js.map → useNotificationEvents-DAmR7FYF.js.map} +1 -1
  80. package/package.json +18 -7
  81. package/dist/AnnouncementModal-Bqy0pn3V.cjs.map +0 -1
  82. package/dist/AnnouncementModal-sxH4K5gy.js.map +0 -1
  83. package/dist/analytics-40-S_fHC.js +0 -440
  84. package/dist/analytics-40-S_fHC.js.map +0 -1
  85. package/dist/analytics-lEzOx2vl.cjs +0 -461
  86. package/dist/analytics-lEzOx2vl.cjs.map +0 -1
  87. package/dist/useBroadcasts-DzpCcbC8.js +0 -161
  88. package/dist/useBroadcasts-DzpCcbC8.js.map +0 -1
  89. package/dist/useBroadcasts-FP6ZrcY_.cjs +0 -160
  90. package/dist/useBroadcasts-FP6ZrcY_.cjs.map +0 -1
  91. package/dist/useCampaigns-BOZ9dDsG.cjs +0 -152
  92. package/dist/useCampaigns-BOZ9dDsG.cjs.map +0 -1
  93. package/dist/useCampaigns-D46b9zuf.js +0 -153
  94. package/dist/useCampaigns-D46b9zuf.js.map +0 -1
@@ -0,0 +1,368 @@
1
+ import { useState, useRef, useEffect, useCallback } from "react";
2
+ import { f as fetchActiveBroadcasts, s as subscribeToBroadcasts, h as trackBroadcastDismiss, j as trackBroadcastImpression, t as trackBroadcastClick, c as clearBroadcastsCache } from "./broadcasts-DnzZkCoy.js";
3
+ import { O as isInitialized, Y as getState, J as getSharedFeaturesStatus, N as isFeatureEnabled, g as clearFeatureFlagsCache, S as subscribeToFeatureFlags, c as checkFeatureAvailability } from "./commonFeatures-Bdt0UZox.js";
4
+ function useBroadcasts(options = {}) {
5
+ const {
6
+ variant,
7
+ platform,
8
+ maxBroadcasts = 10,
9
+ autoFetch = true,
10
+ realtime = false
11
+ } = options;
12
+ const [broadcasts, setBroadcasts] = useState([]);
13
+ const [isLoading, setIsLoading] = useState(autoFetch);
14
+ const [error, setError] = useState(null);
15
+ const dismissedIdsRef = useRef(/* @__PURE__ */ new Set());
16
+ const impressionTrackedRef = useRef(/* @__PURE__ */ new Set());
17
+ const fetchBroadcastsData = useCallback(async () => {
18
+ if (!isInitialized()) {
19
+ setError(new Error("shared-features not initialized"));
20
+ setIsLoading(false);
21
+ return;
22
+ }
23
+ setIsLoading(true);
24
+ setError(null);
25
+ try {
26
+ const allBroadcasts = await fetchActiveBroadcasts({
27
+ variant,
28
+ platform
29
+ });
30
+ const filteredBroadcasts = allBroadcasts.filter((b) => !dismissedIdsRef.current.has(b.id)).slice(0, maxBroadcasts);
31
+ setBroadcasts(filteredBroadcasts);
32
+ } catch (err) {
33
+ const errorObj = err instanceof Error ? err : new Error("Failed to fetch broadcasts");
34
+ setError(errorObj);
35
+ console.error("[shared-features] Error fetching broadcasts:", err);
36
+ } finally {
37
+ setIsLoading(false);
38
+ }
39
+ }, [variant, platform, maxBroadcasts]);
40
+ useEffect(() => {
41
+ if (autoFetch) {
42
+ fetchBroadcastsData();
43
+ }
44
+ }, [autoFetch, fetchBroadcastsData]);
45
+ useEffect(() => {
46
+ if (!realtime || !isInitialized()) return;
47
+ const unsubscribe = subscribeToBroadcasts(
48
+ (newBroadcasts) => {
49
+ const filtered = newBroadcasts.filter((b) => !dismissedIdsRef.current.has(b.id)).filter((b) => !variant || b.variant === variant).slice(0, maxBroadcasts);
50
+ setBroadcasts(filtered);
51
+ setIsLoading(false);
52
+ },
53
+ { variant, platform }
54
+ );
55
+ return () => {
56
+ unsubscribe();
57
+ };
58
+ }, [realtime, variant, platform, maxBroadcasts]);
59
+ const handleDismissBroadcast = useCallback((broadcastId) => {
60
+ dismissedIdsRef.current.add(broadcastId);
61
+ setBroadcasts((prev) => prev.filter((b) => b.id !== broadcastId));
62
+ trackBroadcastDismiss(broadcastId).catch((err) => {
63
+ console.error("[shared-features] Failed to track dismiss:", err);
64
+ });
65
+ }, []);
66
+ const handleTrackImpression = useCallback((broadcastId) => {
67
+ if (impressionTrackedRef.current.has(broadcastId)) return;
68
+ impressionTrackedRef.current.add(broadcastId);
69
+ trackBroadcastImpression(broadcastId).catch((err) => {
70
+ console.error("[shared-features] Failed to track impression:", err);
71
+ });
72
+ }, []);
73
+ const handleTrackClick = useCallback((broadcastId) => {
74
+ trackBroadcastClick(broadcastId).catch((err) => {
75
+ console.error("[shared-features] Failed to track click:", err);
76
+ });
77
+ }, []);
78
+ const checkIsDismissed = useCallback((broadcastId) => {
79
+ return dismissedIdsRef.current.has(broadcastId);
80
+ }, []);
81
+ const handleRefresh = useCallback(async () => {
82
+ clearBroadcastsCache();
83
+ await fetchBroadcastsData();
84
+ }, [fetchBroadcastsData]);
85
+ return {
86
+ broadcasts,
87
+ isLoading,
88
+ error,
89
+ dismissBroadcast: handleDismissBroadcast,
90
+ trackImpression: handleTrackImpression,
91
+ trackClick: handleTrackClick,
92
+ isDismissed: checkIsDismissed,
93
+ refresh: handleRefresh
94
+ };
95
+ }
96
+ function useBannerBroadcasts(options = {}) {
97
+ return useBroadcasts({ ...options, variant: "banner" });
98
+ }
99
+ function useModalBroadcasts(options = {}) {
100
+ return useBroadcasts({ ...options, variant: "modal", maxBroadcasts: 1 });
101
+ }
102
+ function useToastBroadcasts(options = {}) {
103
+ return useBroadcasts({ ...options, variant: "toast" });
104
+ }
105
+ function useBellBroadcasts(options = {}) {
106
+ return useBroadcasts({ ...options, variant: "bell" });
107
+ }
108
+ function useSingleBroadcast(options = {}) {
109
+ const result = useBroadcasts({ ...options, maxBroadcasts: 1 });
110
+ const broadcast = result.broadcasts[0] || null;
111
+ return {
112
+ broadcast,
113
+ isLoading: result.isLoading,
114
+ error: result.error,
115
+ dismiss: () => broadcast && result.dismissBroadcast(broadcast.id),
116
+ trackImpression: () => broadcast && result.trackImpression(broadcast.id),
117
+ trackClick: () => broadcast && result.trackClick(broadcast.id),
118
+ isDismissed: broadcast ? result.isDismissed(broadcast.id) : false
119
+ };
120
+ }
121
+ function useAnnouncementModal() {
122
+ const { broadcast, dismiss, trackImpression, trackClick } = useSingleBroadcast({
123
+ variant: "modal"
124
+ });
125
+ const [isOpen, setIsOpen] = useState(false);
126
+ const impressionTrackedRef = useRef(false);
127
+ useEffect(() => {
128
+ if (broadcast && !impressionTrackedRef.current) {
129
+ setIsOpen(true);
130
+ trackImpression();
131
+ impressionTrackedRef.current = true;
132
+ }
133
+ }, [broadcast, trackImpression]);
134
+ const handleClose = useCallback(() => {
135
+ setIsOpen(false);
136
+ dismiss();
137
+ }, [dismiss]);
138
+ const handleAction = useCallback(() => {
139
+ trackClick();
140
+ if (broadcast?.actionUrl) {
141
+ window.open(broadcast.actionUrl, "_blank");
142
+ }
143
+ handleClose();
144
+ }, [broadcast, trackClick, handleClose]);
145
+ return {
146
+ broadcast,
147
+ isOpen,
148
+ close: handleClose,
149
+ handleAction
150
+ };
151
+ }
152
+ function useFeatureFlags(options = {}) {
153
+ const {
154
+ autoRefresh = false,
155
+ refreshInterval = 5 * 60 * 1e3,
156
+ // 5 minutes
157
+ autoFetch = true
158
+ } = options;
159
+ const [status, setStatus] = useState(null);
160
+ const [loading, setLoading] = useState(autoFetch);
161
+ const [error, setError] = useState(null);
162
+ const mountedRef = useRef(true);
163
+ const consumerVersions = useRef(
164
+ getState().config?.featureVersions
165
+ );
166
+ const fetchStatus = useCallback(async () => {
167
+ if (!isInitialized()) {
168
+ setError("shared-features not initialized");
169
+ setLoading(false);
170
+ return;
171
+ }
172
+ setLoading(true);
173
+ setError(null);
174
+ try {
175
+ const newStatus = await getSharedFeaturesStatus(consumerVersions.current);
176
+ if (mountedRef.current) {
177
+ setStatus(newStatus);
178
+ }
179
+ } catch (err) {
180
+ const message = err instanceof Error ? err.message : "Failed to fetch feature flags";
181
+ if (mountedRef.current) {
182
+ setError(message);
183
+ console.error("[shared-features] Error fetching feature flags:", err);
184
+ }
185
+ } finally {
186
+ if (mountedRef.current) {
187
+ setLoading(false);
188
+ }
189
+ }
190
+ }, []);
191
+ useEffect(() => {
192
+ if (autoFetch) {
193
+ fetchStatus();
194
+ }
195
+ }, [autoFetch, fetchStatus]);
196
+ useEffect(() => {
197
+ if (!autoRefresh) return;
198
+ const interval = setInterval(() => {
199
+ fetchStatus();
200
+ }, refreshInterval);
201
+ return () => clearInterval(interval);
202
+ }, [autoRefresh, refreshInterval, fetchStatus]);
203
+ useEffect(() => {
204
+ mountedRef.current = true;
205
+ return () => {
206
+ mountedRef.current = false;
207
+ };
208
+ }, []);
209
+ const checkFeatureAvailable = useCallback(
210
+ (featureId) => {
211
+ if (!status) return isFeatureEnabled(featureId);
212
+ const availability = status.features[featureId];
213
+ return availability?.available ?? false;
214
+ },
215
+ [status]
216
+ );
217
+ const getAvailability = useCallback(
218
+ (featureId) => {
219
+ if (!status) return null;
220
+ return status.features[featureId] ?? null;
221
+ },
222
+ [status]
223
+ );
224
+ const refetch = useCallback(async () => {
225
+ clearFeatureFlagsCache();
226
+ await fetchStatus();
227
+ }, [fetchStatus]);
228
+ return {
229
+ status,
230
+ loading,
231
+ error,
232
+ refetch,
233
+ isFeatureAvailable: checkFeatureAvailable,
234
+ getFeatureAvailability: getAvailability,
235
+ hasDeprecatedFeatures: (status?.deprecatedFeatures.length ?? 0) > 0,
236
+ hasUpgradeRequired: (status?.upgradeRequiredFeatures.length ?? 0) > 0
237
+ };
238
+ }
239
+ function useFeature(featureId) {
240
+ const [availability, setAvailability] = useState(
241
+ null
242
+ );
243
+ const [loading, setLoading] = useState(true);
244
+ useEffect(() => {
245
+ let mounted = true;
246
+ const checkFeature = async () => {
247
+ if (!isInitialized()) {
248
+ setLoading(false);
249
+ return;
250
+ }
251
+ try {
252
+ const consumerVersions = getState().config?.featureVersions;
253
+ const result = await checkFeatureAvailability(
254
+ featureId,
255
+ consumerVersions
256
+ );
257
+ if (mounted) {
258
+ setAvailability(result);
259
+ }
260
+ } catch (err) {
261
+ console.error(
262
+ `[shared-features] Error checking feature '${featureId}':`,
263
+ err
264
+ );
265
+ } finally {
266
+ if (mounted) {
267
+ setLoading(false);
268
+ }
269
+ }
270
+ };
271
+ checkFeature();
272
+ return () => {
273
+ mounted = false;
274
+ };
275
+ }, [featureId]);
276
+ return {
277
+ /** Whether the feature is available */
278
+ available: availability?.available ?? false,
279
+ /** Whether the check is in progress */
280
+ loading,
281
+ /** Full availability details */
282
+ availability,
283
+ /** Whether the feature is enabled (but might need upgrade) */
284
+ enabled: availability?.enabled ?? false,
285
+ /** Whether using a deprecated version */
286
+ deprecated: availability?.deprecated ?? false,
287
+ /** Whether an upgrade is required */
288
+ upgradeRequired: availability?.upgradeRequired ?? false,
289
+ /** Deprecation warning if applicable */
290
+ deprecationWarning: availability?.deprecationWarning,
291
+ /** Reason feature is unavailable */
292
+ unavailableReason: availability?.unavailableReason
293
+ };
294
+ }
295
+ function useFeatureFlagsSubscription(callback) {
296
+ const callbackRef = useRef(callback);
297
+ callbackRef.current = callback;
298
+ useEffect(() => {
299
+ if (!isInitialized()) return;
300
+ const consumerVersions = getState().config?.featureVersions;
301
+ const unsubscribe = subscribeToFeatureFlags(async (flags) => {
302
+ if (!flags) {
303
+ callbackRef.current(null);
304
+ return;
305
+ }
306
+ const status = await getSharedFeaturesStatus(consumerVersions);
307
+ callbackRef.current(status);
308
+ });
309
+ return () => unsubscribe();
310
+ }, []);
311
+ }
312
+ function useSharedFeaturesOperational() {
313
+ const { status, loading } = useFeatureFlags({ autoFetch: true });
314
+ return {
315
+ /** Whether shared-features is operational */
316
+ operational: status?.operational ?? false,
317
+ /** Whether check is in progress */
318
+ loading,
319
+ /** Maintenance message if in maintenance mode */
320
+ maintenanceMessage: status?.maintenanceMessage,
321
+ /** Whether in maintenance mode */
322
+ maintenanceMode: status?.maintenanceMode ?? false,
323
+ /** Current API version */
324
+ apiVersion: status?.apiVersion ?? "v1"
325
+ };
326
+ }
327
+ function useFeatureGate(featureId) {
328
+ const { available, loading, deprecated, deprecationWarning } = useFeature(featureId);
329
+ useEffect(() => {
330
+ if (deprecated && deprecationWarning) {
331
+ console.warn(`[shared-features] ${deprecationWarning}`);
332
+ }
333
+ }, [deprecated, deprecationWarning]);
334
+ return {
335
+ /** Whether the feature should be rendered */
336
+ shouldRender: available,
337
+ /** Whether still checking availability */
338
+ loading,
339
+ /** Whether using deprecated version */
340
+ deprecated,
341
+ /** Component that renders children if available, fallback otherwise */
342
+ FallbackOrChildren: useCallback(
343
+ ({
344
+ children,
345
+ fallback = null
346
+ }) => {
347
+ if (loading) return null;
348
+ return available ? children : fallback;
349
+ },
350
+ [available, loading]
351
+ )
352
+ };
353
+ }
354
+ export {
355
+ useBannerBroadcasts as a,
356
+ useBellBroadcasts as b,
357
+ useBroadcasts as c,
358
+ useFeature as d,
359
+ useFeatureFlags as e,
360
+ useFeatureFlagsSubscription as f,
361
+ useFeatureGate as g,
362
+ useModalBroadcasts as h,
363
+ useSharedFeaturesOperational as i,
364
+ useSingleBroadcast as j,
365
+ useToastBroadcasts as k,
366
+ useAnnouncementModal as u
367
+ };
368
+ //# sourceMappingURL=useFeatureFlags-BRJSyH9M.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFeatureFlags-BRJSyH9M.js","sources":["../src/hooks/useBroadcasts.ts","../src/hooks/useFeatureFlags.ts"],"sourcesContent":["/**\n * useBroadcasts Hook\n *\n * React hook for fetching and displaying broadcast notifications in consumer projects.\n *\n * @author Ahsan Mahmood <aoneahsan@gmail.com>\n */\n\nimport { useState, useEffect, useCallback, useRef } from 'react';\nimport {\n fetchActiveBroadcasts,\n subscribeToBroadcasts,\n trackBroadcastImpression,\n trackBroadcastClick,\n trackBroadcastDismiss,\n clearBroadcastsCache,\n} from '../services/broadcasts';\nimport { isInitialized } from '../firebase/config';\nimport type {\n BroadcastNotification,\n BroadcastVariant,\n NotificationPlatform,\n UseBroadcastsReturn,\n} from '../types/notifications';\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\nexport interface UseBroadcastsOptions {\n /** Filter by variant type */\n variant?: BroadcastVariant;\n /** Override platform detection */\n platform?: NotificationPlatform;\n /** Maximum number of broadcasts to return */\n maxBroadcasts?: number;\n /** Whether to auto-fetch on mount (default: true) */\n autoFetch?: boolean;\n /** Whether to subscribe to real-time updates (default: false) */\n realtime?: boolean;\n}\n\n// ============================================================================\n// MAIN HOOK\n// ============================================================================\n\n/**\n * Hook to fetch and manage broadcast notifications\n *\n * @example\n * ```tsx\n * const { broadcasts, isLoading, dismissBroadcast, trackClick } = useBroadcasts({\n * variant: 'banner',\n * maxBroadcasts: 3,\n * });\n *\n * return (\n * <div>\n * {broadcasts.map(broadcast => (\n * <BroadcastBanner\n * key={broadcast.id}\n * broadcast={broadcast}\n * onDismiss={() => dismissBroadcast(broadcast.id)}\n * onActionClick={() => trackClick(broadcast.id)}\n * />\n * ))}\n * </div>\n * );\n * ```\n */\nexport function useBroadcasts(\n options: UseBroadcastsOptions = {}\n): UseBroadcastsReturn {\n const {\n variant,\n platform,\n maxBroadcasts = 10,\n autoFetch = true,\n realtime = false,\n } = options;\n\n const [broadcasts, setBroadcasts] = useState<BroadcastNotification[]>([]);\n const [isLoading, setIsLoading] = useState(autoFetch);\n const [error, setError] = useState<Error | null>(null);\n const dismissedIdsRef = useRef<Set<string>>(new Set());\n const impressionTrackedRef = useRef<Set<string>>(new Set());\n\n // Fetch broadcasts\n const fetchBroadcastsData = useCallback(async () => {\n if (!isInitialized()) {\n setError(new Error('shared-features not initialized'));\n setIsLoading(false);\n return;\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n const allBroadcasts = await fetchActiveBroadcasts({\n variant,\n platform,\n });\n\n // Filter out locally dismissed and limit count\n const filteredBroadcasts = allBroadcasts\n .filter((b) => !dismissedIdsRef.current.has(b.id))\n .slice(0, maxBroadcasts);\n\n setBroadcasts(filteredBroadcasts);\n } catch (err) {\n const errorObj =\n err instanceof Error ? err : new Error('Failed to fetch broadcasts');\n setError(errorObj);\n console.error('[shared-features] Error fetching broadcasts:', err);\n } finally {\n setIsLoading(false);\n }\n }, [variant, platform, maxBroadcasts]);\n\n // Auto-fetch on mount\n useEffect(() => {\n if (autoFetch) {\n fetchBroadcastsData();\n }\n }, [autoFetch, fetchBroadcastsData]);\n\n // Real-time subscription\n useEffect(() => {\n if (!realtime || !isInitialized()) return;\n\n const unsubscribe = subscribeToBroadcasts(\n (newBroadcasts) => {\n // Filter and limit\n const filtered = newBroadcasts\n .filter((b) => !dismissedIdsRef.current.has(b.id))\n .filter((b) => !variant || b.variant === variant)\n .slice(0, maxBroadcasts);\n\n setBroadcasts(filtered);\n setIsLoading(false);\n },\n { variant, platform }\n );\n\n return () => {\n unsubscribe();\n };\n }, [realtime, variant, platform, maxBroadcasts]);\n\n // Dismiss broadcast\n const handleDismissBroadcast = useCallback((broadcastId: string) => {\n // Update local state immediately\n dismissedIdsRef.current.add(broadcastId);\n setBroadcasts((prev) => prev.filter((b) => b.id !== broadcastId));\n\n // Track dismiss and persist\n trackBroadcastDismiss(broadcastId).catch((err) => {\n console.error('[shared-features] Failed to track dismiss:', err);\n });\n }, []);\n\n // Track impression\n const handleTrackImpression = useCallback((broadcastId: string) => {\n // Only track once per session\n if (impressionTrackedRef.current.has(broadcastId)) return;\n impressionTrackedRef.current.add(broadcastId);\n\n trackBroadcastImpression(broadcastId).catch((err) => {\n console.error('[shared-features] Failed to track impression:', err);\n });\n }, []);\n\n // Track click\n const handleTrackClick = useCallback((broadcastId: string) => {\n trackBroadcastClick(broadcastId).catch((err) => {\n console.error('[shared-features] Failed to track click:', err);\n });\n }, []);\n\n // Check if dismissed\n const checkIsDismissed = useCallback((broadcastId: string) => {\n return dismissedIdsRef.current.has(broadcastId);\n }, []);\n\n // Refresh broadcasts\n const handleRefresh = useCallback(async () => {\n clearBroadcastsCache();\n await fetchBroadcastsData();\n }, [fetchBroadcastsData]);\n\n return {\n broadcasts,\n isLoading,\n error,\n dismissBroadcast: handleDismissBroadcast,\n trackImpression: handleTrackImpression,\n trackClick: handleTrackClick,\n isDismissed: checkIsDismissed,\n refresh: handleRefresh,\n };\n}\n\n// ============================================================================\n// SPECIALIZED HOOKS\n// ============================================================================\n\n/**\n * Hook specifically for banner broadcasts\n */\nexport function useBannerBroadcasts(\n options: Omit<UseBroadcastsOptions, 'variant'> = {}\n) {\n return useBroadcasts({ ...options, variant: 'banner' });\n}\n\n/**\n * Hook specifically for modal broadcasts\n */\nexport function useModalBroadcasts(\n options: Omit<UseBroadcastsOptions, 'variant'> = {}\n) {\n return useBroadcasts({ ...options, variant: 'modal', maxBroadcasts: 1 });\n}\n\n/**\n * Hook specifically for toast broadcasts\n */\nexport function useToastBroadcasts(\n options: Omit<UseBroadcastsOptions, 'variant'> = {}\n) {\n return useBroadcasts({ ...options, variant: 'toast' });\n}\n\n/**\n * Hook specifically for bell/notification center broadcasts\n */\nexport function useBellBroadcasts(\n options: Omit<UseBroadcastsOptions, 'variant'> = {}\n) {\n return useBroadcasts({ ...options, variant: 'bell' });\n}\n\n// ============================================================================\n// SINGLE BROADCAST HOOK\n// ============================================================================\n\nexport interface UseSingleBroadcastReturn {\n /** The broadcast (first matching one) */\n broadcast: BroadcastNotification | null;\n /** Whether loading */\n isLoading: boolean;\n /** Error if any */\n error: Error | null;\n /** Dismiss the broadcast */\n dismiss: () => void;\n /** Track impression */\n trackImpression: () => void;\n /** Track click */\n trackClick: () => void;\n /** Whether broadcast was dismissed */\n isDismissed: boolean;\n}\n\n/**\n * Hook to get a single broadcast (convenience wrapper)\n *\n * @example\n * ```tsx\n * const { broadcast, dismiss, trackClick } = useSingleBroadcast({ variant: 'modal' });\n *\n * if (!broadcast) return null;\n *\n * return (\n * <AnnouncementModal\n * broadcast={broadcast}\n * onClose={dismiss}\n * onActionClick={trackClick}\n * />\n * );\n * ```\n */\nexport function useSingleBroadcast(\n options: Omit<UseBroadcastsOptions, 'maxBroadcasts'> = {}\n): UseSingleBroadcastReturn {\n const result = useBroadcasts({ ...options, maxBroadcasts: 1 });\n const broadcast = result.broadcasts[0] || null;\n\n return {\n broadcast,\n isLoading: result.isLoading,\n error: result.error,\n dismiss: () => broadcast && result.dismissBroadcast(broadcast.id),\n trackImpression: () => broadcast && result.trackImpression(broadcast.id),\n trackClick: () => broadcast && result.trackClick(broadcast.id),\n isDismissed: broadcast ? result.isDismissed(broadcast.id) : false,\n };\n}\n\n// ============================================================================\n// ANNOUNCEMENT MODAL HOOK\n// ============================================================================\n\nexport interface UseAnnouncementModalReturn {\n /** The modal broadcast to display */\n broadcast: BroadcastNotification | null;\n /** Whether the modal should be shown */\n isOpen: boolean;\n /** Close the modal */\n close: () => void;\n /** Handle action button click */\n handleAction: () => void;\n}\n\n/**\n * Hook for managing announcement modal display\n * Automatically tracks impressions and handles dismissal\n *\n * @example\n * ```tsx\n * const { broadcast, isOpen, close, handleAction } = useAnnouncementModal();\n *\n * return (\n * <Dialog open={isOpen} onOpenChange={(open) => !open && close()}>\n * <DialogContent>\n * <h2>{broadcast?.title}</h2>\n * <p>{broadcast?.message}</p>\n * {broadcast?.actionUrl && (\n * <Button onClick={handleAction}>{broadcast.actionText || 'Learn More'}</Button>\n * )}\n * </DialogContent>\n * </Dialog>\n * );\n * ```\n */\nexport function useAnnouncementModal(): UseAnnouncementModalReturn {\n const { broadcast, dismiss, trackImpression, trackClick } = useSingleBroadcast({\n variant: 'modal',\n });\n\n const [isOpen, setIsOpen] = useState(false);\n const impressionTrackedRef = useRef(false);\n\n // Show modal when broadcast is available\n useEffect(() => {\n if (broadcast && !impressionTrackedRef.current) {\n setIsOpen(true);\n trackImpression();\n impressionTrackedRef.current = true;\n }\n }, [broadcast, trackImpression]);\n\n const handleClose = useCallback(() => {\n setIsOpen(false);\n dismiss();\n }, [dismiss]);\n\n const handleAction = useCallback(() => {\n trackClick();\n if (broadcast?.actionUrl) {\n window.open(broadcast.actionUrl, '_blank');\n }\n handleClose();\n }, [broadcast, trackClick, handleClose]);\n\n return {\n broadcast,\n isOpen,\n close: handleClose,\n handleAction,\n };\n}\n","/**\n * useFeatureFlags Hook\n *\n * React hook for checking feature availability and status in consumer projects.\n *\n * @author Ahsan Mahmood <aoneahsan@gmail.com>\n */\n\nimport { useState, useEffect, useCallback, useRef } from 'react';\nimport {\n getSharedFeaturesStatus,\n checkFeatureAvailability,\n isFeatureEnabled,\n subscribeToFeatureFlags,\n clearFeatureFlagsCache,\n} from '../services/featureFlags';\nimport { isInitialized, getState } from '../firebase/config';\nimport type {\n FeatureId,\n FeatureAvailability,\n SharedFeaturesStatus,\n UseFeatureFlagsOptions,\n UseFeatureFlagsResult,\n ConsumerFeatureVersions,\n} from '../types/featureFlags';\n\n/**\n * Hook to fetch and monitor feature flags\n *\n * @param options - Hook options\n * @returns Feature flags status and utilities\n *\n * @example\n * ```tsx\n * const {\n * status,\n * loading,\n * isFeatureAvailable,\n * hasDeprecatedFeatures\n * } = useFeatureFlags();\n *\n * if (loading) return <Spinner />;\n *\n * if (!status?.operational) {\n * return <MaintenancePage message={status?.maintenanceMessage} />;\n * }\n *\n * if (isFeatureAvailable('contactInfo')) {\n * return <ContactInfo />;\n * }\n * ```\n */\nexport function useFeatureFlags(\n options: UseFeatureFlagsOptions = {}\n): UseFeatureFlagsResult {\n const {\n autoRefresh = false,\n refreshInterval = 5 * 60 * 1000, // 5 minutes\n autoFetch = true,\n } = options;\n\n const [status, setStatus] = useState<SharedFeaturesStatus | null>(null);\n const [loading, setLoading] = useState(autoFetch);\n const [error, setError] = useState<string | null>(null);\n\n // Track mounted state to prevent state updates after unmount\n const mountedRef = useRef(true);\n\n // Get consumer versions from config if available\n const consumerVersions = useRef<ConsumerFeatureVersions | undefined>(\n getState().config?.featureVersions\n );\n\n // Fetch status\n const fetchStatus = useCallback(async () => {\n if (!isInitialized()) {\n setError('shared-features not initialized');\n setLoading(false);\n return;\n }\n\n setLoading(true);\n setError(null);\n\n try {\n const newStatus = await getSharedFeaturesStatus(consumerVersions.current);\n\n if (mountedRef.current) {\n setStatus(newStatus);\n }\n } catch (err) {\n const message =\n err instanceof Error ? err.message : 'Failed to fetch feature flags';\n\n if (mountedRef.current) {\n setError(message);\n console.error('[shared-features] Error fetching feature flags:', err);\n }\n } finally {\n if (mountedRef.current) {\n setLoading(false);\n }\n }\n }, []);\n\n // Auto-fetch on mount\n useEffect(() => {\n if (autoFetch) {\n fetchStatus();\n }\n }, [autoFetch, fetchStatus]);\n\n // Auto-refresh interval\n useEffect(() => {\n if (!autoRefresh) return;\n\n const interval = setInterval(() => {\n fetchStatus();\n }, refreshInterval);\n\n return () => clearInterval(interval);\n }, [autoRefresh, refreshInterval, fetchStatus]);\n\n // Cleanup on unmount\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n };\n }, []);\n\n // Check if a feature is available\n const checkFeatureAvailable = useCallback(\n (featureId: FeatureId): boolean => {\n // Quick check using cached data\n if (!status) return isFeatureEnabled(featureId);\n\n const availability = status.features[featureId];\n return availability?.available ?? false;\n },\n [status]\n );\n\n // Get feature availability details\n const getAvailability = useCallback(\n (featureId: FeatureId): FeatureAvailability | null => {\n if (!status) return null;\n return status.features[featureId] ?? null;\n },\n [status]\n );\n\n // Refetch with cache clear\n const refetch = useCallback(async () => {\n clearFeatureFlagsCache();\n await fetchStatus();\n }, [fetchStatus]);\n\n return {\n status,\n loading,\n error,\n refetch,\n isFeatureAvailable: checkFeatureAvailable,\n getFeatureAvailability: getAvailability,\n hasDeprecatedFeatures: (status?.deprecatedFeatures.length ?? 0) > 0,\n hasUpgradeRequired: (status?.upgradeRequiredFeatures.length ?? 0) > 0,\n };\n}\n\n/**\n * Hook to check a single feature's availability\n *\n * @param featureId - The feature to check\n * @returns Feature availability and loading state\n *\n * @example\n * ```tsx\n * const { available, loading, deprecated } = useFeature('contactInfo');\n *\n * if (loading) return <Spinner />;\n * if (!available) return null;\n *\n * return <ContactInfo />;\n * ```\n */\nexport function useFeature(featureId: FeatureId) {\n const [availability, setAvailability] = useState<FeatureAvailability | null>(\n null\n );\n const [loading, setLoading] = useState(true);\n\n useEffect(() => {\n let mounted = true;\n\n const checkFeature = async () => {\n if (!isInitialized()) {\n setLoading(false);\n return;\n }\n\n try {\n const consumerVersions = getState().config?.featureVersions;\n const result = await checkFeatureAvailability(\n featureId,\n consumerVersions\n );\n\n if (mounted) {\n setAvailability(result);\n }\n } catch (err) {\n console.error(\n `[shared-features] Error checking feature '${featureId}':`,\n err\n );\n } finally {\n if (mounted) {\n setLoading(false);\n }\n }\n };\n\n checkFeature();\n\n return () => {\n mounted = false;\n };\n }, [featureId]);\n\n return {\n /** Whether the feature is available */\n available: availability?.available ?? false,\n /** Whether the check is in progress */\n loading,\n /** Full availability details */\n availability,\n /** Whether the feature is enabled (but might need upgrade) */\n enabled: availability?.enabled ?? false,\n /** Whether using a deprecated version */\n deprecated: availability?.deprecated ?? false,\n /** Whether an upgrade is required */\n upgradeRequired: availability?.upgradeRequired ?? false,\n /** Deprecation warning if applicable */\n deprecationWarning: availability?.deprecationWarning,\n /** Reason feature is unavailable */\n unavailableReason: availability?.unavailableReason,\n };\n}\n\n/**\n * Hook to subscribe to real-time feature flag updates\n *\n * @param callback - Function to call when flags change\n *\n * @example\n * ```tsx\n * useFeatureFlagsSubscription((flags) => {\n * if (flags?.maintenanceMode) {\n * showMaintenanceBanner();\n * }\n * });\n * ```\n */\nexport function useFeatureFlagsSubscription(\n callback: (status: SharedFeaturesStatus | null) => void\n) {\n const callbackRef = useRef(callback);\n callbackRef.current = callback;\n\n useEffect(() => {\n if (!isInitialized()) return;\n\n const consumerVersions = getState().config?.featureVersions;\n\n const unsubscribe = subscribeToFeatureFlags(async (flags) => {\n if (!flags) {\n callbackRef.current(null);\n return;\n }\n\n // Get full status with current flags\n const status = await getSharedFeaturesStatus(consumerVersions);\n callbackRef.current(status);\n });\n\n return () => unsubscribe();\n }, []);\n}\n\n/**\n * Hook to check if shared-features is operational\n *\n * @returns Whether shared-features is operational\n *\n * @example\n * ```tsx\n * const { operational, maintenanceMessage } = useSharedFeaturesOperational();\n *\n * if (!operational) {\n * return <MaintenancePage message={maintenanceMessage} />;\n * }\n * ```\n */\nexport function useSharedFeaturesOperational() {\n const { status, loading } = useFeatureFlags({ autoFetch: true });\n\n return {\n /** Whether shared-features is operational */\n operational: status?.operational ?? false,\n /** Whether check is in progress */\n loading,\n /** Maintenance message if in maintenance mode */\n maintenanceMessage: status?.maintenanceMessage,\n /** Whether in maintenance mode */\n maintenanceMode: status?.maintenanceMode ?? false,\n /** Current API version */\n apiVersion: status?.apiVersion ?? 'v1',\n };\n}\n\n/**\n * Hook for conditional rendering based on feature availability\n *\n * @param featureId - The feature to check\n * @returns Object with show/hide helpers\n *\n * @example\n * ```tsx\n * const { shouldRender, FallbackOrChildren } = useFeatureGate('contactInfo');\n *\n * return (\n * <FallbackOrChildren fallback={<OldContactInfo />}>\n * <NewContactInfo />\n * </FallbackOrChildren>\n * );\n * ```\n */\nexport function useFeatureGate(featureId: FeatureId) {\n const { available, loading, deprecated, deprecationWarning } =\n useFeature(featureId);\n\n // Log deprecation warning in development\n useEffect(() => {\n if (deprecated && deprecationWarning) {\n console.warn(`[shared-features] ${deprecationWarning}`);\n }\n }, [deprecated, deprecationWarning]);\n\n return {\n /** Whether the feature should be rendered */\n shouldRender: available,\n /** Whether still checking availability */\n loading,\n /** Whether using deprecated version */\n deprecated,\n /** Component that renders children if available, fallback otherwise */\n FallbackOrChildren: useCallback(\n ({\n children,\n fallback = null,\n }: {\n children: React.ReactNode;\n fallback?: React.ReactNode;\n }) => {\n if (loading) return null;\n return available ? children : fallback;\n },\n [available, loading]\n ),\n };\n}\n"],"names":[],"mappings":"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"}