@wlloyalty/wll-react-sdk 1.0.102 → 1.0.104

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/dist/index.d.ts CHANGED
@@ -196,6 +196,7 @@ declare class BadgeTileConfig {
196
196
  emptyBadgeArtworkUrl?: string;
197
197
  awardedDatePrefix?: string;
198
198
  badgeNotEarnedMessage?: string;
199
+ lastEarnedAt?: string;
199
200
  }
200
201
  type BadgeDetail = {
201
202
  name: string;
@@ -661,6 +662,12 @@ type NavigationConfig = {
661
662
  baseUrl?: string;
662
663
  };
663
664
 
665
+ /**
666
+ * Supported event types for the SDK event system
667
+ * @typedef {string} EventTypes
668
+ */
669
+ type EventTypes = 'GROUP_DATA_CHANGED' | 'SECTION_DATA_CHANGED' | 'TILE_DATA_CHANGED' | string;
670
+
664
671
  type Fetcher = <T>(endpoint: string, options?: RequestInit) => Promise<APIResponse<T>>;
665
672
  type SDKConfig = {
666
673
  apiKey: string;
@@ -679,6 +686,8 @@ type WllSdkContextType = ThemeContextType & {
679
686
  getTileByID: (id: string) => Promise<APIResponse<Tile>>;
680
687
  handleNavigation: (link: string, target: CTALinkTarget) => Promise<void>;
681
688
  refreshGroup: (id: string) => Promise<APIResponse<TGroup>>;
689
+ notifyDataChange: (eventType: EventTypes, data?: any) => void;
690
+ subscribeToDataChange: (eventType: EventTypes, callback: (data?: any) => void) => () => void;
682
691
  } & Readonly<{
683
692
  readonly config: SDKConfig;
684
693
  }>;
package/dist/native.js CHANGED
@@ -1595,6 +1595,66 @@ var useGetGroupByID = createResourceGetter('groups', true);
1595
1595
  var useGetSectionByID = createResourceGetter('sections');
1596
1596
  var useGetTileByID = createResourceGetter('tiles');
1597
1597
 
1598
+ /**
1599
+ * A simple event emitter for handling SDK events
1600
+ * Provides a pub-sub mechanism for components to communicate
1601
+ */
1602
+ var EventEmitter = /** @class */ (function () {
1603
+ function EventEmitter() {
1604
+ /**
1605
+ * Map of event types to arrays of callback functions
1606
+ * @private
1607
+ */
1608
+ this.events = new Map();
1609
+ }
1610
+ /**
1611
+ * Subscribe to an event
1612
+ * @param {EventTypes} event - The event type to subscribe to
1613
+ * @param {EventCallback} callback - The callback function to execute when the event is emitted
1614
+ * @returns {Function} An unsubscribe function that removes this callback when called
1615
+ */
1616
+ EventEmitter.prototype.on = function (event, callback) {
1617
+ var _this = this;
1618
+ var _a;
1619
+ if (!this.events.has(event)) {
1620
+ this.events.set(event, []);
1621
+ }
1622
+ (_a = this.events.get(event)) === null || _a === void 0 ? void 0 : _a.push(callback);
1623
+ return function () {
1624
+ var callbacks = _this.events.get(event);
1625
+ if (callbacks) {
1626
+ var index = callbacks.indexOf(callback);
1627
+ if (index !== -1) {
1628
+ callbacks.splice(index, 1);
1629
+ }
1630
+ }
1631
+ };
1632
+ };
1633
+ /**
1634
+ * Emit an event with optional data
1635
+ * @param {EventTypes} event - The event type to emit
1636
+ * @param {any} [data] - Optional data to pass to the event callbacks
1637
+ */
1638
+ EventEmitter.prototype.emit = function (event, data) {
1639
+ var callbacks = this.events.get(event);
1640
+ if (callbacks) {
1641
+ callbacks.forEach(function (callback) { return callback(data); });
1642
+ }
1643
+ };
1644
+ /**
1645
+ * Remove all event listeners
1646
+ * Use this method to clean up when the event emitter is no longer needed
1647
+ */
1648
+ EventEmitter.prototype.clear = function () {
1649
+ this.events.clear();
1650
+ };
1651
+ return EventEmitter;
1652
+ }());
1653
+ /**
1654
+ * Singleton instance of the EventEmitter for use throughout the SDK
1655
+ */
1656
+ var sdkEventEmitter = new EventEmitter();
1657
+
1598
1658
  var sizes = {
1599
1659
  borderRadiusSm: 15,
1600
1660
  borderRadiusLg: 20,
@@ -1961,6 +2021,12 @@ var WllSdkProvider = function (_a) {
1961
2021
  return [2 /*return*/, getGroupByID(id)];
1962
2022
  });
1963
2023
  }); }, [getGroupByID]);
