@datlv-trustshop/shopify-inapp-components 0.1.9

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 (74) hide show
  1. package/README.md +141 -0
  2. package/dist/components/AppList.d.ts +13 -0
  3. package/dist/components/AppList.js +64 -0
  4. package/dist/components/ArticleList.d.ts +20 -0
  5. package/dist/components/ArticleList.js +174 -0
  6. package/dist/components/ArticleSlide.d.ts +14 -0
  7. package/dist/components/ArticleSlide.js +151 -0
  8. package/dist/components/FooterBanner.d.ts +10 -0
  9. package/dist/components/FooterBanner.js +72 -0
  10. package/dist/components/GrowApps.d.ts +13 -0
  11. package/dist/components/GrowApps.js +213 -0
  12. package/dist/components/ImageLoading.d.ts +15 -0
  13. package/dist/components/ImageLoading.js +66 -0
  14. package/dist/components/PartnerList.d.ts +9 -0
  15. package/dist/components/PartnerList.js +102 -0
  16. package/dist/components/PopupBanner.d.ts +12 -0
  17. package/dist/components/PopupBanner.js +100 -0
  18. package/dist/components/TopBanner.d.ts +14 -0
  19. package/dist/components/TopBanner.js +31 -0
  20. package/dist/components/WhatsNew.d.ts +14 -0
  21. package/dist/components/WhatsNew.js +258 -0
  22. package/dist/components/index.d.ts +9 -0
  23. package/dist/components/index.js +9 -0
  24. package/dist/components/inlineStyles.d.ts +110 -0
  25. package/dist/components/inlineStyles.js +114 -0
  26. package/dist/components/styles.d.ts +152 -0
  27. package/dist/components/styles.js +158 -0
  28. package/dist/core/adapter.d.ts +6 -0
  29. package/dist/core/adapter.js +301 -0
  30. package/dist/core/engine.d.ts +33 -0
  31. package/dist/core/engine.js +176 -0
  32. package/dist/core/fetcher.d.ts +4 -0
  33. package/dist/core/fetcher.js +72 -0
  34. package/dist/core/global-manager.d.ts +99 -0
  35. package/dist/core/global-manager.js +315 -0
  36. package/dist/hooks/index.d.ts +6 -0
  37. package/dist/hooks/index.js +6 -0
  38. package/dist/hooks/useApps.d.ts +3 -0
  39. package/dist/hooks/useApps.js +18 -0
  40. package/dist/hooks/useArticles.d.ts +11 -0
  41. package/dist/hooks/useArticles.js +49 -0
  42. package/dist/hooks/useBanner.d.ts +5 -0
  43. package/dist/hooks/useBanner.js +22 -0
  44. package/dist/hooks/useDashboard.d.ts +11 -0
  45. package/dist/hooks/useDashboard.js +13 -0
  46. package/dist/hooks/useGrowApps.d.ts +10 -0
  47. package/dist/hooks/useGrowApps.js +14 -0
  48. package/dist/hooks/useTranslations.d.ts +3 -0
  49. package/dist/hooks/useTranslations.js +9 -0
  50. package/dist/hooks/useWhatsNew.d.ts +11 -0
  51. package/dist/hooks/useWhatsNew.js +34 -0
  52. package/dist/index.d.ts +18 -0
  53. package/dist/index.js +16 -0
  54. package/dist/provider/DashboardProvider.d.ts +36 -0
  55. package/dist/provider/DashboardProvider.js +184 -0
  56. package/dist/translations/default.d.ts +2 -0
  57. package/dist/translations/default.js +27 -0
  58. package/dist/types/app.d.ts +14 -0
  59. package/dist/types/app.js +1 -0
  60. package/dist/types/article.d.ts +14 -0
  61. package/dist/types/article.js +1 -0
  62. package/dist/types/banner.d.ts +22 -0
  63. package/dist/types/banner.js +1 -0
  64. package/dist/types/dashboard.d.ts +42 -0
  65. package/dist/types/dashboard.js +1 -0
  66. package/dist/types/index.d.ts +6 -0
  67. package/dist/types/index.js +6 -0
  68. package/dist/types/partner.d.ts +8 -0
  69. package/dist/types/partner.js +1 -0
  70. package/dist/types/product-update.d.ts +23 -0
  71. package/dist/types/product-update.js +1 -0
  72. package/dist/types/translations.d.ts +28 -0
  73. package/dist/types/translations.js +1 -0
  74. package/package.json +61 -0
