@applicaster/zapp-react-native-utils 13.0.0-rc.14 → 13.0.0-rc.141

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 (185) hide show
  1. package/README.md +0 -10
  2. package/actionsExecutor/ActionExecutor.ts +16 -9
  3. package/actionsExecutor/ActionExecutorContext.tsx +214 -16
  4. package/actionsExecutor/consts.ts +4 -0
  5. package/alertUtils/alert.ts +148 -0
  6. package/alertUtils/index.ts +1 -148
  7. package/analyticsUtils/AnalyticPlayerListener.ts +18 -1
  8. package/analyticsUtils/__tests__/__snapshots__/analyticsManagerNoModule.test.js.snap +9 -9
  9. package/analyticsUtils/currentScreenProperities.ts +6 -4
  10. package/analyticsUtils/helpers/hooks.ts +1 -1
  11. package/appUtils/HooksManager/Hook.ts +6 -2
  12. package/appUtils/HooksManager/__tests__/__snapshots__/hook.test.js.snap +7 -7
  13. package/appUtils/HooksManager/__tests__/__snapshots__/hooksManager.test.js.snap +186 -186
  14. package/appUtils/HooksManager/index.ts +3 -1
  15. package/appUtils/HooksManager/types.ts +5 -2
  16. package/appUtils/__tests__/__snapshots__/localizationsHelper.test.ts.snap +151 -0
  17. package/appUtils/__tests__/allZappLocales.ts +79 -0
  18. package/appUtils/__tests__/{localizationsHelper.test.js → localizationsHelper.test.ts} +11 -0
  19. package/appUtils/accessibilityManager/const.ts +18 -0
  20. package/appUtils/accessibilityManager/index.ts +46 -2
  21. package/appUtils/contextKeysManager/contextResolver.ts +66 -0
  22. package/appUtils/contextKeysManager/index.ts +2 -2
  23. package/appUtils/contextKeysManager/utils/index.ts +2 -1
  24. package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +9 -6
  25. package/appUtils/focusManager/index.ios.ts +14 -4
  26. package/appUtils/focusManager/index.ts +108 -69
  27. package/appUtils/focusManager/treeDataStructure/Tree/index.js +23 -0
  28. package/appUtils/focusManager/utils/__tests__/findChild.test.ts +35 -0
  29. package/appUtils/focusManager/utils/enums.ts +4 -0
  30. package/appUtils/focusManager/utils/index.ts +5 -0
  31. package/appUtils/focusManagerAux/utils/index.ts +4 -3
  32. package/appUtils/keyCodes/__tests__/__snapshots__/keyCodes.test.js.snap +2 -2
  33. package/appUtils/keyCodes/__tests__/keyCodes.test.js +1 -1
  34. package/appUtils/keyCodes/index.ts +11 -7
  35. package/appUtils/keyCodes/keys/keysByPlatform.ts +4 -0
  36. package/appUtils/keyInputHandler/KeyInputHandler.ts +68 -0
  37. package/appUtils/localizationsHelper.ts +31 -0
  38. package/appUtils/orientationHelper.ts +11 -13
  39. package/appUtils/platform/const.ts +14 -0
  40. package/appUtils/platform/platformUtils.ts +47 -4
  41. package/appUtils/playerManager/index.ts +1 -1
  42. package/appUtils/playerManager/player.ts +42 -18
  43. package/appUtils/playerManager/playerHooks/usePlayerCurrentTime.tsx +11 -7
  44. package/appUtils/playerManager/playerNative.ts +18 -2
  45. package/appUtils/playerManager/usePlayerControllerSetup.tsx +3 -3
  46. package/appUtils/playerManager/usePlayerTitleSummaryOverlay.tsx +7 -1
  47. package/arrayUtils/__tests__/__snapshots__/arrayUtils.test.ts.snap +4 -4
  48. package/arrayUtils/__tests__/isEmptyArray.test.ts +63 -0
  49. package/arrayUtils/__tests__/isFilledArray.test.ts +1 -1
  50. package/arrayUtils/index.ts +7 -2
  51. package/audioPlayerUtils/__tests__/getArtworkImage.test.ts +144 -0
  52. package/audioPlayerUtils/__tests__/getBackgroundImage.test.ts +72 -0
  53. package/audioPlayerUtils/__tests__/getImageFromEntry.test.ts +110 -0
  54. package/audioPlayerUtils/assets/index.ts +2 -0
  55. package/audioPlayerUtils/index.ts +242 -0
  56. package/cellUtils/index.ts +9 -5
  57. package/componentsUtils/__tests__/isFirstComponentGallery.test.ts +33 -0
  58. package/componentsUtils/__tests__/isFirstComponentScreenPicker.test.ts +33 -0
  59. package/componentsUtils/__tests__/isGallery.test.ts +33 -0
  60. package/componentsUtils/__tests__/isScreenPicker.test.ts +33 -0
  61. package/componentsUtils/index.ts +39 -0
  62. package/configurationUtils/__tests__/configurationUtils.test.js +0 -31
  63. package/configurationUtils/__tests__/getMediaItems.test.ts +65 -0
  64. package/configurationUtils/__tests__/imageSrcFromMediaItem.test.ts +34 -0
  65. package/configurationUtils/index.ts +63 -34
  66. package/dateUtils/index.ts +19 -0
  67. package/equalUtils/__tests__/isEqual/combination.test.ts +263 -0
  68. package/equalUtils/index.ts +49 -30
  69. package/focusManager/FocusManager.ts +14 -2
  70. package/focusManager/index.ts +23 -4
  71. package/functionUtils/__tests__/__snapshots__/functionUtils.test.js.snap +4 -4
  72. package/functionUtils/index.ts +46 -8
  73. package/idleUtils/__tests__/withTimeout$.test.ts +37 -0
  74. package/idleUtils/index.ts +1 -1
  75. package/idleUtils/withTimeout.ts +15 -2
  76. package/index.d.ts +0 -12
  77. package/localizationUtils/index.ts +8 -13
  78. package/logger/const.ts +9 -67
  79. package/manifestUtils/__tests__/createConfig.test.js +16 -16
  80. package/manifestUtils/defaultManifestConfigurations/generalContent.js +13 -0
  81. package/manifestUtils/defaultManifestConfigurations/player.js +9 -3
  82. package/manifestUtils/fonts/index.js +5 -6
  83. package/manifestUtils/index.js +2 -0
  84. package/manifestUtils/keys.js +27 -2
  85. package/manifestUtils/sharedConfiguration/screenPicker/__tests__/utils.test.js +304 -0
  86. package/manifestUtils/sharedConfiguration/screenPicker/stylesFields.js +874 -0
  87. package/manifestUtils/sharedConfiguration/screenPicker/utils.js +130 -0
  88. package/modalState/__tests__/index.test.ts +51 -0
  89. package/modalState/index.ts +32 -2
  90. package/navigationUtils/__tests__/__snapshots__/navigationUtils.test.js.snap +7 -6
  91. package/navigationUtils/__tests__/itemTypes.test.js +2 -2
  92. package/navigationUtils/__tests__/navigationUtils.test.js +2 -2
  93. package/navigationUtils/index.ts +6 -4
  94. package/numberUtils/__tests__/toPositiveNumberWithDefault.test.ts +23 -3
  95. package/numberUtils/index.ts +11 -5
  96. package/package.json +5 -10
  97. package/playerUtils/configurationGenerator.ts +9 -11
  98. package/playerUtils/index.ts +23 -0
  99. package/reactHooks/advertising/index.ts +5 -5
  100. package/reactHooks/app/useAppState.ts +2 -2
  101. package/reactHooks/autoscrolling/__tests__/useTrackCurrentAutoScrollingElement.test.ts +1 -1
  102. package/reactHooks/autoscrolling/__tests__/useTrackedView.test.tsx +6 -8
  103. package/reactHooks/autoscrolling/useTrackedView.ts +12 -1
  104. package/reactHooks/cell-click/__tests__/index.test.js +10 -2
  105. package/reactHooks/cell-click/index.ts +7 -1
  106. package/reactHooks/feed/__tests__/useBuildPipesUrl.test.tsx +4 -4
  107. package/reactHooks/feed/__tests__/useFeedLoader.test.tsx +10 -11
  108. package/reactHooks/feed/useBatchLoading.ts +12 -14
  109. package/reactHooks/feed/useFeedLoader.tsx +18 -9
  110. package/reactHooks/feed/usePipesCacheReset.ts +5 -5
  111. package/reactHooks/flatList/__tests__/index.test.tsx +30 -21
  112. package/reactHooks/hookModal/hooks/useHookModalScreenData.ts +39 -0
  113. package/reactHooks/layout/__tests__/index.test.tsx +10 -10
  114. package/reactHooks/layout/useDimensions/helpers/__tests__/getInitialDimensions.native.test.js +14 -28
  115. package/reactHooks/layout/useDimensions/helpers/__tests__/getInitialDimensions.test.js +1 -1
  116. package/reactHooks/layout/useDimensions/useDimensions.ts +8 -0
  117. package/reactHooks/navigation/__mocks__/useNavigation.ts +3 -0
  118. package/reactHooks/navigation/__tests__/index.test.tsx +6 -21
  119. package/reactHooks/navigation/getTabBarHeight.ts +10 -0
  120. package/reactHooks/navigation/index.ts +34 -236
  121. package/reactHooks/navigation/useGetBottomTabBarHeight.ts +19 -0
  122. package/reactHooks/navigation/useGetNavBarTopBorderWidth.ts +14 -0
  123. package/reactHooks/navigation/useIsScreenActive.ts +17 -0
  124. package/reactHooks/navigation/useNavigationPluginData.ts +19 -0
  125. package/reactHooks/navigation/useNavigationType.ts +17 -0
  126. package/reactHooks/navigation/usePathname.ts +4 -0
  127. package/reactHooks/navigation/useProfilerLogging.ts +15 -0
  128. package/reactHooks/navigation/useRoute.ts +98 -0
  129. package/reactHooks/navigation/useUniqueRouteSuffix.ts +41 -0
  130. package/reactHooks/player/TVSeekControlller/ISeekController.ts +32 -0
  131. package/reactHooks/player/TVSeekControlller/LongPressSeekController.ts +71 -0
  132. package/reactHooks/player/TVSeekControlller/TVSeekController.ts +258 -0
  133. package/reactHooks/player/TVSeekControlller/TapSeekController.ts +53 -0
  134. package/reactHooks/player/__tests__/{useAutoSeek.test.tsx → useAutoSeek._test.tsx} +2 -3
  135. package/reactHooks/player/const.ts +0 -4
  136. package/reactHooks/player/index.ts +0 -6
  137. package/reactHooks/screen/__tests__/useScreenBackgroundColor.test.tsx +69 -0
  138. package/reactHooks/screen/useScreenBackgroundColor.ts +3 -15
  139. package/reactHooks/state/README.md +79 -0
  140. package/reactHooks/state/ZStoreProvider.tsx +71 -0
  141. package/reactHooks/state/__tests__/ZStoreProvider.test.tsx +66 -0
  142. package/reactHooks/state/index.ts +2 -0
  143. package/reactHooks/state/useRefWithInitialValue.ts +14 -0
  144. package/reactHooks/state/useStateFromSubscribe.ts +23 -0
  145. package/reactHooks/useListenEventBusEvent.ts +1 -1
  146. package/reactHooks/usePluginConfiguration.ts +1 -1
  147. package/reactHooks/useSubscriberFor.ts +4 -3
  148. package/reactUtils/__tests__/__snapshots__/reactUtilsHelpers.test.js.snap +16 -4
  149. package/reactUtils/__tests__/reactUtils.test.js +1 -37
  150. package/reactUtils/__tests__/reactUtilsHelpers.test.js +72 -71
  151. package/reactUtils/createContext/__tests__/__snapshots__/helpers.test.js.snap +13 -79
  152. package/reactUtils/createContext/__tests__/__snapshots__/{index.test.js.snap → index.test.ts.snap} +2 -2
  153. package/reactUtils/createContext/__tests__/__snapshots__/provider.test.js.snap +3 -28
  154. package/reactUtils/createContext/__tests__/__snapshots__/withConsumer.test.js.snap +3 -4
  155. package/reactUtils/createContext/__tests__/__snapshots__/withProvider.test.js.snap +7 -3
  156. package/reactUtils/createContext/__tests__/helpers.test.js +107 -121
  157. package/reactUtils/createContext/__tests__/{index.test.js → index.test.ts} +2 -2
  158. package/reactUtils/createContext/__tests__/provider.test.js +4 -6
  159. package/reactUtils/createContext/__tests__/withConsumer.test.js +12 -12
  160. package/reactUtils/createContext/__tests__/withProvider.test.js +4 -4
  161. package/reactUtils/createContext/helpers.ts +6 -1
  162. package/reactUtils/createContext/index.ts +11 -25
  163. package/reactUtils/index.ts +9 -11
  164. package/screenState/index.ts +24 -10
  165. package/services/js2native.ts +673 -0
  166. package/testUtils/index.tsx +0 -10
  167. package/theme/__mocks__/index.ts +4 -0
  168. package/theme/index.ts +1 -1
  169. package/time/BackgroundTimer.ts +55 -0
  170. package/time/Timer.ts +9 -6
  171. package/typeGuards/index.ts +3 -0
  172. package/types.ts +1 -0
  173. package/utils/README.md +30 -0
  174. package/utils/chunk.ts +5 -0
  175. package/utils/index.ts +16 -0
  176. package/utils/times.ts +5 -0
  177. package/zappFrameworkUtils/localStorageHelper.ts +38 -10
  178. package/zappFrameworkUtils/loginPluginUtils.ts +6 -2
  179. package/zappFrameworkUtils/presentPluginOneTime.ts +2 -3
  180. package/zappFrameworkUtils/types.ts +11 -0
  181. package/reactHooks/player/useAutoSeek.tsx +0 -87
  182. package/reactHooks/player/useSeek.tsx +0 -66
  183. package/reactHooks/player/useTapSeek.tsx +0 -58
  184. package/reactUtils/createContext/__tests__/index-no-react.test.js +0 -27
  185. /package/reactHooks/player/__tests__/{useTapSeek.test.ts → useTapSeek._test.ts} +0 -0