2024
+ var notifyDataChange = React.useCallback(function (eventType, data) {
2025
+ sdkEventEmitter.emit(eventType, data);
2026
+ }, []);
2027
+ var subscribeToDataChange = React.useCallback(function (eventType, callback) {
2028
+ return sdkEventEmitter.on(eventType, callback);
2029
+ }, []);
1964
2030
  var contextValue = React.useMemo(function () { return ({
1965
2031
  theme: theme,
1966
2032
  setTheme: setTheme,
@@ -1969,6 +2035,8 @@ var WllSdkProvider = function (_a) {
1969
2035
  getTileByID: getTileByID,
1970
2036
  handleNavigation: handleNavigation,
1971
2037
  refreshGroup: refreshGroup,
2038
+ notifyDataChange: notifyDataChange,
2039
+ subscribeToDataChange: subscribeToDataChange,
1972
2040
  config: config,
1973
2041
  }); }, [
1974
2042
  theme,
@@ -1978,6 +2046,8 @@ var WllSdkProvider = function (_a) {
1978
2046
  getTileByID,
1979
2047
  handleNavigation,
1980
2048
  refreshGroup,
2049
+ notifyDataChange,
2050
+ subscribeToDataChange,
1981
2051
  config,
1982
2052
  ]);
1983
2053
  return (jsxRuntimeExports.jsx(WllSdkContext.Provider, { value: contextValue, children: jsxRuntimeExports.jsx(ResponsiveProvider, { children: children }) }));
@@ -2579,7 +2649,7 @@ var BaseTileBody = function (props) {
2579
2649
  return undefined;
2580
2650
  return isDesktop ? 3 : isTablet ? 4 : 3;
2581
2651
  };
2582
- return (jsxRuntimeExports.jsx(Text, __assign({ variant: "body" }, props, { accessibilityRole: "text", accessibilityLabel: body, numberOfLines: getNumberOfLines(), testID: "tile-body", children: body })));
2652
+ return (jsxRuntimeExports.jsx(Text, __assign({ variant: "body" }, props, { role: "article", accessibilityLabel: body, numberOfLines: getNumberOfLines(), testID: "tile-body", children: body })));
2583
2653
  };
2584
2654
 
2585
2655
  /**
@@ -2691,7 +2761,7 @@ var BaseTileContent = function (_a) {
2691
2761
  justifyContent: 'center',
2692
2762
  height: !artworkUrl ? '100%' : undefined,
2693
2763
  },
2694
- ], accessibilityRole: "none", children: children }));
2764
+ ], role: "none", children: children }));
2695
2765
  };
2696
2766
 
2697
2767
  /**
@@ -2714,7 +2784,7 @@ var BaseTileHeader = function (_a) {
2714
2784
  return null;
2715
2785
  var dynamicStyles = useBaseTileStyles();
2716
2786
  var combinedStyle = __assign(__assign(__assign({}, dynamicStyles.header), { marginTop: sizeInfo.isHalfSize ? 0 : dynamicStyles.header.marginTop }), (sizeInfo.isHalfSize ? { alignItems: 'center' } : {}));
2717
- return (jsxRuntimeExports.jsx(reactNative.View, { style: combinedStyle, testID: "tile-header", accessibilityRole: "header", children: children }));
2787
+ return (jsxRuntimeExports.jsx(reactNative.View, { style: combinedStyle, testID: "tile-header", role: "heading", children: children }));
2718
2788
  };
2719
2789
 
2720
2790
  /**
@@ -2731,7 +2801,7 @@ var BaseTileMedia = function (props) {
2731
2801
  var styles = useBaseTileStyles();
2732
2802
  if (!artworkUrl)
2733
2803
  return null;
2734
- return (jsxRuntimeExports.jsx(ProgressiveImage, __assign({}, props, { source: { uri: artworkUrl }, testID: "tile-media", style: [props.style, baseStyles.media, styles.media], alt: "Content image".concat(title ? " for ".concat(title) : ''), accessibilityRole: "image" })));
2804
+ return (jsxRuntimeExports.jsx(ProgressiveImage, __assign({}, props, { source: { uri: artworkUrl }, testID: "tile-media", style: [props.style, baseStyles.media, styles.media], alt: "Content image".concat(title ? " for ".concat(title) : ''), role: "img" })));
2735
2805
  };
2736
2806
 
2737
2807
  /**
@@ -2754,7 +2824,7 @@ var BaseTileTitle = function () {
2754
2824
  // Don't show title for half tiles with image
2755
2825
  if ((isHalfSize && artworkUrl) || !title)
2756
2826
  return null;
2757
- return (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx(Text, { variant: "title", accessibilityRole: "header", accessibilityLabel: title, numberOfLines: 1, testID: "tile-title", children: title }), ctaLink && (jsxRuntimeExports.jsx(Icon, { name: "ChevronRight", color: (_b = (_a = sdk.theme) === null || _a === void 0 ? void 0 : _a.derivedSurfaceText) === null || _b === void 0 ? void 0 : _b[20], accessibilityLabel: "View details" }))] }));
2827
+ return (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx(Text, { variant: "title", role: "heading", accessibilityLabel: title, numberOfLines: 1, testID: "tile-title", children: title }), ctaLink && (jsxRuntimeExports.jsx(Icon, { name: "ChevronRight", color: (_b = (_a = sdk.theme) === null || _a === void 0 ? void 0 : _a.derivedSurfaceText) === null || _b === void 0 ? void 0 : _b[20], accessibilityLabel: "View details" }))] }));
2758
2828
  };
2759
2829
 
2760
2830
  /**
@@ -2807,7 +2877,7 @@ var BaseTileContainer = function (_a) {
2807
2877
  layout,
2808
2878
  style,
2809
2879
  ];
2810
- }, onPress: handlePress, disabled: tile.type !== 'REWARD' && tile.type !== 'REWARD_CATEGORY' && !ctaLink, accessible: true, accessibilityRole: "button", accessibilityLabel: "".concat(title).concat(ctaLink ? ' - Click to open' : ''), accessibilityState: { disabled: !ctaLink }, children: children }));
2880
+ }, onPress: handlePress, disabled: tile.type !== 'REWARD' && tile.type !== 'REWARD_CATEGORY' && !ctaLink, accessible: true, role: "button", accessibilityLabel: "".concat(title).concat(ctaLink ? ' - Click to open' : ''), accessibilityState: { disabled: !ctaLink }, children: children }));
2811
2881
  };
2812
2882
  /**
2813
2883
  * BaseTileRoot component to provide context and render children.
@@ -3032,6 +3102,63 @@ function withTileFetching(WrappedComponent) {
3032
3102
  };
3033
3103
  }
3034
3104
 
3105
+ /**
3106
+ * Sorts tiles by priority (higher priority first) and maintains original order for equal priorities
3107
+ * @param tiles Array of tiles to sort
3108
+ * @returns Sorted array of tiles
3109
+ */
3110
+ var sortByPriority = function (tiles) {
3111
+ return __spreadArray([], tiles, true).sort(function (a, b) {
3112
+ // Sort by priority (higher priority first)
3113
+ if (a.priority !== b.priority) {
3114
+ return b.priority - a.priority;
3115
+ }
3116
+ // If priorities are equal, maintain original order
3117
+ return tiles.indexOf(a) - tiles.indexOf(b);
3118
+ });
3119
+ };
3120
+ /**
3121
+ * Transforms locale to a locale that is supported by the browser
3122
+ * @param locale Two-letter locale code to transform (en, fr, etc.)
3123
+ * @returns Full locale string (e.g., en-GB, fr-FR)
3124
+ */
3125
+ var transformLocale = function (locale) {
3126
+ var localeMapping = {
3127
+ en: 'en-GB',
3128
+ fr: 'fr-FR',
3129
+ es: 'es-ES',
3130
+ de: 'de-DE',
3131
+ it: 'it-IT',
3132
+ pt: 'pt-PT',
3133
+ us: 'en-US',
3134
+ };
3135
+ var languageCode = (locale !== null && locale !== void 0 ? locale : 'en').toLowerCase();
3136
+ return localeMapping[languageCode] || 'en-GB';
3137
+ };
3138
+ /**
3139
+ * Formats a date string to a localized date string based on user locale
3140
+ * @param date Date string to format
3141
+ * @param userLocale User's locale (defaults to 'en')
3142
+ * @returns Formatted date string or fallback message
3143
+ */
3144
+ var handleLastEarnedDate = function (date, userLocale) {
3145
+ if (userLocale === void 0) { userLocale = 'en'; }
3146
+ if (!date)
3147
+ return 'Date not available';
3148
+ try {
3149
+ var formattedLocale = transformLocale(userLocale);
3150
+ var dateObj = new Date(date);
3151
+ if (isNaN(dateObj.getTime())) {
3152
+ return 'Invalid Date';
3153
+ }
3154
+ return dateObj.toLocaleDateString(formattedLocale);
3155
+ }
3156
+ catch (error) {
3157
+ console.error('Error formatting date:', error);
3158
+ return 'Invalid Date';
3159
+ }
3160
+ };
3161
+
3035
3162
  /**
3036
3163
  * Custom hook that returns the styles for the BadgeTile component.
3037
3164
  * Applies responsive styling based on the current device.
@@ -3095,7 +3222,7 @@ var BadgeTileDateEarned = function () {
3095
3222
  var theme = useWllSdk().theme;
3096
3223
  if (!isContextValid(tileContext))
3097
3224
  return null;
3098
- var _a = tileContext.configuration, count = _a.count, awardedDatePrefix = _a.awardedDatePrefix, createdAt = _a.createdAt, badgeNotEarnedMessage = _a.badgeNotEarnedMessage, type = _a.type;
3225
+ var _a = tileContext.configuration, count = _a.count, awardedDatePrefix = _a.awardedDatePrefix, lastEarnedAt = _a.lastEarnedAt, badgeNotEarnedMessage = _a.badgeNotEarnedMessage, type = _a.type, locale = _a.locale;
3099
3226
  // Don't show for Latest type with count=0
3100
3227
  if (type === exports.BadgeTileType.Latest && count === 0) {
3101
3228
  return null;
@@ -3111,10 +3238,10 @@ var BadgeTileDateEarned = function () {
3111
3238
  var textColor = getReadableTextColor(backgroundColor);
3112
3239
  var displayText = count === 0
3113
3240
  ? badgeNotEarnedMessage
3114
- : "".concat(awardedDatePrefix, " ").concat(new Date(createdAt).toLocaleDateString());
3241
+ : "".concat(awardedDatePrefix, " ").concat(handleLastEarnedDate(lastEarnedAt, locale));
3115
3242
  var accessibilityLabel = count === 0
3116
3243
  ? 'Badge not yet earned'
3117
- : "Badge earned on ".concat(new Date(createdAt).toLocaleDateString());
3244
+ : "Badge earned on ".concat(handleLastEarnedDate(lastEarnedAt, locale));
3118
3245
  return (jsxRuntimeExports.jsx(reactNative.View, { style: containerStyle, accessible: true, accessibilityLabel: accessibilityLabel, testID: "badge-tile-date-earned", children: jsxRuntimeExports.jsx(Text, { variant: "label", style: [styles.dateEarnedText, { color: textColor }], numberOfLines: 1, ellipsizeMode: "tail", accessibilityElementsHidden: true, importantForAccessibility: "no-hide-descendants", children: displayText }) }));
3119
3246
  };
3120
3247
 
@@ -3296,7 +3423,7 @@ var BannerTileDescription = function () {
3296
3423
  var description = bannerContext.configuration.description;
3297
3424
  if (!description)
3298
3425
  return null;
3299
- return (jsxRuntimeExports.jsx(Text, { style: styles.description, accessibilityRole: "text", accessibilityLabel: description, testID: "banner-tile-description", children: description }));
3426
+ return (jsxRuntimeExports.jsx(Text, { style: styles.description, role: "article", accessibilityLabel: description, testID: "banner-tile-description", children: description }));
3300
3427
  };
3301
3428
 
3302
3429
  /**
@@ -3316,7 +3443,7 @@ var BannerTileMedia = function (_a) {
3316
3443
  var containerStyle = {
3317
3444
  width: isArtworkOnly ? '100%' : '30%',
3318
3445
  };
3319
- return (jsxRuntimeExports.jsx(reactNative.View, { style: [styles.mediaContainer, containerStyle], accessibilityRole: "image", accessibilityLabel: "Banner image".concat(title ? " for ".concat(title) : ''), testID: "banner-tile-media", children: jsxRuntimeExports.jsx(ProgressiveImage, { source: { uri: artworkUrl }, style: styles.media, alt: "Banner image".concat(title ? " for ".concat(title) : '') }) }));
3446
+ return (jsxRuntimeExports.jsx(reactNative.View, { style: [styles.mediaContainer, containerStyle], role: "img", accessibilityLabel: "Banner image".concat(title ? " for ".concat(title) : ''), testID: "banner-tile-media", children: jsxRuntimeExports.jsx(ProgressiveImage, { source: { uri: artworkUrl }, style: styles.media, alt: "Banner image".concat(title ? " for ".concat(title) : '') }) }));
3320
3447
  };
3321
3448
 
3322
3449
  /**
@@ -3332,7 +3459,7 @@ var BannerTileTitle = function () {
3332
3459
  var title = bannerContext.configuration.title;
3333
3460
  if (!title)
3334
3461
  return null;
3335
- return (jsxRuntimeExports.jsx(Text, { variant: "title", testID: "banner-tile-title", style: styles.title, accessibilityRole: "header", accessibilityLabel: title, children: title }));
3462
+ return (jsxRuntimeExports.jsx(Text, { variant: "title", testID: "banner-tile-title", style: styles.title, role: "heading", accessibilityLabel: title, children: title }));
3336
3463
  };
3337
3464
 
3338
3465
  /**
@@ -3438,7 +3565,7 @@ var ContentTileMedia = function (_a) {
3438
3565
  var containerStyle = {
3439
3566
  flexBasis: isArtworkOnly ? '100%' : '50%',
3440
3567
  };
3441
- return (jsxRuntimeExports.jsx(reactNative.View, { style: [styles.imageContainer, containerStyle], testID: "content-tile-media", accessibilityRole: "image", accessibilityLabel: "Image for ".concat(title), children: jsxRuntimeExports.jsx(ProgressiveImage, { source: { uri: artworkUrl }, style: styles.image, alt: "Image for ".concat(title) }) }));
3568
+ return (jsxRuntimeExports.jsx(reactNative.View, { style: [styles.imageContainer, containerStyle], testID: "content-tile-media", role: "img", accessibilityLabel: "Image for ".concat(title), children: jsxRuntimeExports.jsx(ProgressiveImage, { source: { uri: artworkUrl }, style: styles.image, alt: "Image for ".concat(title) }) }));
3442
3569
  };
3443
3570
 
3444
3571
  var ContentTileSummary = function () {
@@ -3455,7 +3582,7 @@ var ContentTileSummary = function () {
3455
3582
  var getNumberOfLines = function () {
3456
3583
  return isFullSize ? 3 : isHalfSize ? 4 : 3;
3457
3584
  };
3458
- return (jsxRuntimeExports.jsx(Text, { variant: "body", accessibilityRole: "text", accessibilityLabel: body, numberOfLines: getNumberOfLines(), testID: "content-tile-summary", children: body }));
3585
+ return (jsxRuntimeExports.jsx(Text, { variant: "body", role: "article", accessibilityLabel: body, numberOfLines: getNumberOfLines(), testID: "content-tile-summary", children: body }));
3459
3586
  };
3460
3587
 
3461
3588
  var ContentTileTitle = function () {
@@ -3471,7 +3598,7 @@ var ContentTileTitle = function () {
3471
3598
  return styles.titleWithLink;
3472
3599
  }
3473
3600
  };
3474
- return (jsxRuntimeExports.jsx(Text, { variant: "title", accessibilityRole: "header", accessibilityLabel: title, numberOfLines: 1, style: handleTitleWidth(), testID: "content-tile-title", children: title }));
3601
+ return (jsxRuntimeExports.jsx(Text, { variant: "title", role: "heading", accessibilityLabel: title, numberOfLines: 1, style: handleTitleWidth(), testID: "content-tile-title", children: title }));
3475
3602
  };
3476
3603
 
3477
3604
  /**
@@ -3513,22 +3640,6 @@ var ContentTile = Object.assign(ContentTileRoot, {
3513
3640
  });
3514
3641
  var ContentTile$1 = withTileFetching(ContentTile);
3515
3642
 
3516
- /**
3517
- * Sorts tiles by priority (higher priority first) and maintains original order for equal priorities
3518
- * @param tiles Array of tiles to sort
3519
- * @returns Sorted array of tiles
3520
- */
3521
- var sortByPriority = function (tiles) {
3522
- return __spreadArray([], tiles, true).sort(function (a, b) {
3523
- // Sort by priority (higher priority first)
3524
- if (a.priority !== b.priority) {
3525
- return b.priority - a.priority;
3526
- }
3527
- // If priorities are equal, maintain original order
3528
- return tiles.indexOf(a) - tiles.indexOf(b);
3529
- });
3530
- };
3531
-
3532
3643
  exports.SectionType = void 0;
3533
3644
  (function (SectionType) {
3534
3645
  SectionType["Grid"] = "GRID";
@@ -4003,7 +4114,7 @@ var useSectionData = function (section, sectionId) {
4003
4114
  */
4004
4115
  var EmptyState = function (_a) {
4005
4116
  var message = _a.message;
4006
- return (jsxRuntimeExports.jsx(reactNative.View, { style: commonStyles.emptyContainer, accessibilityRole: "text", accessibilityLabel: "Empty state: ".concat(message), children: jsxRuntimeExports.jsx(reactNative.Text, { children: message }) }));
4117
+ return (jsxRuntimeExports.jsx(reactNative.View, { style: commonStyles.emptyContainer, role: "article", accessibilityLabel: "Empty state: ".concat(message), children: jsxRuntimeExports.jsx(reactNative.Text, { children: message }) }));
4007
4118
  };
4008
4119
  /**
4009
4120
  * The Section component renders a section based on its type (e.g., Banner, Grid).
@@ -4072,6 +4183,14 @@ var useGroupContext = function () {
4072
4183
  /**
4073
4184
  * Custom hook to fetch and manage group data
4074
4185
  *
4186
+ * This hook handles two distinct data fetching scenarios:
4187
+ * 1. Initial fetch: Shows loading state while first loading data
4188
+ * 2. Background refresh: Updates data silently without loading states
4189
+ *
4190
+ * The hook subscribes to GROUP_DATA_CHANGED events to refresh data
4191
+ * when notified by the host application, ensuring UI remains responsive
4192
+ * without showing loading indicators during refreshes.
4193
+ *
4075
4194
  * @param {string} id - The ID of the group to fetch
4076
4195
  * @returns {Object} Object containing group data, loading state, and any error
4077
4196
  */
@@ -4080,60 +4199,86 @@ var useGroupData = function (id) {
4080
4199
  var _a = React.useState(null), groupData = _a[0], setGroupData = _a[1];
4081
4200
  var _b = React.useState(null), error = _b[0], setError = _b[1];
4082
4201
  var _c = React.useState(true), isLoading = _c[0], setIsLoading = _c[1];
4083
- var fetchGroup = React.useCallback(function () {
4084
- var args_1 = [];
4085
- for (var _i = 0; _i < arguments.length; _i++) {
4086
- args_1[_i] = arguments[_i];
4087
- }
4088
- return __awaiter(void 0, __spreadArray([], args_1, true), void 0, function (showLoading) {
4089
- var response, err_1;
4090
- if (showLoading === void 0) { showLoading = true; }
4091
- return __generator(this, function (_a) {
4092
- switch (_a.label) {
4093
- case 0:
4094
- if (!id || !sdk || !sdk.getGroupByID) {
4095
- setError('Unable to fetch group data: invalid configuration');
4096
- setIsLoading(false);
4097
- return [2 /*return*/];
4098
- }
4099
- if (showLoading) {
4100
- setIsLoading(true);
4101
- }
4102
- setError(null);
4103
- _a.label = 1;
4104
- case 1:
4105
- _a.trys.push([1, 3, 4, 5]);
4106
- return [4 /*yield*/, sdk.refreshGroup(id)];
4107
- case 2:
4108
- response = _a.sent();
4109
- if (response && response.status === 'success' && response.data) {
4110
- setGroupData(response.data);
4111
- }
4112
- else {
4113
- setError((response && response.error) || 'Failed to fetch group data.');
4114
- }
4115
- return [3 /*break*/, 5];
4116
- case 3:
4117
- err_1 = _a.sent();
4118
- setError('Failed to fetch group data. Please try again later.');
4119
- console.error('Error fetching group:', err_1);
4120
- return [3 /*break*/, 5];
4121
- case 4:
4122
- if (showLoading) {
4123
- setIsLoading(false);
4124
- }
4125
- return [7 /*endfinally*/];
4126
- case 5: return [2 /*return*/];
4127
- }
4128
- });
4202
+ var _d = React.useState(false), isInitialFetchDone = _d[0], setIsInitialFetchDone = _d[1];
4203
+ var initialFetch = React.useCallback(function () { return __awaiter(void 0, void 0, void 0, function () {
4204
+ var response, err_1;
4205
+ return __generator(this, function (_a) {
4206
+ switch (_a.label) {
4207
+ case 0:
4208
+ if (!id || !sdk || !sdk.getGroupByID) {
4209
+ setError('Unable to fetch group data: invalid configuration');
4210
+ setIsLoading(false);
4211
+ setIsInitialFetchDone(true);
4212
+ return [2 /*return*/];
4213
+ }
4214
+ setIsLoading(true);
4215
+ setError(null);
4216
+ _a.label = 1;
4217
+ case 1:
4218
+ _a.trys.push([1, 3, 4, 5]);
4219
+ return [4 /*yield*/, sdk.refreshGroup(id)];
4220
+ case 2:
4221
+ response = _a.sent();
4222
+ if (response && response.status === 'success' && response.data) {
4223
+ setGroupData(response.data);
4224
+ }
4225
+ else {
4226
+ setError((response && response.error) || 'Failed to fetch group data.');
4227
+ }
4228
+ return [3 /*break*/, 5];
4229
+ case 3:
4230
+ err_1 = _a.sent();
4231
+ setError('Failed to fetch group data. Please try again later.');
4232
+ console.error('Error fetching group:', err_1);
4233
+ return [3 /*break*/, 5];
4234
+ case 4:
4235
+ setIsLoading(false);
4236
+ setIsInitialFetchDone(true);
4237
+ return [7 /*endfinally*/];
4238
+ case 5: return [2 /*return*/];
4239
+ }
4129
4240
  });
4130
- }, [id, sdk]);
4241
+ }); }, [id, sdk]);
4242
+ var silentRefresh = React.useCallback(function () { return __awaiter(void 0, void 0, void 0, function () {
4243
+ var response, err_2;
4244
+ return __generator(this, function (_a) {
4245
+ switch (_a.label) {
4246
+ case 0:
4247
+ if (!id || !sdk || !sdk.getGroupByID || !isInitialFetchDone) {
4248
+ return [2 /*return*/];
4249
+ }
4250
+ _a.label = 1;
4251
+ case 1:
4252
+ _a.trys.push([1, 3, , 4]);
4253
+ return [4 /*yield*/, sdk.refreshGroup(id)];
4254
+ case 2:
4255
+ response = _a.sent();
4256
+ if (response && response.status === 'success' && response.data) {
4257
+ setGroupData(response.data);
4258
+ }
4259
+ return [3 /*break*/, 4];
4260
+ case 3:
4261
+ err_2 = _a.sent();
4262
+ console.error('Error during silent refresh:', err_2);
4263
+ return [3 /*break*/, 4];
4264
+ case 4: return [2 /*return*/];
4265
+ }
4266
+ });
4267
+ }); }, [id, sdk, isInitialFetchDone]);
4131
4268
  var refreshGroup = React.useCallback(function () {
4132
- return fetchGroup(false);
4133
- }, [fetchGroup]);
4269
+ return silentRefresh();
4270
+ }, [silentRefresh]);
4134
4271
  React.useEffect(function () {
4135
- fetchGroup(true);
4136
- }, [fetchGroup]);
4272
+ if (sdk) {
4273
+ initialFetch();
4274
+ var unsubscribeGroup_1 = sdk.subscribeToDataChange('GROUP_DATA_CHANGED', function () {
4275
+ silentRefresh();
4276
+ });
4277
+ return function () {
4278
+ unsubscribeGroup_1();
4279
+ };
4280
+ }
4281
+ }, [initialFetch, id, sdk, silentRefresh]);
4137
4282
  return { groupData: groupData, isLoading: isLoading, error: error, refreshGroup: refreshGroup };
4138
4283
  };
4139
4284
  /**
@@ -4191,7 +4336,7 @@ var Group = function (_a) {
4191
4336
  if (error || !groupData) {
4192
4337
  return jsxRuntimeExports.jsx(GroupEmptyState, { message: error || 'No group data available' });
4193
4338
  }
4194
- return (jsxRuntimeExports.jsx(GroupContext.Provider, { value: { groupData: groupData }, children: jsxRuntimeExports.jsx(reactNative.View, { "data-testid": "group-container", children: jsxRuntimeExports.jsx(GroupSections, {}) }) }));
4339
+ return (jsxRuntimeExports.jsx(GroupContext.Provider, { value: { groupData: groupData }, children: jsxRuntimeExports.jsx(reactNative.View, { testID: "group-container", children: jsxRuntimeExports.jsx(GroupSections, {}) }) }));
4195
4340
  };
4196
4341
 
4197
4342
  /**
@@ -4404,7 +4549,7 @@ var PointsTileFormattedPoints = function () {
4404
4549
  return null;
4405
4550
  var calculatedPoints = applyMultiplier(points, pointsMultiplier);
4406
4551
  var fullPointsText = "".concat(pointsPrefix).concat(calculatedPoints, " ").concat(pointsSuffix).trim();
4407
- return (jsxRuntimeExports.jsx(reactNative.View, { testID: "points-tile-points", accessibilityRole: "text", accessibilityLabel: "Points value: ".concat(fullPointsText), children: jsxRuntimeExports.jsxs(Row, { align: "center", justify: "start", children: [pointsPrefix ? (jsxRuntimeExports.jsx(Text, { variant: "caption", testID: "points-tile-prefix", children: pointsPrefix })) : null, jsxRuntimeExports.jsx(Text, { variant: "caption", testID: "points-tile-value", children: calculatedPoints }), pointsSuffix ? (jsxRuntimeExports.jsx(Text, { variant: "caption", style: styles.suffix, testID: "points-tile-suffix", children: pointsSuffix })) : null] }) }));
4552
+ return (jsxRuntimeExports.jsx(reactNative.View, { testID: "points-tile-points", role: "article", accessibilityLabel: "Points value: ".concat(fullPointsText), children: jsxRuntimeExports.jsxs(Row, { align: "center", justify: "start", children: [pointsPrefix ? (jsxRuntimeExports.jsx(Text, { variant: "caption", testID: "points-tile-prefix", children: pointsPrefix })) : null, jsxRuntimeExports.jsx(Text, { variant: "caption", testID: "points-tile-value", children: calculatedPoints }), pointsSuffix ? (jsxRuntimeExports.jsx(Text, { variant: "caption", style: styles.suffix, testID: "points-tile-suffix", children: pointsSuffix })) : null] }) }));
4408
4553
  };
4409
4554
 
4410
4555
  /**
@@ -4421,7 +4566,7 @@ var PointsTileMedia = function (_a) {
4421
4566
  var styles = usePointsTileStyles(isFullSize);
4422
4567
  if (!artworkUrl)
4423
4568
  return null;
4424
- return (jsxRuntimeExports.jsx(reactNative.View, { testID: "points-tile-media", style: styles.imageContainer, accessibilityRole: "image", accessibilityLabel: "Points tile image for ".concat(title), children: jsxRuntimeExports.jsx(reactNative.Image, { source: { uri: artworkUrl }, style: styles.image, resizeMode: isFullSize ? 'cover' : 'contain' }) }));
4569
+ return (jsxRuntimeExports.jsx(reactNative.View, { testID: "points-tile-media", style: styles.imageContainer, role: "img", accessibilityLabel: "Points tile image for ".concat(title), children: jsxRuntimeExports.jsx(reactNative.Image, { source: { uri: artworkUrl }, style: styles.image, resizeMode: isFullSize ? 'cover' : 'contain' }) }));
4425
4570
  };
4426
4571
 
4427
4572
  /**
@@ -4436,7 +4581,7 @@ var PointsTileTitle = function () {
4436
4581
  var title = tileContext.configuration.title;
4437
4582
  if (!title)
4438
4583
  return null;
4439
- return (jsxRuntimeExports.jsx(Text, { variant: "eyebrow", testID: "points-tile-title", accessibilityRole: "header", accessibilityLabel: title, children: title }));
4584
+ return (jsxRuntimeExports.jsx(Text, { variant: "eyebrow", testID: "points-tile-title", role: "heading", accessibilityLabel: title, children: title }));
4440
4585
  };
4441
4586
 
4442
4587
  /**
@@ -4515,7 +4660,7 @@ var RewardCategoryHeader = function () {
4515
4660
  var _a = tileContext.configuration, _b = _a.showName, showName = _b === void 0 ? true : _b, _c = _a.name, name = _c === void 0 ? '' : _c;
4516
4661
  if (!showName || !name)
4517
4662
  return null;
4518
- return (jsxRuntimeExports.jsx(reactNative.View, { style: [styles.header, { backgroundColor: theme.primary }], testID: "reward-category-header", accessibilityRole: "header", accessibilityLabel: "Reward category: ".concat(name), children: jsxRuntimeExports.jsx(Text, { style: [styles.headerText, { color: theme.primaryText }], ellipsizeMode: "tail", numberOfLines: 1, children: name }) }));
4663
+ return (jsxRuntimeExports.jsx(reactNative.View, { style: [styles.header, { backgroundColor: theme.primary }], testID: "reward-category-header", role: "heading", accessibilityLabel: "Reward category: ".concat(name), children: jsxRuntimeExports.jsx(Text, { style: [styles.headerText, { color: theme.primaryText }], ellipsizeMode: "tail", numberOfLines: 1, children: name }) }));
4519
4664
  };
4520
4665
 
4521
4666
  /**
@@ -4531,7 +4676,7 @@ var RewardCategoryMedia = function () {
4531
4676
  var _a = tileContext.configuration, artworkUrl = _a.artworkUrl, _b = _a.name, name = _b === void 0 ? 'Reward' : _b;
4532
4677
  if (!artworkUrl)
4533
4678
  return null;
4534
- return (jsxRuntimeExports.jsx(ProgressiveImage, { testID: "reward-category-media", source: { uri: artworkUrl }, style: styles.background, alt: "Reward category image for ".concat(name), accessibilityRole: "image" }));
4679
+ return (jsxRuntimeExports.jsx(ProgressiveImage, { testID: "reward-category-media", source: { uri: artworkUrl }, style: styles.background, alt: "Reward category image for ".concat(name), role: "img" }));
4535
4680
  };
4536
4681
 
4537
4682
  /**
@@ -4564,7 +4709,7 @@ var RewardCategoryTile$1 = withTileFetching(RewardCategoryTile);
4564
4709
  var RewardTileChevron = function () {
4565
4710
  var _a;
4566
4711
  var theme = useWllSdk().theme;
4567
- return (jsxRuntimeExports.jsx(Icon, { name: "ChevronRight", size: IS_MOBILE ? 16 : undefined, color: ((_a = theme === null || theme === void 0 ? void 0 : theme.derivedSurfaceText) === null || _a === void 0 ? void 0 : _a[20]) || '#000000', accessibilityRole: "image", accessibilityLabel: "View reward details" }));
4712
+ return (jsxRuntimeExports.jsx(Icon, { name: "ChevronRight", size: IS_MOBILE ? 16 : undefined, color: ((_a = theme === null || theme === void 0 ? void 0 : theme.derivedSurfaceText) === null || _a === void 0 ? void 0 : _a[20]) || '#000000', role: "img", accessibilityLabel: "View reward details" }));
4568
4713
  };
4569
4714
 
4570
4715
  /**
@@ -4638,7 +4783,7 @@ var RewardTileMedia = function (_a) {
4638
4783
  var containerStyle = {
4639
4784
  flexBasis: isArtworkOnly ? '100%' : '50%',
4640
4785
  };
4641
- return (jsxRuntimeExports.jsx(reactNative.View, { style: [styles.imageContainer, containerStyle], testID: "reward-tile-media", accessibilityRole: "image", accessibilityLabel: "Reward image for ".concat(name), children: jsxRuntimeExports.jsx(ProgressiveImage, { source: { uri: artworkUrl }, style: styles.image, alt: "Reward image for ".concat(name) }) }));
4786
+ return (jsxRuntimeExports.jsx(reactNative.View, { style: [styles.imageContainer, containerStyle], testID: "reward-tile-media", role: "img", accessibilityLabel: "Reward image for ".concat(name), children: jsxRuntimeExports.jsx(ProgressiveImage, { source: { uri: artworkUrl }, style: styles.image, alt: "Reward image for ".concat(name) }) }));
4642
4787
  };
4643
4788
 
4644
4789
  /**
@@ -4656,7 +4801,7 @@ var RewardTilePoints = function () {
4656
4801
  return null;
4657
4802
  var calculatedPoints = applyMultiplier(price, pointsMultiplier);
4658
4803
  var accessibilityLabel = getPointsLabel('Reward points:', calculatedPoints, pointsPrefix, pointsSuffix);
4659
- return (jsxRuntimeExports.jsx(reactNative.View, { testID: "reward-tile-points", accessibilityRole: "text", accessibilityLabel: accessibilityLabel, children: jsxRuntimeExports.jsxs(Row, { align: "center", justify: "start", style: { marginTop: 8 }, children: [pointsPrefix ? jsxRuntimeExports.jsx(Text, { variant: "caption", children: pointsPrefix }) : null, jsxRuntimeExports.jsx(Text, { variant: "caption", testID: "reward-tile-points-value", children: calculatedPoints }), pointsSuffix ? (jsxRuntimeExports.jsx(Text, { variant: "caption", style: styles.suffix, children: pointsSuffix })) : null] }) }));
4804
+ return (jsxRuntimeExports.jsx(reactNative.View, { testID: "reward-tile-points", role: "article", accessibilityLabel: accessibilityLabel, children: jsxRuntimeExports.jsxs(Row, { align: "center", justify: "start", style: { marginTop: 8 }, children: [pointsPrefix ? jsxRuntimeExports.jsx(Text, { variant: "caption", children: pointsPrefix }) : null, jsxRuntimeExports.jsx(Text, { variant: "caption", testID: "reward-tile-points-value", children: calculatedPoints }), pointsSuffix ? (jsxRuntimeExports.jsx(Text, { variant: "caption", style: styles.suffix, children: pointsSuffix })) : null] }) }));
4660
4805
  };
4661
4806
 
4662
4807
  /**
@@ -4671,7 +4816,7 @@ var RewardTileSummary = function () {
4671
4816
  var summary = tileContext.configuration.summary;
4672
4817
  if (!summary)
4673
4818
  return null;
4674
- return (jsxRuntimeExports.jsx(Text, { variant: "body", accessibilityRole: "text", accessibilityLabel: summary, testID: "reward-tile-summary", children: summary }));
4819
+ return (jsxRuntimeExports.jsx(Text, { variant: "body", role: "article", accessibilityLabel: summary, testID: "reward-tile-summary", children: summary }));
4675
4820
  };
4676
4821
 
4677
4822
  /**
@@ -4692,7 +4837,7 @@ var RewardTileTitle = function () {
4692
4837
  return styles.titleWithLink;
4693
4838
  }
4694
4839
  };
4695
- return (jsxRuntimeExports.jsx(Text, { variant: "title", ellipsizeMode: "tail", numberOfLines: 1, accessibilityRole: "header", accessibilityLabel: "Reward title: ".concat(name), testID: "reward-tile-title", style: handleTitleWidth(), children: name }));
4840
+ return (jsxRuntimeExports.jsx(Text, { variant: "title", ellipsizeMode: "tail", numberOfLines: 1, role: "heading", accessibilityLabel: "Reward title: ".concat(name), testID: "reward-tile-title", style: handleTitleWidth(), children: name }));
4696
4841
  };
4697
4842
 
4698
4843
  /**