@applicaster/zapp-react-native-utils 13.0.0-rc.12 → 13.0.0-rc.121

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 (183) hide show
  1. package/README.md +0 -10
  2. package/actionsExecutor/ActionExecutor.ts +16 -9
  3. package/actionsExecutor/ActionExecutorContext.tsx +196 -11
  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.js → Hook.ts} +39 -23
  12. package/appUtils/HooksManager/__tests__/__snapshots__/hook.test.js.snap +10 -8
  13. package/appUtils/HooksManager/__tests__/__snapshots__/hooksManager.test.js.snap +693 -0
  14. package/appUtils/HooksManager/__tests__/hook.test.js +196 -184
  15. package/appUtils/HooksManager/__tests__/hooksManager.test.js +96 -99
  16. package/appUtils/HooksManager/{constants.js → constants.ts} +1 -1
  17. package/appUtils/HooksManager/{index.js → index.ts} +124 -113
  18. package/appUtils/HooksManager/types.ts +119 -0
  19. package/appUtils/RiverFocusManager/index.js +17 -12
  20. package/appUtils/__tests__/__snapshots__/localizationsHelper.test.ts.snap +151 -0
  21. package/appUtils/__tests__/allZappLocales.ts +79 -0
  22. package/appUtils/__tests__/{localizationsHelper.test.js → localizationsHelper.test.ts} +11 -0
  23. package/appUtils/accessibilityManager/index.ts +42 -1
  24. package/appUtils/contextKeysManager/contextResolver.ts +66 -0
  25. package/appUtils/contextKeysManager/index.ts +2 -2
  26. package/appUtils/contextKeysManager/utils/index.ts +2 -1
  27. package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +9 -6
  28. package/appUtils/focusManager/index.ios.ts +14 -4
  29. package/appUtils/focusManager/index.ts +108 -69
  30. package/appUtils/focusManager/treeDataStructure/Tree/index.js +25 -3
  31. package/appUtils/focusManager/treeDataStructure/Utils/index.js +1 -3
  32. package/appUtils/focusManager/utils/__tests__/findChild.test.ts +35 -0
  33. package/appUtils/focusManager/utils/enums.ts +4 -0
  34. package/appUtils/focusManager/utils/index.ts +5 -0
  35. package/appUtils/focusManagerAux/utils/index.ts +4 -3
  36. package/appUtils/{index.js → index.ts} +1 -1
  37. package/appUtils/keyCodes/__tests__/__snapshots__/keyCodes.test.js.snap +2 -2
  38. package/appUtils/keyCodes/__tests__/keyCodes.test.js +4 -4
  39. package/appUtils/keyCodes/{index.js → index.ts} +13 -7
  40. package/appUtils/keyCodes/keys/index.ts +3 -0
  41. package/appUtils/keyCodes/{keys.android.js → keys/keyEventMapper.ts} +0 -19
  42. package/appUtils/keyCodes/keys/keys.android.ts +18 -0
  43. package/appUtils/keyCodes/keys/keys.ios.ts +25 -0
  44. package/appUtils/keyCodes/keys/keys.ts +15 -0
  45. package/appUtils/keyCodes/{keysByPlatform.js → keys/keysByPlatform.ts} +4 -0
  46. package/appUtils/keyCodes/keysByPlatform.ts +8 -0
  47. package/appUtils/keyInputHandler/KeyInputHandler.ts +68 -0
  48. package/appUtils/{localizationsHelper.js → localizationsHelper.ts} +31 -0
  49. package/appUtils/orientationHelper.ts +11 -13
  50. package/appUtils/platform/const.ts +14 -0
  51. package/appUtils/platform/platformUtils.ts +47 -18
  52. package/appUtils/playerManager/index.ts +1 -1
  53. package/appUtils/playerManager/player.ts +42 -18
  54. package/appUtils/playerManager/playerHooks/usePlayerCurrentTime.tsx +11 -7
  55. package/appUtils/playerManager/playerNative.ts +18 -2
  56. package/appUtils/playerManager/usePlayerControllerSetup.tsx +3 -3
  57. package/appUtils/playerManager/usePlayerTitleSummaryOverlay.tsx +7 -1
  58. package/arrayUtils/__tests__/__snapshots__/arrayUtils.test.ts.snap +4 -4
  59. package/cellUtils/index.ts +9 -5
  60. package/componentsUtils/__tests__/isFirstComponentGallery.test.ts +33 -0
  61. package/componentsUtils/__tests__/isFirstComponentScreenPicker.test.ts +33 -0
  62. package/componentsUtils/__tests__/isGallery.test.ts +33 -0
  63. package/componentsUtils/__tests__/isScreenPicker.test.ts +33 -0
  64. package/componentsUtils/index.ts +39 -0
  65. package/dateUtils/index.ts +19 -0
  66. package/domUtils/{cookieManager.js → cookieManager.ts} +1 -2
  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 +61 -19
  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/keys.js +27 -2
  84. package/manifestUtils/sharedConfiguration/screenPicker/__tests__/utils.test.js +304 -0
  85. package/manifestUtils/sharedConfiguration/screenPicker/stylesFields.js +875 -0
  86. package/manifestUtils/sharedConfiguration/screenPicker/utils.js +130 -0
  87. package/modalState/__tests__/index.test.ts +51 -0
  88. package/modalState/index.ts +33 -7
  89. package/navigationUtils/__tests__/__snapshots__/navigationUtils.test.js.snap +7 -6
  90. package/navigationUtils/__tests__/itemTypes.test.js +2 -2
  91. package/navigationUtils/__tests__/navigationUtils.test.js +2 -2
  92. package/navigationUtils/index.ts +20 -9
  93. package/numberUtils/__tests__/toPositiveNumberWithDefault.test.ts +23 -3
  94. package/numberUtils/index.ts +11 -5
  95. package/package.json +5 -10
  96. package/playerUtils/configurationGenerator.ts +9 -11
  97. package/reactHooks/advertising/index.ts +5 -5
  98. package/reactHooks/autoscrolling/__tests__/useTrackCurrentAutoScrollingElement.test.ts +1 -1
  99. package/reactHooks/autoscrolling/__tests__/useTrackedView.test.tsx +6 -8
  100. package/reactHooks/autoscrolling/useTrackedView.ts +12 -1
  101. package/reactHooks/cell-click/__tests__/index.test.js +10 -2
  102. package/reactHooks/cell-click/index.ts +7 -1
  103. package/reactHooks/feed/__tests__/useBuildPipesUrl.test.tsx +4 -4
  104. package/reactHooks/feed/__tests__/useFeedLoader.test.tsx +10 -11
  105. package/reactHooks/feed/useBatchLoading.ts +10 -12
  106. package/reactHooks/feed/useFeedLoader.tsx +18 -9
  107. package/reactHooks/feed/usePipesCacheReset.ts +5 -5
  108. package/reactHooks/flatList/__tests__/index.test.tsx +30 -21
  109. package/reactHooks/hookModal/hooks/useHookModalScreenData.ts +39 -0
  110. package/reactHooks/layout/__tests__/index.test.tsx +10 -10
  111. package/reactHooks/layout/useDimensions/helpers/__tests__/getInitialDimensions.native.test.js +14 -28
  112. package/reactHooks/layout/useDimensions/helpers/__tests__/getInitialDimensions.test.js +1 -1
  113. package/reactHooks/layout/useDimensions/useDimensions.ts +8 -0
  114. package/reactHooks/navigation/__mocks__/useNavigation.ts +3 -0
  115. package/reactHooks/navigation/__tests__/index.test.tsx +6 -21
  116. package/reactHooks/navigation/getTabBarHeight.ts +10 -0
  117. package/reactHooks/navigation/index.ts +41 -240
  118. package/reactHooks/navigation/useGetBottomTabBarHeight.ts +19 -0
  119. package/reactHooks/navigation/useGetNavBarTopBorderWidth.ts +14 -0
  120. package/reactHooks/navigation/useIsScreenActive.ts +17 -0
  121. package/reactHooks/navigation/useNavigationPluginData.ts +19 -0
  122. package/reactHooks/navigation/useNavigationType.ts +17 -0
  123. package/reactHooks/navigation/usePathname.ts +4 -0
  124. package/reactHooks/navigation/useProfilerLogging.ts +15 -0
  125. package/reactHooks/navigation/useRoute.ts +98 -0
  126. package/reactHooks/navigation/useUniqueRouteSuffix.ts +41 -0
  127. package/reactHooks/player/TVSeekControlller/ISeekController.ts +32 -0
  128. package/reactHooks/player/TVSeekControlller/LongPressSeekController.ts +71 -0
  129. package/reactHooks/player/TVSeekControlller/TVSeekController.ts +258 -0
  130. package/reactHooks/player/TVSeekControlller/TapSeekController.ts +53 -0
  131. package/reactHooks/player/__tests__/{useAutoSeek.test.tsx → useAutoSeek._test.tsx} +2 -3
  132. package/reactHooks/player/const.ts +0 -4
  133. package/reactHooks/player/index.ts +0 -6
  134. package/reactHooks/screen/__tests__/useScreenBackgroundColor.test.tsx +69 -0
  135. package/reactHooks/screen/useScreenBackgroundColor.ts +3 -15
  136. package/reactHooks/state/useRefWithInitialValue.ts +14 -0
  137. package/reactHooks/state/useStateFromSubscribe.ts +23 -0
  138. package/reactHooks/useListenEventBusEvent.ts +1 -1
  139. package/reactHooks/usePluginConfiguration.ts +1 -1
  140. package/reactHooks/useSubscriberFor.ts +4 -3
  141. package/reactUtils/__tests__/__snapshots__/reactUtilsHelpers.test.js.snap +16 -4
  142. package/reactUtils/__tests__/reactUtils.test.js +1 -37
  143. package/reactUtils/__tests__/reactUtilsHelpers.test.js +72 -71
  144. package/reactUtils/createContext/__tests__/__snapshots__/helpers.test.js.snap +13 -79
  145. package/reactUtils/createContext/__tests__/__snapshots__/{index.test.js.snap → index.test.ts.snap} +2 -2
  146. package/reactUtils/createContext/__tests__/__snapshots__/provider.test.js.snap +3 -28
  147. package/reactUtils/createContext/__tests__/__snapshots__/withConsumer.test.js.snap +3 -4
  148. package/reactUtils/createContext/__tests__/__snapshots__/withProvider.test.js.snap +7 -3
  149. package/reactUtils/createContext/__tests__/helpers.test.js +107 -121
  150. package/reactUtils/createContext/__tests__/{index.test.js → index.test.ts} +2 -2
  151. package/reactUtils/createContext/__tests__/provider.test.js +4 -6
  152. package/reactUtils/createContext/__tests__/withConsumer.test.js +12 -12
  153. package/reactUtils/createContext/__tests__/withProvider.test.js +4 -4
  154. package/reactUtils/createContext/helpers.ts +6 -1
  155. package/reactUtils/createContext/index.ts +11 -25
  156. package/reactUtils/index.ts +9 -25
  157. package/screenState/index.ts +24 -10
  158. package/services/js2native.ts +673 -0
  159. package/testUtils/index.tsx +0 -10
  160. package/theme/__mocks__/index.ts +4 -0
  161. package/theme/index.ts +1 -1
  162. package/time/BackgroundTimer.ts +55 -0
  163. package/time/Timer.ts +9 -6
  164. package/types.ts +1 -0
  165. package/utils/README.md +30 -0
  166. package/utils/chunk.ts +5 -0
  167. package/utils/index.ts +5 -0
  168. package/utils/times.ts +5 -0
  169. package/zappFrameworkUtils/localStorageHelper.ts +6 -0
  170. package/zappFrameworkUtils/loginPluginUtils.ts +6 -2
  171. package/zappFrameworkUtils/presentPluginOneTime.ts +2 -3
  172. package/zappFrameworkUtils/types.ts +11 -0
  173. package/appUtils/keyCodes/keys.ios.js +0 -46
  174. package/reactHooks/player/useAutoSeek.tsx +0 -87
  175. package/reactHooks/player/useSeek.tsx +0 -66
  176. package/reactHooks/player/useTapSeek.tsx +0 -58
  177. package/reactUtils/createContext/__tests__/index-no-react.test.js +0 -27
  178. /package/appUtils/HooksManager/{logger.js → logger.ts} +0 -0
  179. /package/appUtils/{directionHelper.js → directionHelper.ts} +0 -0
  180. /package/appUtils/keyCodes/{androidTVKeys.js → androidTVKeys.ts} +0 -0
  181. /package/appUtils/keyCodes/{keys.web.js → keys/keys.web.ts} +0 -0
  182. /package/domUtils/{logger.js → logger.ts} +0 -0
  183. /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,6 +1,6 @@