package/README.md CHANGED
@@ -376,16 +376,6 @@ useEffect(() => {
376
376
  }, []);
377
377
  ```
378
378
 
379
- ### testUtils
380
-
381
- `@applicaster/zapp-react-native-utils/testUtils`
382
-
383
- - `testIDEquals: (testId: any) => boolean | { width: number, height: number }` - Function to be used in tandem with enzyme findWhere
384
-
385
- ```javascript
386
- wrapper.findWhere(testIDEquals("text"));
387
- ```
388
-
389
379
  ### appUtils - contextKeysManager
390
380
 
391
381
  `@applicaster/zapp-react-native-utils/appUtils/contextKeyManager`
@@ -17,9 +17,10 @@ class ActionExecutor {
17
17
 
18
18
  handleAction = async (
19
19
  action: ActionType,
20
- entry: ZappEntry = null
20
+ context?: Record<string, any>
21
21
  ): Promise<ActionResult> => {
22
22
  const handler = this.registeredActions[action.type];
23
+ const entry = context?.entry as ZappEntry;
23
24
 
24
25
  if (!handler) {
25
26
  log_error(
@@ -38,11 +39,11 @@ class ActionExecutor {
38
39
  );
39
40
 
40
41
  try {
41
- return handler(action, entry);
42
+ return handler(action, context);
42
43
  } catch (error) {
43
44
  log_error(
44
45
  `handleAction: error handling action type: ${action.type}, message: ${error.message}`,
45
- { action, entry, error }
46
+ { action, context, error }
46
47
  );
47
48
 
48
49
  throw error;
@@ -51,11 +52,11 @@ class ActionExecutor {
51
52
 
52
53
  handleActions = async (
53
54
  actionTypes: ActionType[],
54
- entry: ZappEntry = null
55
+ context?: Record<string, any>
55
56
  ): Promise<ActionResult> => {
56
57
  for (const action of actionTypes) {
57
58
  // TODO: Handle action result error
58
- const result = await this.handleAction(action, entry);
59
+ const result = await this.handleAction(action, context);
59
60
 
60
61
  if (result === ActionResult.Cancel) {
61
62
  log_info(`handleActions: action: ${action.type} canceled`);
@@ -67,7 +68,10 @@ class ActionExecutor {
67
68
  return ActionResult.Success;
68
69
  };
69
70
 
70
- handleEntryActions = async (entry: ZappEntry): Promise<ActionResult> => {
71
+ handleEntryActions = async (
72
+ entry: ZappEntry,
73
+ context?: Record<string, any>
74
+ ): Promise<ActionResult> => {
71
75
  const tapActions = entry.extensions?.tap_actions?.actions;
72
76
 
73
77
  if (!tapActions) {
@@ -77,7 +81,7 @@ class ActionExecutor {
77
81
  if (!Array.isArray(tapActions)) {
78
82
  log_error(
79
83
  `handleEntryActions: tapActions is not an array for id: ${entry.id} title: ${entry.title}`,
80
- { entry }
84
+ { context, entry }
81
85
  );
82
86
 
83
87
  return;
@@ -87,7 +91,7 @@ class ActionExecutor {
87
91
  return;
88
92
  }
89
93
 
90
- await this.handleActions(tapActions, entry);
94
+ await this.handleActions(tapActions, { ...context, entry });
91
95
  };
92
96
 
93
97
  unregisterAction = (actionType: string) => {
@@ -96,7 +100,10 @@ class ActionExecutor {
96
100
 
97
101
  registerAction = (
98
102
  type: string,
99
- handler: (action: ActionType, entry?: ZappEntry) => Promise<ActionResult>
103
+ handler: (
104
+ action: ActionType,
105
+ context?: Record<string, any>
106
+ ) => Promise<ActionResult>
100
107
  ) => {
101
108
  if (this.registeredActions[type]) {
102
109
  log_error(`registerAction: action type: ${type} already registered`);
@@ -1,20 +1,41 @@
1
1
  /// <reference types="@applicaster/applicaster-types" />
2
2
  import { localStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/LocalStorage";
3
- import React, { createContext, useMemo } from "react";
3
+ import React, { createContext, useEffect, useMemo } from "react";
4
4
  import {
5
5
  actionExecutor as _actionExecutor,
6
6
  ActionResult,
7
7
  } from "./ActionExecutor";
8
- import { batchSaveToLocalStorage } from "../zappFrameworkUtils/localStorageHelper";
9
- import { QUICK_BRICK_EVENTS } from "@applicaster/zapp-react-native-bridge/QuickBrick";
8
+ import {
9
+ batchRemoveAllFromNamespaceForStorage,
10
+ batchSave,
11
+ } from "../zappFrameworkUtils/localStorageHelper";
12
+ import { sessionStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/SessionStorage";
13
+
10
14
  import * as QuickBrickManager from "@applicaster/zapp-react-native-bridge/QuickBrick";
15
+ import { QUICK_BRICK_EVENTS } from "@applicaster/zapp-react-native-bridge/QuickBrick";
11
16
  import { showConfirmationDialog } from "../alertUtils";
12
17
  import { createCloudEvent, sendCloudEvent } from "../cloudEventsUtils";
13
18
  import { createLogger } from "../logger";
14
19
  import { StorageMultiSelectProvider } from "@applicaster/zapp-react-native-bridge/ZappStorage/StorageMultiSelectProvider";
15
20
  import { ACTIVE_LAYOUT_ID_STORAGE_KEY } from "@applicaster/quick-brick-core/App/remoteContextReloader/consts";
21
+ import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
22
+ import { loadPipesData } from "@applicaster/zapp-react-native-redux/ZappPipes";
23
+ import {
24
+ EntryResolver,
25
+ resolveObjectValues,
26
+ } from "../appUtils/contextKeysManager/contextResolver";
27
+ import { useNavigation } from "../reactHooks";
28
+ import { get } from "lodash";
16
29
 
17
- const { log_error, log_info } = createLogger({
30
+ import {
31
+ useContentTypes,
32
+ usePickFromState,
33
+ } from "@applicaster/zapp-react-native-redux/hooks";
34
+ import { TOGGLE_FLAG_MAX_ITEMS_REACHED_EVENT } from "./consts";
35
+ import { postEvent, useSubscriberFor } from "../reactHooks/useSubscriberFor";
36
+ import { APP_EVENTS } from "../appUtils/events";
37
+
38
+ export const { log_error, log_info, log_debug } = createLogger({
18
39
  subsystem: "ActionExecutorContext",
19
40
  category: "General",
20
41
  });
@@ -22,29 +43,102 @@ const { log_error, log_info } = createLogger({
22
43
  type ActionExecutorContextType = {
23
44
  registerAction: (
24
45
  type: string,
25
- handler: (action: ActionType, entry: ZappEntry) => Promise<ActionResult>
46
+ handler: (
47
+ action: ActionType,
48
+ context?: Record<string, any>
49
+ ) => Promise<ActionResult>
26
50
  ) => void;
27
51
  unregisterAction: (type: string) => void;
28
- handleAction: (action: ActionType, entry: ZappEntry) => Promise<ActionResult>;
52
+ handleAction: (
53
+ action: ActionType,
54
+ context?: Record<string, any>
55
+ ) => Promise<ActionResult>;
29
56
  handleActions: (
30
57
  actions: ActionType[],
31
- entry: ZappEntry
58
+ context: Record<string, any>
59
+ ) => Promise<ActionResult>;
60
+ handleEntryActions: (
61
+ entry: ZappEntry,
62
+ context?: Record<string, any>
32
63
  ) => Promise<ActionResult>;
33
- handleEntryActions: (entry: ZappEntry) => Promise<ActionResult>;
34
64
  };
35
65
  type Props = {
36
66
  children: React.ReactNode;
37
67
  };
38
68
 
69
+ function findParentComponent(
70
+ childId: string,
71
+ parent: ZappRiver | ZappUIComponent
72
+ ): ZappRiver | ZappUIComponent | null {
73
+ for (const child of parent.ui_components) {
74
+ if (child.id === childId) return parent;
75
+
76
+ if (child.ui_components) {
77
+ const found = findParentComponent(childId, child);
78
+ if (found) return found;
79
+ }
80
+ }
81
+
82
+ return null;
83
+ }
84
+
85
+ // send all data just in case (like for message string formatting)
86
+ // Type is not exported for now
87
+ type MaxTagsReachedEvent = {
88
+ selectedItems: string[];
89
+ maxItems: number;
90
+ tag: string;
91
+ keyNamespace: string;
92
+ };
93
+
94
+ async function onMaxTagsReached(data: MaxTagsReachedEvent) {
95
+ postEvent(TOGGLE_FLAG_MAX_ITEMS_REACHED_EVENT, [data]);
96
+ }
97
+
39
98
  const prepareDefaultActions = (actionExecutor) => {
40
99
  actionExecutor.registerAction("localStorageSet", async (action) => {
41
100
  const namespaces = action.options.content;
42
- await batchSaveToLocalStorage(namespaces);
101
+ await batchSave(namespaces, localStorage);
43
102
  // TODO: Add support for ownershipKey and ownershipNamespace
44
103
 
45
104
  return ActionResult.Success;
46
105
  });
47
106
 
107
+ actionExecutor.registerAction("sessionStorageSet", async (action) => {
108
+ const namespaces = action.options.content;
109
+ await batchSave(namespaces, sessionStorage);
110
+ // TODO: Add support for ownershipKey and ownershipNamespace
111
+
112
+ return ActionResult.Success;
113
+ });
114
+
115
+ actionExecutor.registerAction(
116
+ "refreshComponent",
117
+ async (_action, context) => {
118
+ const dispatch = appStore.getDispatch();
119
+
120
+ const dataSource =
121
+ context?.component?.data?.source ||
122
+ findParentComponent(context?.component.id, context?.screenData)?.data
123
+ ?.source;
124
+
125
+ log_info(`handleAction: refreshComponent for dataSource:${dataSource}`);
126
+
127
+ // TODO: In theory we should wait callback to complete, before completing the action, but now it's not needed
128
+ // TODO: handle focused item removal
129
+ dispatch(
130
+ loadPipesData(dataSource, {
131
+ silentRefresh: false,
132
+ clearCache: true,
133
+ callback: (_data) => {},
134
+ riverId: context?.screenData?.id,
135
+ })
136
+ );
137
+
138
+ return ActionResult.Success;
139
+ }
140
+ );
141
+
48
142
  actionExecutor.registerAction("switchLayout", async (action) => {
49
143
  log_info("handleAction: switchLayout event");
50
144
 
@@ -69,24 +163,30 @@ const prepareDefaultActions = (actionExecutor) => {
69
163
  actionExecutor.registerAction("confirmDialog", async (action) => {
70
164
  log_info("handleAction: confirmDialog event");
71
165
 
72
- const confirmationPromise = new Promise<ActionResult>((resolve) => {
166
+ return new Promise<ActionResult>((resolve) => {
73
167
  showConfirmationDialog({
74
168
  ...action.options,
75
169
  confirmCompletion: () => resolve(ActionResult.Success),
76
170
  cancelCompletion: () => resolve(ActionResult.Cancel),
77
171
  });
78
172
  });
79
-
80
- return confirmationPromise;
81
173
  });
82
174
 
83
- actionExecutor.registerAction("sendCloudEvent", async (action, entry) => {
175
+ actionExecutor.registerAction("sendCloudEvent", async (action, context) => {
84
176
  try {
85
177
  const options = action.options;
86
178
 
179
+ const entry = context?.entry || {};
180
+ const entryResolver = new EntryResolver(entry);
181
+
182
+ const data =
183
+ options?.data && options.inflateData
184
+ ? await resolveObjectValues(options.data, { entry: entryResolver })
185
+ : options?.data || entry;
186
+
87
187
  const cloudEvent = await createCloudEvent({
88
188
  type: options.type || "com.applicaster.selector.action.v1",
89
- data: options.data || entry,
189
+ data,
90
190
  subject: options.subject || entry?.id,
91
191
  });
92
192
 
@@ -117,9 +217,33 @@ const prepareDefaultActions = (actionExecutor) => {
117
217
 
118
218
  actionExecutor.registerAction(
119
219
  "localStorageToggleFlag",
120
- async (action: ActionType, entry?: ZappEntry): Promise<ActionResult> => {
220
+ async (
221
+ action: ActionType,
222
+ context?: Record<string, any>
223
+ ): Promise<ActionResult> => {
224
+ if (!context) {
225
+ log_error(
226
+ "handleAction: localStorageToggleFlag action missing context"
227
+ );
228
+
229
+ return ActionResult.Error;
230
+ }
231
+
232
+ const entry = context?.entry as ZappEntry;
233
+
234
+ if (!entry) {
235
+ log_error(
236
+ "handleAction: localStorageToggleFlag action missing entry. Entry is required to get the tag."
237
+ );
238
+
239
+ return ActionResult.Error;
240
+ }
241
+
242
+ const tag = action.options?.selector
243
+ ? get(entry, action.options.selector)
244
+ : (entry.extensions?.tag ?? entry.id);
245
+
121
246
  const keyNamespace = action.options?.key;
122
- const tag = entry?.extensions?.tag;
123
247
 
124
248
  if (keyNamespace && tag) {
125
249
  const multiSelectProvider =
@@ -137,6 +261,23 @@ const prepareDefaultActions = (actionExecutor) => {
137
261
  if (selectedItems.includes(tag)) {
138
262
  await multiSelectProvider.removeItem(tag);
139
263
  } else {
264
+ const maxItems = action.options?.max_items;
265
+
266
+ if (maxItems && selectedItems.length >= maxItems) {
267
+ log_info(
268
+ `handleAction: localStorageToggleFlag event reached max items limit: ${maxItems}, cannot add tag: ${tag}`
269
+ );
270
+
271
+ await onMaxTagsReached({
272
+ selectedItems,
273
+ maxItems,
274
+ tag,
275
+ keyNamespace,
276
+ });
277
+
278
+ return ActionResult.Cancel;
279
+ }
280
+
140
281
  await multiSelectProvider.addItem(tag);
141
282
  }
142
283
  } else {
@@ -160,6 +301,10 @@ export function withActionExecutor(Component) {
160
301
  prepareDefaultActions(_actionExecutor);
161
302
 
162
303
  return function ActionExecutorComponent(props: Props) {
304
+ const navigator = useNavigation();
305
+ const { rivers } = usePickFromState(["rivers"]);
306
+ const contentTypes = useContentTypes();
307
+
163
308
  const handlers = useMemo(() => {
164
309
  return {
165
310
  unregisterAction: _actionExecutor.unregisterAction,
@@ -170,6 +315,59 @@ export function withActionExecutor(Component) {
170
315
  };
171
316
  }, []);
172
317
 
318
+ useSubscriberFor(APP_EVENTS.onLogout, () => {
319
+ log_debug(
320
+ "User profile: onLogout event received, clearing user profile data"
321
+ );
322
+
323
+ const userAccountKey = "user_account";
324
+ void batchRemoveAllFromNamespaceForStorage(userAccountKey, localStorage);
325
+
326
+ void batchRemoveAllFromNamespaceForStorage(
327
+ userAccountKey,
328
+ sessionStorage
329
+ );
330
+ });
331
+
332
+ useEffect(() => {
333
+ return _actionExecutor.registerAction(
334
+ "navigateToScreen",
335
+
336
+ async (action: ActionType, context?: Record<string, any>) => {
337
+ const screenType = action.options?.typeMapping;
338
+
339
+ if (!screenType) {
340
+ log_error("navigateToScreen: typeMapping option is missing");
341
+
342
+ return ActionResult.Error;
343
+ }
344
+
345
+ const screenId = contentTypes?.[screenType]?.screen_id || null;
346
+
347
+ if (!screenId) {
348
+ log_error(
349
+ `navigateToScreen: can not resolve screen type mapping: ${screenType}`
350
+ );
351
+
352
+ return ActionResult.Error;
353
+ }
354
+
355
+ const river = rivers[screenId];
356
+
357
+ if (!river) {
358
+ log_error("navigateToScreen: can not resolve river");
359
+
360
+ return ActionResult.Error;
361
+ }
362
+
363
+ context?.callback?.({ success: false, error: null, abort: true });
364
+ navigator.replace(river);
365
+
366
+ return ActionResult.Success;
367
+ }
368
+ );
369
+ }, [navigator, rivers, contentTypes]);
370
+
173
371
  return (
174
372
  <ActionExecutorContext.Provider value={handlers}>
175
373
  <Component {...props} />
@@ -0,0 +1,4 @@
1
+ export const TOGGLE_FLAG_MAX_ITEMS_REACHED_EVENT =
2
+ "action.localStorageToggleFlag.maxItemsReached";
3
+
4
+ export const ACTION_EXECUTOR_EVENT_SOURCE = "ActionExecutor";
@@ -0,0 +1,148 @@
1
+ import { Alert } from "react-native";
2
+ import { isWeb } from "@applicaster/zapp-react-native-utils/reactUtils";
3
+ import { confirmationDialogStore } from "@applicaster/zapp-react-native-ui-components/Contexts/ConfirmDialogState";
4
+
5
+ // #region "Alert Dialog"
6
+
7
+ const globalAny: any = global;
8
+
9
+ const showWebAlertDialog = ({ message, completion }: AlertWebDialog) => {
10
+ globalAny?.alert?.(message);
11
+ completion?.();
12
+ };
13
+
14
+ const showNativeAlertDialog = ({
15
+ title,
16
+ message,
17
+ okButtonText,
18
+ completion,
19
+ }: AlertDialogType) => {
20
+ Alert.alert(title, message, [
21
+ {
22
+ text: okButtonText,
23
+ onPress: completion,
24
+ },
25
+ ]);
26
+ };
27
+
28
+ export const showAlertDialog = ({
29
+ title,
30
+ message,
31
+ okButtonText,
32
+ completion,
33
+ }: AlertDialogType) => {
34
+ if (isWeb()) {
35
+ showWebAlertDialog({ message, completion });
36
+ } else {
37
+ showNativeAlertDialog({
38
+ title,
39
+ message,
40
+ okButtonText,
41
+ completion,
42
+ });
43
+ }
44
+ };
45
+
46
+ // #endregion "Alert Dialog"
47
+
48
+ // #region "Confirmation Dialog"
49
+
50
+ const showWebDialog = ({
51
+ message,
52
+ confirmCompletion,
53
+ cancelCompletion,
54
+ }: WebConfirmationDialog) => {
55
+ const isConfirmed = globalAny?.confirm?.(message);
56
+
57
+ if (isConfirmed) {
58
+ confirmCompletion?.();
59
+ } else {
60
+ cancelCompletion?.();
61
+ }
62
+ };
63
+
64
+ const showNativeDialog = ({
65
+ title,
66
+ message,
67
+ okButtonText,
68
+ cancelButtonText,
69
+ confirmCompletion,
70
+ cancelCompletion,
71
+ }: ConfirmationDialog) => {
72
+ Alert.alert(title, message, [
73
+ {
74
+ text: cancelButtonText,
75
+ onPress: cancelCompletion,
76
+ },
77
+ {
78
+ text: okButtonText,
79
+ style: "destructive",
80
+ onPress: confirmCompletion,
81
+ },
82
+ ]);
83
+ };
84
+
85
+ const handleCustomDialog = (data) => {
86
+ const {
87
+ showDialog,
88
+ hideDialog,
89
+ setConfirmAction,
90
+ setCancelAction,
91
+ setMessages,
92
+ } = confirmationDialogStore.getState();
93
+
94
+ setMessages(data.messages);
95
+
96
+ if (data?.cancelCompletion) {
97
+ setCancelAction(() => {
98
+ data.cancelCompletion();
99
+ hideDialog();
100
+ });
101
+ }
102
+
103
+ if (data?.confirmCompletion) {
104
+ setConfirmAction(() => {
105
+ data.confirmCompletion();
106
+ hideDialog();
107
+ });
108
+ }
109
+
110
+ showDialog();
111
+ };
112
+
113
+ export const showConfirmationDialog = ({
114
+ title,
115
+ message,
116
+ okButtonText,
117
+ cancelButtonText,
118
+ confirmCompletion,
119
+ cancelCompletion,
120
+ }: CustomConfirmationDialog): void => {
121
+ if (isWeb()) {
122
+ if (cancelCompletion) {
123
+ handleCustomDialog({
124
+ messages: {
125
+ title,
126
+ message,
127
+ okButtonText,
128
+ cancelButtonText,
129
+ },
130
+ confirmCompletion,
131
+ cancelCompletion,
132
+ });
133
+ } else {
134
+ showWebDialog({ message, confirmCompletion, cancelCompletion });
135
+ }
136
+ } else {
137
+ showNativeDialog({
138
+ title,
139
+ message,
140
+ okButtonText,
141
+ cancelButtonText,
142
+ confirmCompletion,
143
+ cancelCompletion,
144
+ });
145
+ }
146
+ };
147
+
148
+ // #endregion "Confirmation Dialog"