@wlloyalty/wll-react-sdk 1.0.102 → 1.0.103

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.
@@ -4,6 +4,7 @@ import { NavigationConfig } from '../types/navigation';
4
4
  import { TSection } from '../types/section';
5
5
  import { BaseThemeObject, ThemeContextType } from '../types/theme';
6
6
  import { CTALinkTarget, Tile } from '../types/tile';
7
+ import { EventTypes } from '../utils/eventEmitter';
7
8
  type Fetcher = <T>(endpoint: string, options?: RequestInit) => Promise<APIResponse<T>>;
8
9
  export type SDKConfig = {
9
10
  apiKey: string;
@@ -22,6 +23,8 @@ type WllSdkContextType = ThemeContextType & {
22
23
  getTileByID: (id: string) => Promise<APIResponse<Tile>>;
23
24
  handleNavigation: (link: string, target: CTALinkTarget) => Promise<void>;
24
25
  refreshGroup: (id: string) => Promise<APIResponse<TGroup>>;
26
+ notifyDataChange: (eventType: EventTypes, data?: any) => void;
27
+ subscribeToDataChange: (eventType: EventTypes, callback: (data?: any) => void) => () => void;
25
28
  } & Readonly<{
26
29
  readonly config: SDKConfig;
27
30
  }>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Type definition for event callback functions
3
+ * @typedef {function} EventCallback
4
+ * @param {any} [data] - Optional data passed with the event
5
+ */
6
+ export type EventCallback = (data?: any) => void;
7
+ /**
8
+ * Supported event types for the SDK event system
9
+ * @typedef {string} EventTypes
10
+ */
11
+ export type EventTypes = 'GROUP_DATA_CHANGED' | 'SECTION_DATA_CHANGED' | 'TILE_DATA_CHANGED' | string;
12
+ /**
13
+ * A simple event emitter for handling SDK events
14
+ * Provides a pub-sub mechanism for components to communicate
15
+ */
16
+ export declare class EventEmitter {
17
+ /**
18
+ * Map of event types to arrays of callback functions
19
+ * @private
20
+ */
21
+ private events;
22
+ /**
23
+ * Subscribe to an event
24
+ * @param {EventTypes} event - The event type to subscribe to
25
+ * @param {EventCallback} callback - The callback function to execute when the event is emitted
26
+ * @returns {Function} An unsubscribe function that removes this callback when called
27
+ */
28
+ on(event: EventTypes, callback: EventCallback): () => void;
29
+ /**
30
+ * Emit an event with optional data
31
+ * @param {EventTypes} event - The event type to emit
32
+ * @param {any} [data] - Optional data to pass to the event callbacks
33
+ */
34
+ emit(event: EventTypes, data?: any): void;
35
+ /**
36
+ * Remove all event listeners
37
+ * Use this method to clean up when the event emitter is no longer needed
38
+ */
39
+ clear(): void;
40
+ }
41
+ /**
42
+ * Singleton instance of the EventEmitter for use throughout the SDK
43
+ */
44
+ export declare const sdkEventEmitter: EventEmitter;
package/dist/web.js CHANGED
@@ -7924,6 +7924,68 @@ var useGetGroupByID = createResourceGetter('groups', true);
7924
7924
  var useGetSectionByID = createResourceGetter('sections');
7925
7925
  var useGetTileByID = createResourceGetter('tiles');
7926
7926
 
7927
+ /**
7928
+ * A simple event emitter for handling SDK events
7929
+ * Provides a pub-sub mechanism for components to communicate
7930
+ */
7931
+ var EventEmitter$1 = /** @class */function () {
7932
+ function EventEmitter() {
7933
+ /**
7934
+ * Map of event types to arrays of callback functions
7935
+ * @private
7936
+ */
7937
+ this.events = new Map();
7938
+ }
7939
+ /**
7940
+ * Subscribe to an event
7941
+ * @param {EventTypes} event - The event type to subscribe to
7942
+ * @param {EventCallback} callback - The callback function to execute when the event is emitted
7943
+ * @returns {Function} An unsubscribe function that removes this callback when called
7944
+ */
7945
+ EventEmitter.prototype.on = function (event, callback) {
7946
+ var _this = this;
7947
+ var _a;
7948
+ if (!this.events.has(event)) {
7949
+ this.events.set(event, []);
7950
+ }
7951
+ (_a = this.events.get(event)) === null || _a === void 0 ? void 0 : _a.push(callback);
7952
+ return function () {
7953
+ var callbacks = _this.events.get(event);
7954
+ if (callbacks) {
7955
+ var index = callbacks.indexOf(callback);
7956
+ if (index !== -1) {
7957
+ callbacks.splice(index, 1);
7958
+ }
7959
+ }
7960
+ };
7961
+ };
7962
+ /**
7963
+ * Emit an event with optional data
7964
+ * @param {EventTypes} event - The event type to emit
7965
+ * @param {any} [data] - Optional data to pass to the event callbacks
7966
+ */
7967
+ EventEmitter.prototype.emit = function (event, data) {
7968
+ var callbacks = this.events.get(event);
7969
+ if (callbacks) {
7970
+ callbacks.forEach(function (callback) {
7971
+ return callback(data);
7972
+ });
7973
+ }
7974
+ };
7975
+ /**
7976
+ * Remove all event listeners
7977
+ * Use this method to clean up when the event emitter is no longer needed
7978
+ */
7979
+ EventEmitter.prototype.clear = function () {
7980
+ this.events.clear();
7981
+ };
7982
+ return EventEmitter;
7983
+ }();
7984
+ /**
7985
+ * Singleton instance of the EventEmitter for use throughout the SDK
7986
+ */
7987
+ var sdkEventEmitter = new EventEmitter$1();
7988
+
7927
7989
  var sizes = {
7928
7990
  borderRadiusSm: 15,
7929
7991
  borderRadiusLg: 20,
@@ -8525,6 +8587,12 @@ var WllSdkProvider = function (_a) {
8525
8587
  });
8526
8588
  });