@@ -0,0 +1,176 @@
1
+ import { adaptDashboardData } from "./adapter";
2
+ import { fetchDashboard } from "./fetcher";
3
+ export class DashboardEngine {
4
+ constructor(config) {
5
+ this.data = null;
6
+ this.initPromise = null;
7
+ this.lastFetchTime = 0;
8
+ this.listeners = new Set();
9
+ this.fetchInProgress = false;
10
+ this.config = {
11
+ cacheTime: 5 * 60 * 1000,
12
+ retryAttempts: 3,
13
+ retryDelay: 1000,
14
+ locale: "en",
15
+ ...config,
16
+ };
17
+ this.currentLocale = this.config.locale || "en";
18
+ }
19
+ static getInstance(config) {
20
+ if (!DashboardEngine.instance) {
21
+ if (!config) {
22
+ throw new Error("DashboardEngine requires config on first initialization");
23
+ }
24
+ DashboardEngine.instance = new DashboardEngine(config);
25
+ }
26
+ return DashboardEngine.instance;
27
+ }
28
+ static resetInstance() {
29
+ DashboardEngine.instance = null;
30
+ }
31
+ async init(forceRefresh = false) {
32
+ const now = Date.now();
33
+ const cacheExpired = now - this.lastFetchTime > (this.config.cacheTime || 0);
34
+ if (!forceRefresh && !cacheExpired && this.data) {
35
+ return Promise.resolve();
36
+ }
37
+ if (this.fetchInProgress && this.initPromise) {
38
+ return this.initPromise;
39
+ }
40
+ if (!this.initPromise || forceRefresh || cacheExpired) {
41
+ this.fetchInProgress = true;
42
+ this.initPromise = this.loadData().finally(() => {
43
+ this.fetchInProgress = false;
44
+ });
45
+ }
46
+ return this.initPromise;
47
+ }
48
+ async loadData() {
49
+ try {
50
+ const rawData = await fetchDashboard(this.config);
51
+ this.data = adaptDashboardData(rawData);
52
+ this.lastFetchTime = Date.now();
53
+ this.notifyListeners();
54
+ }
55
+ catch (error) {
56
+ console.error("Failed to load dashboard data:", error);
57
+ throw error;
58
+ }
59
+ }
60
+ subscribe(listener) {
61
+ this.listeners.add(listener);
62
+ listener(this.data);
63
+ return () => {
64
+ this.listeners.delete(listener);
65
+ };
66
+ }
67
+ notifyListeners() {
68
+ this.listeners.forEach((listener) => listener(this.data));
69
+ }
70
+ getData() {
71
+ return this.data;
72
+ }
73
+ getBanners(type) {
74
+ if (!this.data?.banners)
75
+ return [];
76
+ if (type) {
77
+ return this.data.banners.filter((banner) => banner.type === type);
78
+ }
79
+ return this.data.banners;
80
+ }
81
+ getActiveBanners(type) {
82
+ return this.getBanners(type).filter((banner) => banner.isActive !== false);
83
+ }
84
+ getApps(group) {
85
+ if (!this.data?.apps)
86
+ return [];
87
+ if (group) {
88
+ return this.data.apps[group] || [];
89
+ }
90
+ return Object.values(this.data.apps).flat();
91
+ }
92
+ getAppGroups() {
93
+ if (!this.data?.apps)
94
+ return [];
95
+ return Object.keys(this.data.apps);
96
+ }
97
+ getArticles(limit) {
98
+ if (!this.data?.articles)
99
+ return [];
100
+ if (limit && limit > 0) {
101
+ return this.data.articles.slice(0, limit);
102
+ }
103
+ return this.data.articles;
104
+ }
105
+ getWhatsNew(limit) {
106
+ if (!this.data?.whatsNew)
107
+ return [];
108
+ if (limit && limit > 0) {
109
+ return this.data.whatsNew.slice(0, limit);
110
+ }
111
+ return this.data.whatsNew;
112
+ }
113
+ async refresh() {
114
+ return this.init(true);
115
+ }
116
+ isInitialized() {
117
+ return this.data !== null;
118
+ }
119
+ getCacheAge() {
120
+ if (!this.lastFetchTime)
121
+ return Infinity;
122
+ return Date.now() - this.lastFetchTime;
123
+ }
124
+ isCacheValid() {
125
+ return this.getCacheAge() < (this.config.cacheTime || 0);
126
+ }
127
+ updateLocale(locale) {
128
+ if (this.currentLocale !== locale) {
129
+ this.currentLocale = locale;
130
+ this.config = { ...this.config, locale };
131
+ this.data = null;
132
+ this.lastFetchTime = 0;
133
+ this.initPromise = null;
134
+ return true; // Locale was changed
135
+ }
136
+ return false; // Locale was not changed
137
+ }
138
+ async setLocale(locale) {
139
+ if (this.currentLocale !== locale) {
140
+ const wasInitialized = this.isInitialized();
141
+ this.currentLocale = locale;
142
+ this.config = { ...this.config, locale };
143
+ // Clear data to force refresh with new locale
144
+ this.data = null;
145
+ this.lastFetchTime = 0;
146
+ this.initPromise = null;
147
+ // If engine was initialized, automatically refresh with new locale
148
+ if (wasInitialized) {
149
+ await this.init();
150
+ }
151
+ // Notify listeners about the change
152
+ this.notifyListeners();
153
+ }
154
+ }
155
+ updateConfig(newConfig) {
156
+ const oldConfig = this.config;
157
+ this.config = { ...this.config, ...newConfig };
158
+ // If locale changed, update current locale and clear cache
159
+ if (newConfig.locale && newConfig.locale !== this.currentLocale) {
160
+ this.currentLocale = newConfig.locale;
161
+ this.data = null;
162
+ this.lastFetchTime = 0;
163
+ this.initPromise = null;
164
+ }
165
+ // If API URL changed, clear cache
166
+ if (newConfig.apiUrl && newConfig.apiUrl !== oldConfig.apiUrl) {
167
+ this.data = null;
168
+ this.lastFetchTime = 0;
169
+ this.initPromise = null;
170
+ }
171
+ }
172
+ getCurrentLocale() {
173
+ return this.currentLocale;
174
+ }
175
+ }
176
+ DashboardEngine.instance = null;
@@ -0,0 +1,4 @@
1
+ import { DashboardConfig } from "../types";
2
+ export declare function fetchDashboard(config: DashboardConfig): Promise<any>;
3
+ export declare function clearCache(url?: string): void;
4
+ export declare function getCacheSize(): number;
@@ -0,0 +1,72 @@
1
+ const cache = new Map();
2
+ export async function fetchDashboard(config) {
3
+ // Build URL with locale query param
4
+ // Handle both absolute and relative URLs
5
+ let url;
6
+ try {
7
+ // Try as absolute URL first
8
+ url = new URL(config.apiUrl);
9
+ }
10
+ catch {
11
+ // If it fails, treat as relative URL
12
+ const baseUrl = typeof window !== 'undefined'
13
+ ? window.location.origin
14
+ : 'http://localhost:3000';
15
+ url = new URL(config.apiUrl, baseUrl);
16
+ }
17
+ const locale = config.locale || 'en';
18
+ url.searchParams.set('locale', locale);
19
+ // Use URL with locale as cache key
20
+ const cacheKey = url.toString();
21
+ const now = Date.now();
22
+ if (config.cacheTime && config.cacheTime > 0) {
23
+ const cached = cache.get(cacheKey);
24
+ if (cached && now - cached.timestamp < config.cacheTime) {
25
+ return Promise.resolve(cached.data);
26
+ }
27
+ }
28
+ const attemptFetch = async (attempt = 1) => {
29
+ try {
30
+ const response = await fetch(url.toString(), {
31
+ method: "GET",
32
+ headers: {
33
+ "Content-Type": "application/json",
34
+ "Accept-Language": locale, // Also send locale in header
35
+ ...config.headers,
36
+ },
37
+ });
38
+ if (!response.ok) {
39
+ throw new Error(`HTTP error! status: ${response.status}`);
40
+ }
41
+ const data = await response.json();
42
+ if (config.cacheTime && config.cacheTime > 0) {
43
+ cache.set(cacheKey, {
44
+ data,
45
+ timestamp: now,
46
+ });
47
+ }
48
+ return data;
49
+ }
50
+ catch (error) {
51
+ const maxAttempts = config.retryAttempts || 3;
52
+ if (attempt < maxAttempts) {
53
+ const delay = (config.retryDelay || 1000) * attempt;
54
+ await new Promise((resolve) => setTimeout(resolve, delay));
55
+ return attemptFetch(attempt + 1);
56
+ }
57
+ throw error;
58
+ }
59
+ };
60
+ return attemptFetch();
61
+ }
62
+ export function clearCache(url) {
63
+ if (url) {
64
+ cache.delete(url);
65
+ }
66
+ else {
67
+ cache.clear();
68
+ }
69
+ }
70
+ export function getCacheSize() {
71
+ return cache.size;
72
+ }
@@ -0,0 +1,99 @@
1
+ import { DashboardEngine } from "./engine";
2
+ import { DashboardConfig, DashboardState } from "../types";
3
+ /**
4
+ * GlobalDashboardManager - Singleton manager for shared SDK state
5
+ *
6
+ * This manager ensures all DashboardProvider instances share:
7
+ * - The same engine instance
8
+ * - The same data/cache
9
+ * - The same locale state
10
+ * - Deduplicated API calls
11
+ *
12
+ * Multiple providers can mount/unmount independently while maintaining
13
+ * a stable, shared runtime.
14
+ */
15
+ export declare class GlobalDashboardManager {
16
+ private static instance;
17
+ private engine;
18
+ private providers;
19
+ private stateListeners;
20
+ private globalState;
21
+ private initPromise;
22
+ private autoInitTimer;
23
+ private lastConfig;
24
+ private isInitializing;
25
+ private constructor();
26
+ static getInstance(): GlobalDashboardManager;
27
+ /**
28
+ * Register a provider instance
29
+ */
30
+ registerProvider(id: string, config?: DashboardConfig): void;
31
+ /**
32
+ * Unregister a provider instance
33
+ */
34
+ unregisterProvider(id: string): void;
35
+ /**
36
+ * Get or create the shared engine instance
37
+ */
38
+ private getOrCreateEngine;
39
+ /**
40
+ * Update the global configuration
41
+ */
42
+ private updateGlobalConfig;
43
+ /**
44
+ * Check if two configs are equal
45
+ */
46
+ private configEquals;
47
+ /**
48
+ * Schedule auto-initialization
49
+ */
50
+ private scheduleAutoInit;
51
+ /**
52
+ * Auto-initialize the engine
53
+ */
54
+ private autoInit;
55
+ /**
56
+ * Initialize the shared engine
57
+ */
58
+ init(config?: DashboardConfig): Promise<void>;
59
+ /**
60
+ * Refresh the dashboard data
61
+ */
62
+ refresh(): Promise<void>;
63
+ /**
64
+ * Update locale globally
65
+ */
66
+ setLocale(locale: string): Promise<void>;
67
+ /**
68
+ * Get the current locale
69
+ */
70
+ getCurrentLocale(): string;
71
+ /**
72
+ * Subscribe to global state changes
73
+ */
74
+ subscribe(id: string, callback: (state: DashboardState) => void): () => void;
75
+ /**
76
+ * Update and broadcast global state
77
+ */
78
+ private updateGlobalState;
79
+ /**
80
+ * Get the current global state
81
+ */
82
+ getState(): DashboardState;
83
+ /**
84
+ * Get the shared engine instance (if created)
85
+ */
86
+ getEngine(): DashboardEngine | null;
87
+ /**
88
+ * Check if manager is initialized
89
+ */
90
+ isInitialized(): boolean;
91
+ /**
92
+ * Get provider count
93
+ */
94
+ getProviderCount(): number;
95
+ /**
96
+ * Reset the global manager (for testing)
97
+ */
98
+ static reset(): void;
99
+ }
@@ -0,0 +1,315 @@
1
+ import { DashboardEngine } from "./engine";
2
+ /**
3
+ * GlobalDashboardManager - Singleton manager for shared SDK state
4
+ *
5
+ * This manager ensures all DashboardProvider instances share:
6
+ * - The same engine instance
7
+ * - The same data/cache
8
+ * - The same locale state
9
+ * - Deduplicated API calls
10
+ *
11
+ * Multiple providers can mount/unmount independently while maintaining
12
+ * a stable, shared runtime.
13
+ */
14
+ export class GlobalDashboardManager {
15
+ constructor() {
16
+ this.engine = null;
17
+ this.providers = new Map();
18
+ this.stateListeners = new Set();
19
+ this.globalState = {
20
+ data: null,
21
+ loading: false,
22
+ error: null,
23
+ lastFetch: null,
24
+ };
25
+ this.initPromise = null;
26
+ this.autoInitTimer = null;
27
+ this.lastConfig = null;
28
+ this.isInitializing = false;
29
+ // Private constructor for singleton
30
+ }
31
+ static getInstance() {
32
+ if (!GlobalDashboardManager.instance) {
33
+ GlobalDashboardManager.instance = new GlobalDashboardManager();
34
+ }
35
+ return GlobalDashboardManager.instance;
36
+ }
37
+ /**
38
+ * Register a provider instance
39
+ */
40
+ registerProvider(id, config) {
41
+ this.providers.set(id, {
42
+ id,
43
+ mounted: true,
44
+ config
45
+ });
46
+ // Update config if provided and different
47
+ if (config && !this.configEquals(this.lastConfig, config)) {
48
+ this.updateGlobalConfig(config);
49
+ }
50
+ // Auto-initialize if this is the first provider
51
+ if (this.providers.size === 1 && config) {
52
+ this.scheduleAutoInit();
53
+ }
54
+ }
55
+ /**
56
+ * Unregister a provider instance
57
+ */
58
+ unregisterProvider(id) {
59
+ this.providers.delete(id);
60
+ // Remove associated listeners
61
+ this.stateListeners = new Set(Array.from(this.stateListeners).filter(l => !l.id.startsWith(id)));
62
+ // Don't destroy engine even if no providers - maintain stable runtime
63
+ }
64
+ /**
65
+ * Get or create the shared engine instance
66
+ */
67
+ getOrCreateEngine(config) {
68
+ if (!this.engine) {
69
+ if (!config && !this.lastConfig) {
70
+ throw new Error("GlobalDashboardManager requires config on first use");
71
+ }
72
+ const finalConfig = config || this.lastConfig;
73
+ this.engine = DashboardEngine.getInstance(finalConfig);
74
+ this.lastConfig = finalConfig;
75
+ // Subscribe to engine changes
76
+ this.engine.subscribe((data) => {
77
+ this.updateGlobalState({
78
+ data,
79
+ loading: false,
80
+ error: null,
81
+ lastFetch: data ? new Date() : this.globalState.lastFetch,
82
+ });
83
+ });
84
+ }
85
+ return this.engine;
86
+ }
87
+ /**
88
+ * Update the global configuration
89
+ */
90
+ updateGlobalConfig(config) {
91
+ this.lastConfig = config;
92
+ if (this.engine) {
93
+ // Update existing engine config
94
+ this.engine.updateConfig(config);
95
+ // If locale changed and engine is initialized, refresh
96
+ if (config.locale && config.locale !== this.engine.getCurrentLocale()) {
97
+ const wasInitialized = this.engine.isInitialized();
98
+ if (wasInitialized) {
99
+ this.engine.setLocale(config.locale).catch(console.error);
100
+ }
101
+ else {
102
+ this.engine.updateLocale(config.locale);
103
+ }
104
+ }
105
+ }
106
+ }
107
+ /**
108
+ * Check if two configs are equal
109
+ */
110
+ configEquals(a, b) {
111
+ if (!a || !b)
112
+ return a === b;
113
+ return (a.apiUrl === b.apiUrl &&
114
+ a.locale === b.locale &&
115
+ a.cacheTime === b.cacheTime &&
116
+ a.retryAttempts === b.retryAttempts &&
117
+ a.retryDelay === b.retryDelay);
118
+ }
119
+ /**
120
+ * Schedule auto-initialization
121
+ */
122
+ scheduleAutoInit() {
123
+ if (this.autoInitTimer) {
124
+ clearTimeout(this.autoInitTimer);
125
+ }
126
+ // Delay slightly to allow all providers to mount
127
+ this.autoInitTimer = setTimeout(() => {
128
+ this.autoInit().catch(console.error);
129
+ }, 10);
130
+ }
131
+ /**
132
+ * Auto-initialize the engine
133
+ */
134
+ async autoInit() {
135
+ if (!this.lastConfig || this.isInitializing)
136
+ return;
137
+ const engine = this.getOrCreateEngine();
138
+ // Only init if not already initialized
139
+ if (!engine.isInitialized() && !this.initPromise) {
140
+ await this.init();
141
+ }
142
+ }
143
+ /**
144
+ * Initialize the shared engine
145
+ */
146
+ async init(config) {
147
+ if (this.initPromise && !config) {
148
+ return this.initPromise;
149
+ }
150
+ if (config) {
151
+ this.updateGlobalConfig(config);
152
+ }
153
+ this.isInitializing = true;
154
+ this.updateGlobalState({ ...this.globalState, loading: true, error: null });
155
+ this.initPromise = (async () => {
156
+ try {
157
+ const engine = this.getOrCreateEngine(config);
158
+ await engine.init();
159
+ const data = engine.getData();
160
+ this.updateGlobalState({
161
+ data,
162
+ loading: false,
163
+ error: null,
164
+ lastFetch: new Date(),
165
+ });
166
+ }
167
+ catch (error) {
168
+ const err = error instanceof Error
169
+ ? error
170
+ : new Error("Failed to initialize dashboard");
171
+ this.updateGlobalState({
172
+ ...this.globalState,
173
+ loading: false,
174
+ error: err,
175
+ });
176
+ throw err;
177
+ }
178
+ finally {
179
+ this.isInitializing = false;
180
+ }
181
+ })();
182
+ return this.initPromise;
183
+ }
184
+ /**
185
+ * Refresh the dashboard data
186
+ */
187
+ async refresh() {
188
+ if (!this.engine) {
189
+ return this.init();
190
+ }
191
+ this.updateGlobalState({ ...this.globalState, loading: true, error: null });
192
+ try {
193
+ await this.engine.refresh();
194
+ const data = this.engine.getData();
195
+ this.updateGlobalState({
196
+ data,
197
+ loading: false,
198
+ error: null,
199
+ lastFetch: new Date(),
200
+ });
201
+ }
202
+ catch (error) {
203
+ const err = error instanceof Error
204
+ ? error
205
+ : new Error("Failed to refresh dashboard");
206
+ this.updateGlobalState({
207
+ ...this.globalState,
208
+ loading: false,
209
+ error: err,
210
+ });
211
+ throw err;
212
+ }
213
+ }
214
+ /**
215
+ * Update locale globally
216
+ */
217
+ async setLocale(locale) {
218
+ if (!this.engine) {
219
+ // Update config for future initialization
220
+ if (this.lastConfig) {
221
+ this.lastConfig = { ...this.lastConfig, locale };
222
+ }
223
+ return;
224
+ }
225
+ await this.engine.setLocale(locale);
226
+ }
227
+ /**
228
+ * Get the current locale
229
+ */
230
+ getCurrentLocale() {
231
+ if (this.engine) {
232
+ return this.engine.getCurrentLocale();
233
+ }
234
+ return this.lastConfig?.locale || "en";
235
+ }
236
+ /**
237
+ * Subscribe to global state changes
238
+ */
239
+ subscribe(id, callback) {
240
+ const listener = { id, callback };
241
+ this.stateListeners.add(listener);
242
+ // Immediately call with current state
243
+ callback(this.globalState);
244
+ // Return unsubscribe function
245
+ return () => {
246
+ this.stateListeners.delete(listener);
247
+ };
248
+ }
249
+ /**
250
+ * Update and broadcast global state
251
+ */
252
+ updateGlobalState(state) {
253
+ this.globalState = state;
254
+ // Notify all listeners
255
+ this.stateListeners.forEach(listener => {
256
+ try {
257
+ listener.callback(state);
258
+ }
259
+ catch (error) {
260
+ console.error(`Error in state listener ${listener.id}:`, error);
261
+ }
262
+ });
263
+ }
264
+ /**
265
+ * Get the current global state
266
+ */
267
+ getState() {
268
+ return this.globalState;
269
+ }
270
+ /**
271
+ * Get the shared engine instance (if created)
272
+ */
273
+ getEngine() {
274
+ return this.engine;
275
+ }
276
+ /**
277
+ * Check if manager is initialized
278
+ */
279
+ isInitialized() {
280
+ return this.engine?.isInitialized() || false;
281
+ }
282
+ /**
283
+ * Get provider count
284
+ */
285
+ getProviderCount() {
286
+ return this.providers.size;
287
+ }
288
+ /**
289
+ * Reset the global manager (for testing)
290
+ */
291
+ static reset() {
292
+ if (GlobalDashboardManager.instance) {
293
+ const manager = GlobalDashboardManager.instance;
294
+ // Clear timers
295
+ if (manager.autoInitTimer) {
296
+ clearTimeout(manager.autoInitTimer);
297
+ }
298
+ // Clear listeners
299
+ manager.stateListeners.clear();
300
+ manager.providers.clear();
301
+ // Reset state
302
+ manager.globalState = {
303
+ data: null,
304
+ loading: false,
305
+ error: null,
306
+ lastFetch: null,
307
+ };
308
+ manager.initPromise = null;
309
+ manager.lastConfig = null;
310
+ manager.engine = null;
311
+ }
312
+ GlobalDashboardManager.instance = null;
313
+ }
314
+ }
315
+ GlobalDashboardManager.instance = null;
@@ -0,0 +1,6 @@
1
+ export * from "./useDashboard";
2
+ export * from "./useBanner";
3
+ export * from "./useApps";
4
+ export * from "./useArticles";
5
+ export * from "./useWhatsNew";
6
+ export * from "./useGrowApps";
@@ -0,0 +1,6 @@
1
+ export * from "./useDashboard";
2
+ export * from "./useBanner";
3
+ export * from "./useApps";
4
+ export * from "./useArticles";
5
+ export * from "./useWhatsNew";
6
+ export * from "./useGrowApps";
@@ -0,0 +1,3 @@
1
+ import { AppItem, AppGroup } from "../types";
2
+ export declare function useApps(group?: AppGroup): AppItem[];
3
+ export declare function useAppGroups(): AppGroup[];
@@ -0,0 +1,18 @@
1
+ import { useMemo } from "react";
2
+ import { useDashboardContext } from "../provider/DashboardProvider";
3
+ export function useApps(group) {
4
+ const { engine, state } = useDashboardContext();
5
+ return useMemo(() => {
6
+ if (!engine || !state.data)
7
+ return [];
8
+ return engine.getApps(group);
9
+ }, [engine, group, state.data]);
10
+ }
11
+ export function useAppGroups() {
12
+ const { engine, state } = useDashboardContext();
13
+ return useMemo(() => {
14
+ if (!engine || !state.data)
15
+ return [];
16
+ return engine.getAppGroups();
17
+ }, [engine, state.data]);
18
+ }