@wlloyalty/wll-react-sdk 1.0.101 → 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.
- package/dist/index.d.ts +10 -1
- package/dist/native.js +182 -56
- package/dist/native.js.map +1 -1
- package/dist/types/components/molecules/Carousel/Carousel.stories.d.ts +3 -0
- package/dist/types/components/molecules/Carousel/index.d.ts +2 -1
- package/dist/types/context/WllSdkContext.d.ts +3 -0
- package/dist/types/unit-tests/eventEmitter.spec.d.ts +1 -0
- package/dist/types/utils/eventEmitter.d.ts +44 -0
- package/dist/web.js +165 -29
- package/dist/web.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -526,8 +526,9 @@ type TSection = {
|
|
|
526
526
|
|
|
527
527
|
type CarouselProps = {
|
|
528
528
|
section?: TSection;
|
|
529
|
+
autoRotateInterval?: number;
|
|
529
530
|
};
|
|
530
|
-
declare const Carousel: ({ section }: CarouselProps) => JSX.Element | null;
|
|
531
|
+
declare const Carousel: ({ section, autoRotateInterval, }: CarouselProps) => JSX.Element | null;
|
|
531
532
|
|
|
532
533
|
type CarouselNavButtonProps = {
|
|
533
534
|
direction: 'left' | 'right';
|
|
@@ -660,6 +661,12 @@ type NavigationConfig = {
|
|
|
660
661
|
baseUrl?: string;
|
|
661
662
|
};
|
|
662
663
|
|
|
664
|
+
/**
|
|
665
|
+
* Supported event types for the SDK event system
|
|
666
|
+
* @typedef {string} EventTypes
|
|
667
|
+
*/
|
|
668
|
+
type EventTypes = 'GROUP_DATA_CHANGED' | 'SECTION_DATA_CHANGED' | 'TILE_DATA_CHANGED' | string;
|
|
669
|
+
|
|
663
670
|
type Fetcher = <T>(endpoint: string, options?: RequestInit) => Promise<APIResponse<T>>;
|
|
664
671
|
type SDKConfig = {
|
|
665
672
|
apiKey: string;
|
|
@@ -678,6 +685,8 @@ type WllSdkContextType = ThemeContextType & {
|
|
|
678
685
|
getTileByID: (id: string) => Promise<APIResponse<Tile>>;
|
|
679
686
|
handleNavigation: (link: string, target: CTALinkTarget) => Promise<void>;
|
|
680
687
|
refreshGroup: (id: string) => Promise<APIResponse<TGroup>>;
|
|
688
|
+
notifyDataChange: (eventType: EventTypes, data?: any) => void;
|
|
689
|
+
subscribeToDataChange: (eventType: EventTypes, callback: (data?: any) => void) => () => void;
|
|
681
690
|
} & Readonly<{
|
|
682
691
|
readonly config: SDKConfig;
|
|
683
692
|
}>;
|
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 }) }));
|
|
@@ -3670,7 +3740,7 @@ var carouselReducer = function (state, action) {
|
|
|
3670
3740
|
}
|
|
3671
3741
|
};
|
|
3672
3742
|
var Carousel = function (_a) {
|
|
3673
|
-
var section = _a.section;
|
|
3743
|
+
var section = _a.section, _b = _a.autoRotateInterval, autoRotateInterval = _b === void 0 ? 5000 : _b;
|
|
3674
3744
|
if (!section)
|
|
3675
3745
|
return null;
|
|
3676
3746
|
var WINDOW_WIDTH = reactNative.useWindowDimensions().width;
|
|
@@ -3678,9 +3748,9 @@ var Carousel = function (_a) {
|
|
|
3678
3748
|
var styles = useCarouselStyles(BUTTON_SIZE);
|
|
3679
3749
|
var animatedIndex = React.useRef(new reactNative.Animated.Value(0)).current;
|
|
3680
3750
|
var theme = useWllSdk().theme;
|
|
3681
|
-
var
|
|
3751
|
+
var _c = useResponsive(), isDesktop = _c.isDesktop, isTablet = _c.isTablet;
|
|
3682
3752
|
var scrollViewRef = React.useRef(null);
|
|
3683
|
-
var
|
|
3753
|
+
var _d = React.useReducer(carouselReducer, __assign(__assign({}, initialState), { containerWidth: WINDOW_WIDTH })), state = _d[0], dispatch = _d[1];
|
|
3684
3754
|
var currentIndex = state.currentIndex, containerWidth = state.containerWidth;
|
|
3685
3755
|
var sortedTiles = sortByPriority(section.tiles.filter(function (tile) { return tile.type === exports.TileType.Banner; }));
|
|
3686
3756
|
var handleScroll = React.useCallback(function (event) {
|
|
@@ -3703,12 +3773,34 @@ var Carousel = function (_a) {
|
|
|
3703
3773
|
};
|
|
3704
3774
|
var handleNext = function () {
|
|
3705
3775
|
var _a;
|
|
3776
|
+
var nextIndex = Math.min(sortedTiles.length - 1, currentIndex + 1);
|
|
3706
3777
|
dispatch({ type: 'NEXT_SLIDE', maxIndex: sortedTiles.length - 1 });
|
|
3707
3778
|
(_a = scrollViewRef.current) === null || _a === void 0 ? void 0 : _a.scrollTo({
|
|
3708
|
-
x:
|
|
3779
|
+
x: nextIndex * containerWidth,
|
|
3709
3780
|
animated: true,
|
|
3710
3781
|
});
|
|
3711
3782
|
};
|
|
3783
|
+
var rotateToNextSlide = React.useCallback(function () {
|
|
3784
|
+
var _a;
|
|
3785
|
+
if (currentIndex >= sortedTiles.length - 1) {
|
|
3786
|
+
dispatch({ type: 'SET_CURRENT_INDEX', payload: 0 });
|
|
3787
|
+
(_a = scrollViewRef.current) === null || _a === void 0 ? void 0 : _a.scrollTo({
|
|
3788
|
+
x: 0,
|
|
3789
|
+
animated: true,
|
|
3790
|
+
});
|
|
3791
|
+
}
|
|
3792
|
+
else {
|
|
3793
|
+
handleNext();
|
|
3794
|
+
}
|
|
3795
|
+
}, [currentIndex, containerWidth, sortedTiles.length]);
|
|
3796
|
+
React.useEffect(function () {
|
|
3797
|
+
if (sortedTiles.length <= 1)
|
|
3798
|
+
return;
|
|
3799
|
+
var rotationTimer = setInterval(function () {
|
|
3800
|
+
rotateToNextSlide();
|
|
3801
|
+
}, autoRotateInterval);
|
|
3802
|
+
return function () { return clearInterval(rotationTimer); };
|
|
3803
|
+
}, [rotateToNextSlide, autoRotateInterval, sortedTiles.length]);
|
|
3712
3804
|
var displayControls = sortedTiles.length > 1;
|
|
3713
3805
|
var showPrevButton = displayControls && currentIndex > 0;
|
|
3714
3806
|
var showNextButton = displayControls && currentIndex < sortedTiles.length - 1;
|
|
@@ -4050,6 +4142,14 @@ var useGroupContext = function () {
|
|
|
4050
4142
|
/**
|
|
4051
4143
|
* Custom hook to fetch and manage group data
|
|
4052
4144
|
*
|
|
4145
|
+
* This hook handles two distinct data fetching scenarios:
|
|
4146
|
+
* 1. Initial fetch: Shows loading state while first loading data
|
|
4147
|
+
* 2. Background refresh: Updates data silently without loading states
|
|
4148
|
+
*
|
|
4149
|
+
* The hook subscribes to GROUP_DATA_CHANGED events to refresh data
|
|
4150
|
+
* when notified by the host application, ensuring UI remains responsive
|
|
4151
|
+
* without showing loading indicators during refreshes.
|
|
4152
|
+
*
|
|
4053
4153
|
* @param {string} id - The ID of the group to fetch
|
|
4054
4154
|
* @returns {Object} Object containing group data, loading state, and any error
|
|
4055
4155
|
*/
|
|
@@ -4058,60 +4158,86 @@ var useGroupData = function (id) {
|
|
|
4058
4158
|
var _a = React.useState(null), groupData = _a[0], setGroupData = _a[1];
|
|
4059
4159
|
var _b = React.useState(null), error = _b[0], setError = _b[1];
|
|
4060
4160
|
var _c = React.useState(true), isLoading = _c[0], setIsLoading = _c[1];
|
|
4061
|
-
var
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
case 4:
|
|
4100
|
-
if (showLoading) {
|
|
4101
|
-
setIsLoading(false);
|
|
4102
|
-
}
|
|
4103
|
-
return [7 /*endfinally*/];
|
|
4104
|
-
case 5: return [2 /*return*/];
|
|
4105
|
-
}
|
|
4106
|
-
});
|
|
4161
|
+
var _d = React.useState(false), isInitialFetchDone = _d[0], setIsInitialFetchDone = _d[1];
|
|
4162
|
+
var initialFetch = React.useCallback(function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
4163
|
+
var response, err_1;
|
|
4164
|
+
return __generator(this, function (_a) {
|
|
4165
|
+
switch (_a.label) {
|
|
4166
|
+
case 0:
|
|
4167
|
+
if (!id || !sdk || !sdk.getGroupByID) {
|
|
4168
|
+
setError('Unable to fetch group data: invalid configuration');
|
|
4169
|
+
setIsLoading(false);
|
|
4170
|
+
setIsInitialFetchDone(true);
|
|
4171
|
+
return [2 /*return*/];
|
|
4172
|
+
}
|
|
4173
|
+
setIsLoading(true);
|
|
4174
|
+
setError(null);
|
|
4175
|
+
_a.label = 1;
|
|
4176
|
+
case 1:
|
|
4177
|
+
_a.trys.push([1, 3, 4, 5]);
|
|
4178
|
+
return [4 /*yield*/, sdk.refreshGroup(id)];
|
|
4179
|
+
case 2:
|
|
4180
|
+
response = _a.sent();
|
|
4181
|
+
if (response && response.status === 'success' && response.data) {
|
|
4182
|
+
setGroupData(response.data);
|
|
4183
|
+
}
|
|
4184
|
+
else {
|
|
4185
|
+
setError((response && response.error) || 'Failed to fetch group data.');
|
|
4186
|
+
}
|
|
4187
|
+
return [3 /*break*/, 5];
|
|
4188
|
+
case 3:
|
|
4189
|
+
err_1 = _a.sent();
|
|
4190
|
+
setError('Failed to fetch group data. Please try again later.');
|
|
4191
|
+
console.error('Error fetching group:', err_1);
|
|
4192
|
+
return [3 /*break*/, 5];
|
|
4193
|
+
case 4:
|
|
4194
|
+
setIsLoading(false);
|
|
4195
|
+
setIsInitialFetchDone(true);
|
|
4196
|
+
return [7 /*endfinally*/];
|
|
4197
|
+
case 5: return [2 /*return*/];
|
|
4198
|
+
}
|
|
4107
4199
|
});
|
|
4108
|
-
}, [id, sdk]);
|
|
4200
|
+
}); }, [id, sdk]);
|
|
4201
|
+
var silentRefresh = React.useCallback(function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
4202
|
+
var response, err_2;
|
|
4203
|
+
return __generator(this, function (_a) {
|
|
4204
|
+
switch (_a.label) {
|
|
4205
|
+
case 0:
|
|
4206
|
+
if (!id || !sdk || !sdk.getGroupByID || !isInitialFetchDone) {
|
|
4207
|
+
return [2 /*return*/];
|
|
4208
|
+
}
|
|
4209
|
+
_a.label = 1;
|
|
4210
|
+
case 1:
|
|
4211
|
+
_a.trys.push([1, 3, , 4]);
|
|
4212
|
+
return [4 /*yield*/, sdk.refreshGroup(id)];
|
|
4213
|
+
case 2:
|
|
4214
|
+
response = _a.sent();
|
|
4215
|
+
if (response && response.status === 'success' && response.data) {
|
|
4216
|
+
setGroupData(response.data);
|
|
4217
|
+
}
|
|
4218
|
+
return [3 /*break*/, 4];
|
|
4219
|
+
case 3:
|
|
4220
|
+
err_2 = _a.sent();
|
|
4221
|
+
console.error('Error during silent refresh:', err_2);
|
|
4222
|
+
return [3 /*break*/, 4];
|
|
4223
|
+
case 4: return [2 /*return*/];
|
|
4224
|
+
}
|
|
4225
|
+
});
|
|
4226
|
+
}); }, [id, sdk, isInitialFetchDone]);
|
|
4109
4227
|
var refreshGroup = React.useCallback(function () {
|
|
4110
|
-
return
|
|
4111
|
-
}, [
|
|
4228
|
+
return silentRefresh();
|
|
4229
|
+
}, [silentRefresh]);
|
|
4112
4230
|
React.useEffect(function () {
|
|
4113
|
-
|
|
4114
|
-
|
|
4231
|
+
if (sdk) {
|
|
4232
|
+
initialFetch();
|
|
4233
|
+
var unsubscribeGroup_1 = sdk.subscribeToDataChange('GROUP_DATA_CHANGED', function () {
|
|
4234
|
+
silentRefresh();
|
|
4235
|
+
});
|
|
4236
|
+
return function () {
|
|
4237
|
+
unsubscribeGroup_1();
|
|
4238
|
+
};
|
|
4239
|
+
}
|
|
4240
|
+
}, [initialFetch, id, sdk, silentRefresh]);
|
|
4115
4241
|
return { groupData: groupData, isLoading: isLoading, error: error, refreshGroup: refreshGroup };
|
|
4116
4242
|
};
|
|
4117
4243
|
/**
|
|
@@ -4169,7 +4295,7 @@ var Group = function (_a) {
|
|
|
4169
4295
|
if (error || !groupData) {
|
|
4170
4296
|
return jsxRuntimeExports.jsx(GroupEmptyState, { message: error || 'No group data available' });
|
|
4171
4297
|
}
|
|
4172
|
-
return (jsxRuntimeExports.jsx(GroupContext.Provider, { value: { groupData: groupData }, children: jsxRuntimeExports.jsx(reactNative.View, {
|
|
4298
|
+
return (jsxRuntimeExports.jsx(GroupContext.Provider, { value: { groupData: groupData }, children: jsxRuntimeExports.jsx(reactNative.View, { testID: "group-container", children: jsxRuntimeExports.jsx(GroupSections, {}) }) }));
|
|
4173
4299
|
};
|
|
4174
4300
|
|
|
4175
4301
|
/**
|