8527
8589
  }, [getGroupByID]);
8590
+ var notifyDataChange = React.useCallback(function (eventType, data) {
8591
+ sdkEventEmitter.emit(eventType, data);
8592
+ }, []);
8593
+ var subscribeToDataChange = React.useCallback(function (eventType, callback) {
8594
+ return sdkEventEmitter.on(eventType, callback);
8595
+ }, []);
8528
8596
  var contextValue = React.useMemo(function () {
8529
8597
  return {
8530
8598
  theme: theme,
@@ -8534,9 +8602,11 @@ var WllSdkProvider = function (_a) {
8534
8602
  getTileByID: getTileByID,
8535
8603
  handleNavigation: handleNavigation,
8536
8604
  refreshGroup: refreshGroup,
8605
+ notifyDataChange: notifyDataChange,
8606
+ subscribeToDataChange: subscribeToDataChange,
8537
8607
  config: config
8538
8608
  };
8539
- }, [theme, setTheme, getGroupByID, getSectionByID, getTileByID, handleNavigation, refreshGroup, config]);
8609
+ }, [theme, setTheme, getGroupByID, getSectionByID, getTileByID, handleNavigation, refreshGroup, notifyDataChange, subscribeToDataChange, config]);
8540
8610
  return /*#__PURE__*/React.createElement(WllSdkContext.Provider, {
8541
8611
  value: contextValue
8542
8612
  }, /*#__PURE__*/React.createElement(ResponsiveProvider, null, children));