1
1
  /// <reference types="@applicaster/applicaster-types" />
2
-
3
- import React, { createContext, useMemo } from "react";
2
+ import { localStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/LocalStorage";
3
+ import React, { createContext, useEffect, useMemo } from "react";
4
4
  import {
5
5
  actionExecutor as _actionExecutor,
6
6
  ActionResult,
@@ -12,8 +12,24 @@ import { showConfirmationDialog } from "../alertUtils";
12
12
  import { createCloudEvent, sendCloudEvent } from "../cloudEventsUtils";
13
13
  import { createLogger } from "../logger";
14
14
  import { StorageMultiSelectProvider } from "@applicaster/zapp-react-native-bridge/ZappStorage/StorageMultiSelectProvider";
15
+ import { ACTIVE_LAYOUT_ID_STORAGE_KEY } from "@applicaster/quick-brick-core/App/remoteContextReloader/consts";
16
+ import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
17
+ import { loadPipesData } from "@applicaster/zapp-react-native-redux/ZappPipes";
18
+ import {
19
+ EntryResolver,
20
+ resolveObjectValues,
21
+ } from "../appUtils/contextKeysManager/contextResolver";
22
+ import { useNavigation } from "../reactHooks";
23
+ import { get } from "lodash";
24
+
25
+ import {
26
+ useContentTypes,
27
+ usePickFromState,
28
+ } from "@applicaster/zapp-react-native-redux/hooks";
29
+ import { TOGGLE_FLAG_MAX_ITEMS_REACHED_EVENT } from "./consts";
30
+ import { postEvent } from "../reactHooks/useSubscriberFor";
15
31
 
16
- const { log_error, log_info } = createLogger({
32
+ export const { log_error, log_info, log_debug } = createLogger({
17
33
  subsystem: "ActionExecutorContext",
18
34
  category: "General",
19
35
  });
@@ -21,20 +37,58 @@ const { log_error, log_info } = createLogger({
21
37
  type ActionExecutorContextType = {
22
38
  registerAction: (
23
39
  type: string,
24
- handler: (action: ActionType, entry: ZappEntry) => Promise<ActionResult>
40
+ handler: (
41
+ action: ActionType,
42
+ context?: Record<string, any>
43
+ ) => Promise<ActionResult>
25
44
  ) => void;
26
45
  unregisterAction: (type: string) => void;
27
- handleAction: (action: ActionType, entry: ZappEntry) => Promise<ActionResult>;
46
+ handleAction: (
47
+ action: ActionType,
48
+ context?: Record<string, any>
49
+ ) => Promise<ActionResult>;
28
50
  handleActions: (
29
51
  actions: ActionType[],
30
- entry: ZappEntry
52
+ context: Record<string, any>
53
+ ) => Promise<ActionResult>;
54
+ handleEntryActions: (
55
+ entry: ZappEntry,
56
+ context?: Record<string, any>
31
57
  ) => Promise<ActionResult>;
32
- handleEntryActions: (entry: ZappEntry) => Promise<ActionResult>;
33
58
  };
34
59
  type Props = {
35
60
  children: React.ReactNode;
36
61
  };
37
62
 
63
+ function findParentComponent(
64
+ childId: string,
65
+ parent: ZappRiver | ZappUIComponent
66
+ ): ZappRiver | ZappUIComponent | null {
67
+ for (const child of parent.ui_components) {
68
+ if (child.id === childId) return parent;
69
+
70
+ if (child.ui_components) {
71
+ const found = findParentComponent(childId, child);
72
+ if (found) return found;
73
+ }
74
+ }
75
+
76
+ return null;
77
+ }
78
+
79
+ // send all data just in case (like for message string formatting)
80
+ // Type is not exported for now
81
+ type MaxTagsReachedEvent = {
82
+ selectedItems: string[];
83
+ maxItems: number;
84
+ tag: string;
85
+ keyNamespace: string;
86
+ };
87
+
88
+ async function onMaxTagsReached(data: MaxTagsReachedEvent) {
89
+ postEvent(TOGGLE_FLAG_MAX_ITEMS_REACHED_EVENT, [data]);
90
+ }
91
+
38
92
  const prepareDefaultActions = (actionExecutor) => {
39
93
  actionExecutor.registerAction("localStorageSet", async (action) => {
40
94
  const namespaces = action.options.content;
@@ -44,6 +98,46 @@ const prepareDefaultActions = (actionExecutor) => {
44
98
  return ActionResult.Success;
45
99
  });
46
100
 
101
+ actionExecutor.registerAction(
102
+ "refreshComponent",
103
+ async (_action, context) => {
104
+ const dispatch = appStore.getDispatch();
105
+
106
+ const dataSource =
107
+ context?.component?.data?.source ||
108
+ findParentComponent(context?.component.id, context?.screenData)?.data
109
+ ?.source;
110
+
111
+ log_info(`handleAction: refreshComponent for dataSource:${dataSource}`);
112
+
113
+ // TODO: In theory we should wait callback to complete, before completing the action, but now it's not needed
114
+ // TODO: handle focused item removal
115
+ dispatch(
116
+ loadPipesData(dataSource, {
117
+ silentRefresh: false,
118
+ clearCache: true,
119
+ callback: (_data) => {},
120
+ riverId: context?.screenData?.id,
121
+ })
122
+ );
123
+
124
+ return ActionResult.Success;
125
+ }
126
+ );
127
+
128
+ actionExecutor.registerAction("switchLayout", async (action) => {
129
+ log_info("handleAction: switchLayout event");
130
+
131
+ await localStorage.setItem(
132
+ ACTIVE_LAYOUT_ID_STORAGE_KEY,
133
+ action.options.layoutId
134
+ );
135
+
136
+ QuickBrickManager.sendQuickBrickEvent(QUICK_BRICK_EVENTS.FORCE_APP_RELOAD);
137
+
138
+ return ActionResult.Success;
139
+ });
140
+
47
141
  actionExecutor.registerAction("appRestart", async () => {
48
142
  log_info(`handleAction: ${QUICK_BRICK_EVENTS.FORCE_APP_RELOAD} event`);
49
143
 
@@ -66,13 +160,21 @@ const prepareDefaultActions = (actionExecutor) => {
66
160
  return confirmationPromise;
67
161
  });
68
162
 
69
- actionExecutor.registerAction("sendCloudEvent", async (action, entry) => {
163
+ actionExecutor.registerAction("sendCloudEvent", async (action, context) => {
70
164
  try {
71
165
  const options = action.options;
72
166
 
167
+ const entry = context?.entry || {};
168
+ const entryResolver = new EntryResolver(entry);
169
+
170
+ const data =
171
+ options?.data && options.inflateData
172
+ ? await resolveObjectValues(options.data, { entry: entryResolver })
173
+ : options?.data || entry;
174
+
73
175
  const cloudEvent = await createCloudEvent({
74
176
  type: options.type || "com.applicaster.selector.action.v1",
75
- data: options.data || entry,
177
+ data,
76
178
  subject: options.subject || entry?.id,
77
179
  });
78
180
 
@@ -103,9 +205,33 @@ const prepareDefaultActions = (actionExecutor) => {
103
205
 
104
206
  actionExecutor.registerAction(
105
207
  "localStorageToggleFlag",
106
- async (action: ActionType, entry?: ZappEntry): Promise<ActionResult> => {
208
+ async (
209
+ action: ActionType,
210
+ context?: Record<string, any>
211
+ ): Promise<ActionResult> => {
212
+ if (!context) {
213
+ log_error(
214
+ "handleAction: localStorageToggleFlag action missing context"
215
+ );
216
+
217
+ return ActionResult.Error;
218
+ }
219
+
220
+ const entry = context?.entry as ZappEntry;
221
+
222
+ if (!entry) {
223
+ log_error(
224
+ "handleAction: localStorageToggleFlag action missing entry. Entry is required to get the tag."
225
+ );
226
+
227
+ return ActionResult.Error;
228
+ }
229
+
230
+ const tag = action.options?.selector
231
+ ? get(entry, action.options.selector)
232
+ : (entry.extensions?.tag ?? entry.id);
233
+
107
234
  const keyNamespace = action.options?.key;
108
- const tag = entry?.extensions?.tag;
109
235
 
110
236
  if (keyNamespace && tag) {
111
237
  const multiSelectProvider =
@@ -123,6 +249,23 @@ const prepareDefaultActions = (actionExecutor) => {
123
249
  if (selectedItems.includes(tag)) {
124
250
  await multiSelectProvider.removeItem(tag);
125
251
  } else {
252
+ const maxItems = action.options?.max_items;
253
+
254
+ if (maxItems && selectedItems.length >= maxItems) {
255
+ log_info(
256
+ `handleAction: localStorageToggleFlag event reached max items limit: ${maxItems}, cannot add tag: ${tag}`
257
+ );
258
+
259
+ await onMaxTagsReached({
260
+ selectedItems,
261
+ maxItems,
262
+ tag,
263
+ keyNamespace,
264
+ });
265
+
266
+ return ActionResult.Cancel;
267
+ }
268
+
126
269
  await multiSelectProvider.addItem(tag);
127
270
  }
128
271
  } else {
@@ -146,6 +289,10 @@ export function withActionExecutor(Component) {
146
289
  prepareDefaultActions(_actionExecutor);
147
290
 
148
291
  return function ActionExecutorComponent(props: Props) {
292
+ const navigator = useNavigation();
293
+ const { rivers } = usePickFromState(["rivers"]);
294
+ const contentTypes = useContentTypes();
295
+
149
296
  const handlers = useMemo(() => {
150
297
  return {
151
298
  unregisterAction: _actionExecutor.unregisterAction,
@@ -156,6 +303,44 @@ export function withActionExecutor(Component) {
156
303
  };
157
304
  }, []);
158
305
 
306
+ useEffect(() => {
307
+ return _actionExecutor.registerAction(
308
+ "navigateToScreen",
309
+ async (action: ActionType, context?: Record<string, any>) => {
310
+ const screenType = action.options?.typeMapping;
311
+
312
+ if (!screenType) {
313
+ log_error("navigateToScreen: typeMapping option is missing");
314
+
315
+ return ActionResult.Error;
316
+ }
317
+
318
+ const screenId = contentTypes?.[screenType]?.screen_id || null;
319
+
320
+ if (!screenId) {
321
+ log_error(
322
+ `navigateToScreen: can not resolve screen type mapping: ${screenType}`
323
+ );
324
+
325
+ return ActionResult.Error;
326
+ }
327
+
328
+ const river = rivers[screenId];
329
+
330
+ if (!river) {
331
+ log_error("navigateToScreen: can not resolve river");
332
+
333
+ return ActionResult.Error;
334
+ }
335
+
336
+ context?.callback?.({ success: false, error: null, abort: true });
337
+ navigator.replace(river);
338
+
339
+ return ActionResult.Success;
340
+ }
341
+ );
342
+ }, [navigator, rivers, contentTypes]);
343
+
159
344
  return (
160
345
  <ActionExecutorContext.Provider value={handlers}>
161
346
  <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"
@@ -1,148 +1 @@
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"
1
+ export { showAlertDialog, showConfirmationDialog } from "./alert";