@@ -21107,6 +21177,14 @@ var useGroupContext = function () {
21107
21177
  /**
21108
21178
  * Custom hook to fetch and manage group data
21109
21179
  *
21180
+ * This hook handles two distinct data fetching scenarios:
21181
+ * 1. Initial fetch: Shows loading state while first loading data
21182
+ * 2. Background refresh: Updates data silently without loading states
21183
+ *
21184
+ * The hook subscribes to GROUP_DATA_CHANGED events to refresh data
21185
+ * when notified by the host application, ensuring UI remains responsive
21186
+ * without showing loading indicators during refreshes.
21187
+ *
21110
21188
  * @param {string} id - The ID of the group to fetch
21111
21189
  * @returns {Object} Object containing group data, loading state, and any error
21112
21190
  */
@@ -21121,27 +21199,22 @@ var useGroupData = function (id) {
21121
21199
  var _c = React.useState(true),
21122
21200
  isLoading = _c[0],
21123
21201
  setIsLoading = _c[1];
21124
- var fetchGroup = React.useCallback(function () {
21125
- var args_1 = [];
21126
- for (var _i = 0; _i < arguments.length; _i++) {
21127
- args_1[_i] = arguments[_i];
21128
- }
21129
- return __awaiter(void 0, __spreadArray([], args_1, true), void 0, function (showLoading) {
21202
+ var _d = React.useState(false),
21203
+ isInitialFetchDone = _d[0],
21204
+ setIsInitialFetchDone = _d[1];
21205
+ var initialFetch = React.useCallback(function () {
21206
+ return __awaiter(void 0, void 0, void 0, function () {
21130
21207
  var response, err_1;
21131
- if (showLoading === void 0) {
21132
- showLoading = true;
21133
- }
21134
21208
  return __generator(this, function (_a) {
21135
21209
  switch (_a.label) {
21136
21210
  case 0:
21137
21211
  if (!id || !sdk || !sdk.getGroupByID) {
21138
21212
  setError('Unable to fetch group data: invalid configuration');
21139
21213
  setIsLoading(false);
21214
+ setIsInitialFetchDone(true);
21140
21215
  return [2 /*return*/];
21141
21216
  }
21142
- if (showLoading) {
21143
- setIsLoading(true);
21144
- }
21217
+ setIsLoading(true);
21145
21218
  setError(null);
21146
21219
  _a.label = 1;
21147
21220
  case 1:
@@ -21161,9 +21234,8 @@ var useGroupData = function (id) {
21161
21234
  console.error('Error fetching group:', err_1);
21162
21235
  return [3 /*break*/, 5];
21163
21236
  case 4:
21164
- if (showLoading) {
21165
- setIsLoading(false);
21166
- }
21237
+ setIsLoading(false);
21238
+ setIsInitialFetchDone(true);
21167
21239
  return [7 /*endfinally*/];
21168
21240
  case 5:
21169
21241
  return [2 /*return*/];
@@ -21171,12 +21243,49 @@ var useGroupData = function (id) {
21171
21243
  });
21172
21244
  });
21173
21245
  }, [id, sdk]);
21246
+ var silentRefresh = React.useCallback(function () {
21247
+ return __awaiter(void 0, void 0, void 0, function () {
21248
+ var response, err_2;
21249
+ return __generator(this, function (_a) {
21250
+ switch (_a.label) {
21251
+ case 0:
21252
+ if (!id || !sdk || !sdk.getGroupByID || !isInitialFetchDone) {
21253
+ return [2 /*return*/];
21254
+ }
21255
+ _a.label = 1;
21256
+ case 1:
21257
+ _a.trys.push([1, 3,, 4]);
21258
+ return [4 /*yield*/, sdk.refreshGroup(id)];
21259
+ case 2:
21260
+ response = _a.sent();
21261
+ if (response && response.status === 'success' && response.data) {
21262
+ setGroupData(response.data);
21263
+ }
21264
+ return [3 /*break*/, 4];
21265
+ case 3:
21266
+ err_2 = _a.sent();
21267
+ console.error('Error during silent refresh:', err_2);
21268
+ return [3 /*break*/, 4];
21269
+ case 4:
21270
+ return [2 /*return*/];
21271
+ }
21272
+ });
21273
+ });
21274
+ }, [id, sdk, isInitialFetchDone]);
21174
21275
  var refreshGroup = React.useCallback(function () {
21175
- return fetchGroup(false);
21176
- }, [fetchGroup]);
21276
+ return silentRefresh();
21277
+ }, [silentRefresh]);
21177
21278
  React.useEffect(function () {
21178
- fetchGroup(true);
21179
- }, [fetchGroup]);
21279
+ if (sdk) {
21280
+ initialFetch();
21281
+ var unsubscribeGroup_1 = sdk.subscribeToDataChange('GROUP_DATA_CHANGED', function () {
21282
+ silentRefresh();
21283
+ });
21284
+ return function () {
21285
+ unsubscribeGroup_1();
21286
+ };
21287
+ }
21288
+ }, [initialFetch, id, sdk, silentRefresh]);
21180
21289
  return {
21181
21290
  groupData: groupData,
21182
21291
  isLoading: isLoading,
@@ -21273,7 +21382,7 @@ var Group = function (_a) {
21273
21382
  groupData: groupData
21274
21383
  }
21275
21384
  }, /*#__PURE__*/React.createElement(View$2, {
21276
- "data-testid": "group-container"
21385
+ testID: "group-container"
21277
21386
  }, /*#__PURE__*/React.createElement(GroupSections, null)));
21278
21387
  };
21279
21388