@applicaster/zapp-react-native-utils 16.0.0-alpha.9225550512 → 16.0.0-alpha.9338540010
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/actionUtils/index.ts +3 -1
- package/actionsExecutor/ActionExecutor.ts +50 -3
- package/actionsExecutor/ActionExecutorContext.tsx +99 -17
- package/actionsExecutor/__tests__/ActionExecutor.test.ts +71 -0
- package/actionsExecutor/__tests__/feedDecorator.test.ts +61 -0
- package/actionsExecutor/actions/__tests__/dismissBottomSheet.test.ts +25 -0
- package/actionsExecutor/actions/__tests__/goBack.test.ts +62 -0
- package/actionsExecutor/actions/__tests__/goHome.test.ts +19 -0
- package/actionsExecutor/actions/__tests__/loadItemsFromSource.test.ts +88 -0
- package/actionsExecutor/actions/__tests__/navigateToScreen.test.ts +267 -0
- package/actionsExecutor/actions/__tests__/openBottomSheet.customContent.test.ts +100 -0
- package/actionsExecutor/actions/__tests__/openBottomSheet.inlineItems.test.ts +300 -0
- package/actionsExecutor/actions/__tests__/presentScreen.test.ts +127 -0
- package/actionsExecutor/actions/__tests__/showAlert.test.ts +49 -0
- package/actionsExecutor/actions/__tests__/showToast.test.ts +88 -0
- package/actionsExecutor/actions/dismissBottomSheet.ts +23 -0
- package/actionsExecutor/actions/goBack.ts +60 -0
- package/actionsExecutor/actions/goHome.ts +31 -0
- package/actionsExecutor/actions/index.ts +12 -0
- package/actionsExecutor/actions/navigateToScreen.ts +43 -45
- package/actionsExecutor/actions/openBottomSheet.ts +339 -0
- package/actionsExecutor/actions/presentScreen.ts +78 -0
- package/actionsExecutor/actions/refreshComponent.ts +6 -0
- package/actionsExecutor/actions/sendCloudEvent.ts +6 -1
- package/actionsExecutor/actions/showAlert.ts +51 -0
- package/actionsExecutor/actions/showToast.ts +64 -8
- package/actionsExecutor/consts.ts +27 -0
- package/actionsExecutor/feedDecorator.ts +6 -6
- package/analyticsUtils/PlayerAnalyticsManager.ts +1 -1
- package/appUtils/HooksManager/index.ts +9 -0
- package/appUtils/playerManager/OverlayObserver/OverlaysObserver.ts +142 -59
- package/appUtils/playerManager/OverlayObserver/__tests__/getUpcomingQueue.test.ts +67 -0
- package/appUtils/playerManager/OverlayObserver/__tests__/liveContent.test.ts +205 -0
- package/appUtils/playerManager/OverlayObserver/__tests__/utils.test.ts +56 -0
- package/appUtils/playerManager/OverlayObserver/getUpcomingQueue.android.tv.ts +4 -0
- package/appUtils/playerManager/OverlayObserver/getUpcomingQueue.ios.tv.ts +4 -0
- package/appUtils/playerManager/OverlayObserver/getUpcomingQueue.ts +24 -0
- package/appUtils/playerManager/OverlayObserver/getUpcomingQueue.web.ts +4 -0
- package/appUtils/playerManager/OverlayObserver/utils.ts +51 -20
- package/appUtils/playerManager/__tests__/playerContent.test.ts +403 -0
- package/appUtils/playerManager/__tests__/playerFactory.test.ts +1 -1
- package/appUtils/playerManager/__tests__/playerNative.test.ts +114 -0
- package/appUtils/playerManager/__tests__/playerNativeCommand.test.ts +62 -0
- package/appUtils/playerManager/__tests__/playerToolbox.test.ts +97 -0
- package/appUtils/playerManager/__tests__/usePlayerContent.test.tsx +64 -0
- package/appUtils/playerManager/__tests__/usePlayerControllerSetup.test.tsx +62 -0
- package/appUtils/playerManager/{conts.ts → const.ts} +33 -0
- package/appUtils/playerManager/index.ts +8 -1
- package/appUtils/playerManager/player.ts +125 -3
- package/appUtils/playerManager/playerFactory.ts +1 -1
- package/appUtils/playerManager/playerNative.ts +28 -4
- package/appUtils/playerManager/playerNativeCommand.ts +3 -6
- package/appUtils/playerManager/playerToolbox.ts +157 -0
- package/appUtils/playerManager/usePlayerContent.tsx +43 -0
- package/appUtils/playerManager/usePlayerControllerSetup.tsx +7 -1
- package/appUtils/playerManager/userLanguagePreference.ts +1 -1
- package/arrayUtils/__tests__/{anyThruthy.test.ts → anyTruthy.test.ts} +8 -0
- package/arrayUtils/__tests__/arrayUtils.test.ts +165 -108
- package/arrayUtils/__tests__/isEmptyArray.test.ts +11 -0
- package/arrayUtils/__tests__/isFilledArray.test.ts +12 -0
- package/arrayUtils/__tests__/isFirst.test.ts +17 -0
- package/arrayUtils/__tests__/isIndexInRange.test.ts +14 -0
- package/arrayUtils/__tests__/isLast.test.ts +31 -0
- package/arrayUtils/__tests__/makeListOf.test.ts +31 -0
- package/arrayUtils/__tests__/makeListOfIndexes.test.ts +20 -0
- package/arrayUtils/__tests__/reorderByIds.test.ts +63 -0
- package/arrayUtils/__tests__/sample.test.ts +61 -0
- package/arrayUtils/index.ts +119 -20
- package/bottomSheet/__tests__/scrollContext.test.tsx +35 -0
- package/bottomSheet/index.ts +17 -0
- package/cellUtils/__tests__/getButtonsEnabled.test.ts +28 -0
- package/cellUtils/__tests__/getCellNavigationEnabled.test.ts +36 -0
- package/cellUtils/__tests__/getIsCellNavigationEnabled.test.ts +35 -0
- package/cellUtils/__tests__/isCellNavigationEnabled.test.ts +21 -0
- package/cellUtils/index.ts +70 -3
- package/configurationUtils/__tests__/manifestKeyParser.test.ts +21 -0
- package/configurationUtils/__tests__/modalBlocksParser.test.ts +392 -0
- package/configurationUtils/manifestKeyParser.ts +50 -10
- package/configurationUtils/modalBlocksParser.ts +252 -0
- package/entryActions/__tests__/buildEntryActions.test.ts +235 -0
- package/entryActions/aliasPresentation.ts +108 -0
- package/entryActions/buildEntryActions.ts +167 -0
- package/entryActions/index.ts +15 -0
- package/entryActions/types.ts +39 -0
- package/focusManager/FocusManager.ts +26 -0
- package/focusManager/__tests__/FocusManager.test.ts +9 -0
- package/localizationUtils/index.ts +12 -6
- package/logger/__tests__/xrayToolbox.test.ts +69 -0
- package/logger/xrayToolbox.ts +67 -0
- package/manifestUtils/__tests__/player.audioControls.test.js +158 -0
- package/manifestUtils/_internals/index.js +8 -3
- package/manifestUtils/defaultManifestConfigurations/generalContent.js +6 -0
- package/manifestUtils/defaultManifestConfigurations/player.js +342 -5
- package/manifestUtils/index.js +3 -0
- package/manifestUtils/keys.js +6 -1
- package/manifestUtils/mobileAction/container/__tests__/mobileActionButtonsContainer.test.js +21 -0
- package/manifestUtils/mobileAction/groups/__tests__/buildMobileActionButtonGroups.test.js +1 -1
- package/manifestUtils/mobileAction/groups/defaults.js +2 -1
- package/manifestUtils/modalBlocks.js +304 -0
- package/modalState/ContentViewModel.ts +113 -0
- package/modalState/EditableCollection.ts +17 -0
- package/modalState/EditableCollectionRegistry.ts +51 -0
- package/modalState/ModalOrchestrator.ts +212 -0
- package/modalState/RemoteEditableCollection.ts +235 -0
- package/modalState/__tests__/ContentViewModel.editable.test.ts +69 -0
- package/modalState/__tests__/ContentViewModel.test.ts +165 -0
- package/modalState/__tests__/EditableCollectionRegistry.test.ts +112 -0
- package/modalState/__tests__/ModalOrchestrator.phase3.test.ts +63 -0
- package/modalState/__tests__/RemoteEditableCollection.test.ts +415 -0
- package/modalState/__tests__/index.test.ts +30 -1
- package/modalState/__tests__/useBottomSheetContent.test.ts +349 -0
- package/modalState/__tests__/useModalStoreState.test.ts +142 -0
- package/modalState/index.ts +35 -83
- package/modalState/store.ts +109 -0
- package/modalState/types.ts +162 -0
- package/modalState/useBottomSheetContent.ts +109 -0
- package/navigationUtils/xrayNavigator.ts +12 -0
- package/numberUtils/__tests__/isMinusZero.test.ts +20 -0
- package/numberUtils/__tests__/isZero.test.ts +27 -0
- package/numberUtils/__tests__/requireNumber.test.ts +50 -0
- package/numberUtils/__tests__/toNumber.test.ts +27 -0
- package/numberUtils/__tests__/toNumberWithDefault.test.ts +64 -0
- package/numberUtils/__tests__/toNumberWithDefaultZero.test.ts +48 -0
- package/numberUtils/index.ts +27 -8
- package/package.json +3 -2
- package/playerUtils/__tests__/contentDataKeys.test.ts +297 -0
- package/playerUtils/__tests__/resolvePlayerActions.test.ts +138 -0
- package/playerUtils/__tests__/resolvePlayerTitleSubtitle.test.ts +180 -0
- package/playerUtils/contentDataKeys.ts +134 -0
- package/playerUtils/index.ts +37 -16
- package/playerUtils/isAudioItem.ts +26 -0
- package/playerUtils/resolvePlayerActions.ts +71 -0
- package/playerUtils/resolvePlayerTitleSubtitle.ts +76 -0
- package/pluginUtils/__tests__/pluginUtils.test.js +32 -0
- package/pluginUtils/index.ts +29 -0
- package/quickBrickAssets/__tests__/index.test.ts +18 -0
- package/quickBrickAssets/index.ts +35 -0
- package/reactHooks/__tests__/getPluginConfiguration.test.ts +82 -0
- package/reactHooks/actions/index.ts +67 -2
- package/reactHooks/cell-click/__tests__/index.test.js +64 -0
- package/reactHooks/cell-click/index.ts +21 -14
- package/reactHooks/connection/index.tsx +8 -5
- package/reactHooks/feed/__tests__/useInflatedUrl.test.tsx +25 -0
- package/reactHooks/feed/__tests__/useMarkPipesDataStale.test.tsx +243 -0
- package/reactHooks/feed/useMarkPipesDataStale.ts +68 -23
- package/reactHooks/index.ts +2 -0
- package/reactHooks/layout/index.ts +1 -1
- package/reactHooks/navigation/__tests__/index.test.tsx +176 -1
- package/reactHooks/navigation/__tests__/usePresentScreen.test.ts +154 -0
- package/reactHooks/navigation/index.ts +2 -0
- package/reactHooks/navigation/usePresentScreen.ts +157 -0
- package/reactHooks/navigation/useRoute.ts +22 -5
- package/reactHooks/usePluginConfiguration.ts +88 -47
- package/reactHooks/utils/__tests__/index.test.js +22 -2
- package/reactHooks/utils/index.ts +11 -1
- package/riverComponetsMeasurementProvider/index.tsx +3 -1
- package/stringUtils/__tests__/stringUtils.test.js +42 -0
- package/stringUtils/index.ts +2 -2
- package/uiActionsRegistrator/__tests__/resolveActionIdentifiers.test.ts +93 -0
- package/uiActionsRegistrator/__tests__/subscribe.test.ts +133 -0
- package/uiActionsRegistrator/__tests__/usableActionItems.test.ts +52 -0
- package/uiActionsRegistrator/index.ts +25 -203
- package/uiActionsRegistrator/registry.ts +351 -0
- package/uiActionsRegistrator/resolveActionIdentifiers.ts +100 -0
- package/uiActionsRegistrator/usableActionItems.ts +66 -0
- package/zappFrameworkUtils/__tests__/localStorageHelper.test.ts +146 -0
- package/zappFrameworkUtils/localStorageHelper.ts +19 -15
- package/appUtils/playerManager/usePlayerTitleSummaryOverlay.tsx +0 -56
- package/playerUtils/__tests__/getPlayerActionButtons.test.ts +0 -54
- package/playerUtils/getPlayerActionButtons.ts +0 -17
- /package/reactHooks/actions/__tests__/{index.test.js → index.test.tsx} +0 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { createPresentScreenAction } from "../presentScreen";
|
|
2
|
+
import { ActionResult } from "../../ActionExecutor";
|
|
3
|
+
|
|
4
|
+
const contextEntry = { id: "context-entry" } as any;
|
|
5
|
+
|
|
6
|
+
const succeeded = { success: true, cancelled: false };
|
|
7
|
+
|
|
8
|
+
const cancelled = { success: false, cancelled: true };
|
|
9
|
+
|
|
10
|
+
describe("presentScreenAction", () => {
|
|
11
|
+
let presentScreen: jest.Mock;
|
|
12
|
+
let presentScreenAction: ReturnType<typeof createPresentScreenAction>;
|
|
13
|
+
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
presentScreen = jest.fn().mockResolvedValue(succeeded);
|
|
16
|
+
presentScreenAction = createPresentScreenAction(presentScreen);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("presents the screen named by typeMapping", async () => {
|
|
20
|
+
await presentScreenAction({
|
|
21
|
+
type: "presentScreen",
|
|
22
|
+
options: { typeMapping: "parent_lock" },
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
expect(presentScreen).toHaveBeenCalledWith({
|
|
26
|
+
typeMapping: "parent_lock",
|
|
27
|
+
entry: undefined,
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("fails without presenting anything when typeMapping is missing", async () => {
|
|
32
|
+
const result = await presentScreenAction({
|
|
33
|
+
type: "presentScreen",
|
|
34
|
+
options: {},
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
expect(result).toBe(ActionResult.Error);
|
|
38
|
+
expect(presentScreen).not.toHaveBeenCalled();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("resolves the '@{entry/}' token to the entry from the execution context", async () => {
|
|
42
|
+
await presentScreenAction(
|
|
43
|
+
{
|
|
44
|
+
type: "presentScreen",
|
|
45
|
+
options: { typeMapping: "parent_lock", entry: "@{entry/}" },
|
|
46
|
+
},
|
|
47
|
+
{ entry: contextEntry }
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
expect(presentScreen).toHaveBeenCalledWith({
|
|
51
|
+
typeMapping: "parent_lock",
|
|
52
|
+
entry: contextEntry,
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("presents an entry supplied inline in the options", async () => {
|
|
57
|
+
const inlineEntry = { id: "inline-entry" } as any;
|
|
58
|
+
|
|
59
|
+
await presentScreenAction({
|
|
60
|
+
type: "presentScreen",
|
|
61
|
+
options: { typeMapping: "parent_lock", entry: inlineEntry },
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
expect(presentScreen).toHaveBeenCalledWith({
|
|
65
|
+
typeMapping: "parent_lock",
|
|
66
|
+
entry: inlineEntry,
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("fails without presenting anything when the entry option is not an object", async () => {
|
|
71
|
+
const result = await presentScreenAction({
|
|
72
|
+
type: "presentScreen",
|
|
73
|
+
options: { typeMapping: "parent_lock", entry: "not-an-entry" as any },
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
expect(result).toBe(ActionResult.Error);
|
|
77
|
+
expect(presentScreen).not.toHaveBeenCalled();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("succeeds when the presented screen reports success", async () => {
|
|
81
|
+
presentScreen.mockResolvedValue(succeeded);
|
|
82
|
+
|
|
83
|
+
const result = await presentScreenAction({
|
|
84
|
+
type: "presentScreen",
|
|
85
|
+
options: { typeMapping: "parent_lock" },
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
expect(result).toBe(ActionResult.Success);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("cancels the action chain when the presented screen is cancelled", async () => {
|
|
92
|
+
presentScreen.mockResolvedValue(cancelled);
|
|
93
|
+
|
|
94
|
+
const result = await presentScreenAction({
|
|
95
|
+
type: "presentScreen",
|
|
96
|
+
options: { typeMapping: "parent_lock" },
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
expect(result).toBe(ActionResult.Cancel);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it("cancels the action chain when the presented screen reports failure", async () => {
|
|
103
|
+
presentScreen.mockResolvedValue({ success: false, cancelled: false });
|
|
104
|
+
|
|
105
|
+
const result = await presentScreenAction({
|
|
106
|
+
type: "presentScreen",
|
|
107
|
+
options: { typeMapping: "parent_lock" },
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
expect(result).toBe(ActionResult.Cancel);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("errors when the screen could not be presented at all", async () => {
|
|
114
|
+
presentScreen.mockResolvedValue({
|
|
115
|
+
success: false,
|
|
116
|
+
cancelled: false,
|
|
117
|
+
error: "can not resolve screen type mapping: parent_lock",
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
const result = await presentScreenAction({
|
|
121
|
+
type: "presentScreen",
|
|
122
|
+
options: { typeMapping: "parent_lock" },
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
expect(result).toBe(ActionResult.Error);
|
|
126
|
+
});
|
|
127
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { showAlertAction } from "../showAlert";
|
|
2
|
+
import { ActionResult } from "../../ActionExecutor";
|
|
3
|
+
import { showAlertDialog } from "../../../alertUtils";
|
|
4
|
+
|
|
5
|
+
jest.mock("../../../alertUtils", () => ({
|
|
6
|
+
showAlertDialog: jest.fn(),
|
|
7
|
+
}));
|
|
8
|
+
|
|
9
|
+
const dialog = showAlertDialog as jest.Mock;
|
|
10
|
+
|
|
11
|
+
const dismiss = () => dialog.mock.calls[0][0].completion();
|
|
12
|
+
|
|
13
|
+
describe("showAlert", () => {
|
|
14
|
+
beforeEach(() => dialog.mockReset());
|
|
15
|
+
|
|
16
|
+
it("shows the notice and resolves once it is dismissed", async () => {
|
|
17
|
+
const result = showAlertAction({
|
|
18
|
+
type: "showAlert",
|
|
19
|
+
options: { title: "Locked", message: "Ask the account owner." },
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
expect(dialog).toHaveBeenCalledWith(
|
|
23
|
+
expect.objectContaining({
|
|
24
|
+
title: "Locked",
|
|
25
|
+
message: "Ask the account owner.",
|
|
26
|
+
okButtonText: "OK",
|
|
27
|
+
})
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
dismiss();
|
|
31
|
+
|
|
32
|
+
// Dismissing a notice is not a cancellation: the chain carries on.
|
|
33
|
+
await expect(result).resolves.toBe(ActionResult.Success);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("takes the dismiss label from the action", async () => {
|
|
37
|
+
const result = showAlertAction({
|
|
38
|
+
type: "showAlert",
|
|
39
|
+
options: { title: "Locked", okButtonText: "Got it" },
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
expect(dialog).toHaveBeenCalledWith(
|
|
43
|
+
expect.objectContaining({ okButtonText: "Got it" })
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
dismiss();
|
|
47
|
+
await result;
|
|
48
|
+
});
|
|
49
|
+
});
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { showToastAction } from "../showToast";
|
|
2
|
+
import { postEvent } from "../../../reactHooks/useSubscriberFor";
|
|
3
|
+
import { ActionResult } from "../../ActionExecutor";
|
|
4
|
+
|
|
5
|
+
jest.mock("../../../reactHooks/useSubscriberFor", () => ({
|
|
6
|
+
postEvent: jest.fn(),
|
|
7
|
+
}));
|
|
8
|
+
|
|
9
|
+
describe("showToastAction", () => {
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
jest.clearAllMocks();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("calls postEvent with confirmation source, default timeout, and returns Success", async () => {
|
|
15
|
+
const action = {
|
|
16
|
+
type: "showToast",
|
|
17
|
+
options: {
|
|
18
|
+
id: "toast-1",
|
|
19
|
+
message: "Added to queue",
|
|
20
|
+
extraMessage: "Extra info",
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const result = await showToastAction(action);
|
|
25
|
+
|
|
26
|
+
expect(postEvent).toHaveBeenCalledTimes(1);
|
|
27
|
+
|
|
28
|
+
expect(postEvent).toHaveBeenCalledWith("showToast", [
|
|
29
|
+
{
|
|
30
|
+
id: "toast-1",
|
|
31
|
+
message: "Added to queue",
|
|
32
|
+
extraMessage: "Extra info",
|
|
33
|
+
style: undefined,
|
|
34
|
+
timeout: 5000,
|
|
35
|
+
source: "confirmation",
|
|
36
|
+
},
|
|
37
|
+
]);
|
|
38
|
+
|
|
39
|
+
expect(result).toBe(ActionResult.Success);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("preserves an explicit timeout and style override", async () => {
|
|
43
|
+
const action = {
|
|
44
|
+
type: "showToast",
|
|
45
|
+
options: {
|
|
46
|
+
message: "Playlist created",
|
|
47
|
+
timeout: 3000,
|
|
48
|
+
style: { backgroundColor: "#00FF00" },
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
await showToastAction(action);
|
|
53
|
+
|
|
54
|
+
expect(postEvent).toHaveBeenCalledWith("showToast", [
|
|
55
|
+
{
|
|
56
|
+
id: undefined,
|
|
57
|
+
message: "Playlist created",
|
|
58
|
+
extraMessage: undefined,
|
|
59
|
+
style: { backgroundColor: "#00FF00" },
|
|
60
|
+
timeout: 3000,
|
|
61
|
+
source: "confirmation",
|
|
62
|
+
},
|
|
63
|
+
]);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("handles missing or empty options without throwing", async () => {
|
|
67
|
+
const action = {
|
|
68
|
+
type: "showToast",
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const result = await showToastAction(action);
|
|
72
|
+
|
|
73
|
+
expect(postEvent).toHaveBeenCalledTimes(1);
|
|
74
|
+
|
|
75
|
+
expect(postEvent).toHaveBeenCalledWith("showToast", [
|
|
76
|
+
{
|
|
77
|
+
id: undefined,
|
|
78
|
+
message: undefined,
|
|
79
|
+
extraMessage: undefined,
|
|
80
|
+
style: undefined,
|
|
81
|
+
timeout: 5000,
|
|
82
|
+
source: "confirmation",
|
|
83
|
+
},
|
|
84
|
+
]);
|
|
85
|
+
|
|
86
|
+
expect(result).toBe(ActionResult.Success);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/// <reference types="@applicaster/applicaster-types" />
|
|
2
|
+
import { dismissModal, modalOrchestrator } from "../../modalState";
|
|
3
|
+
import { ActionResult } from "../ActionExecutor";
|
|
4
|
+
import { ActionHandler } from "../types";
|
|
5
|
+
import { createLogger } from "../../logger";
|
|
6
|
+
|
|
7
|
+
const { log_info } = createLogger({
|
|
8
|
+
subsystem: "ActionExecutorContext",
|
|
9
|
+
category: "General",
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Dismisses the active bottom sheet / modal.
|
|
14
|
+
*/
|
|
15
|
+
export const dismissBottomSheetAction: ActionHandler<
|
|
16
|
+
any
|
|
17
|
+
> = async (): Promise<ActionResult> => {
|
|
18
|
+
log_info("handleAction: dismissBottomSheet");
|
|
19
|
+
modalOrchestrator.close();
|
|
20
|
+
dismissModal();
|
|
21
|
+
|
|
22
|
+
return ActionResult.Success;
|
|
23
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/// <reference types="@applicaster/applicaster-types" />
|
|
2
|
+
import { ActionResult } from "../ActionExecutor";
|
|
3
|
+
import { ActionHandler } from "../types";
|
|
4
|
+
import { createLogger } from "../../logger";
|
|
5
|
+
|
|
6
|
+
const { log_info } = createLogger({
|
|
7
|
+
subsystem: "ActionExecutorContext",
|
|
8
|
+
category: "General",
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Options for the goBack action.
|
|
13
|
+
*/
|
|
14
|
+
export interface GoBackOptions {
|
|
15
|
+
/**
|
|
16
|
+
* Navigate to the home screen when there is no screen to go back to.
|
|
17
|
+
* Defaults to true.
|
|
18
|
+
*/
|
|
19
|
+
fallbackToHome?: boolean;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Go back to the first screen of the stack instead of the previous one.
|
|
23
|
+
* Defaults to false.
|
|
24
|
+
*/
|
|
25
|
+
backToTop?: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Creates a go back action handler with the provided dependencies.
|
|
30
|
+
* This factory pattern allows the action to access navigation state at runtime.
|
|
31
|
+
*
|
|
32
|
+
* @param navigator - The app navigator performing the back navigation
|
|
33
|
+
* @returns An action handler that navigates back
|
|
34
|
+
*/
|
|
35
|
+
export function createGoBackAction(
|
|
36
|
+
navigator: QuickBrickAppNavigator
|
|
37
|
+
): ActionHandler<GoBackOptions> {
|
|
38
|
+
return async function goBackAction(action): Promise<ActionResult> {
|
|
39
|
+
const fallbackToHome = action.options?.fallbackToHome ?? true;
|
|
40
|
+
const backToTop = action.options?.backToTop ?? false;
|
|
41
|
+
|
|
42
|
+
// With fallbackToHome on, the navigator goes home on an empty stack by
|
|
43
|
+
// itself. The guard only matters when the caller opted out of that.
|
|
44
|
+
if (!fallbackToHome && !navigator.canGoBack()) {
|
|
45
|
+
log_info(
|
|
46
|
+
"goBack: no screen to go back to and fallbackToHome is disabled, ignoring"
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
return ActionResult.Error;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
log_info(
|
|
53
|
+
`goBack: navigating back, fallbackToHome: ${fallbackToHome}, backToTop: ${backToTop}`
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
navigator.goBack(fallbackToHome, false, backToTop);
|
|
57
|
+
|
|
58
|
+
return ActionResult.Success;
|
|
59
|
+
};
|
|
60
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/// <reference types="@applicaster/applicaster-types" />
|
|
2
|
+
import { ActionResult } from "../ActionExecutor";
|
|
3
|
+
import { ActionHandler } from "../types";
|
|
4
|
+
import { createLogger } from "../../logger";
|
|
5
|
+
|
|
6
|
+
const { log_info } = createLogger({
|
|
7
|
+
subsystem: "ActionExecutorContext",
|
|
8
|
+
category: "General",
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Creates a go home action handler with the provided dependencies.
|
|
13
|
+
* This factory pattern allows the action to access navigation state at runtime.
|
|
14
|
+
*
|
|
15
|
+
* The navigator's `initialLaunch` flag is intentionally not exposed: it selects
|
|
16
|
+
* the offline home river during app bootstrap and is not a per-action choice.
|
|
17
|
+
*
|
|
18
|
+
* @param navigator - The app navigator performing the navigation
|
|
19
|
+
* @returns An action handler that navigates to the home screen
|
|
20
|
+
*/
|
|
21
|
+
export function createGoHomeAction(
|
|
22
|
+
navigator: QuickBrickAppNavigator
|
|
23
|
+
): ActionHandler {
|
|
24
|
+
return async function goHomeAction(): Promise<ActionResult> {
|
|
25
|
+
log_info("goHome: navigating to the home screen");
|
|
26
|
+
|
|
27
|
+
navigator.goHome();
|
|
28
|
+
|
|
29
|
+
return ActionResult.Success;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -15,6 +15,8 @@ export { appRestartAction } from "./appRestart";
|
|
|
15
15
|
|
|
16
16
|
export { confirmDialogAction } from "./confirmDialog";
|
|
17
17
|
|
|
18
|
+
export { showAlertAction } from "./showAlert";
|
|
19
|
+
|
|
18
20
|
export { sendCloudEventAction } from "./sendCloudEvent";
|
|
19
21
|
|
|
20
22
|
export { sessionStorageToggleFlagAction } from "./sessionStorageToggleFlag";
|
|
@@ -27,4 +29,14 @@ export { screenToggleFlagAction } from "./screenToggleFlag";
|
|
|
27
29
|
|
|
28
30
|
export { createNavigateToScreenAction } from "./navigateToScreen";
|
|
29
31
|
|
|
32
|
+
export { createPresentScreenAction } from "./presentScreen";
|
|
33
|
+
|
|
34
|
+
export { createGoBackAction } from "./goBack";
|
|
35
|
+
|
|
36
|
+
export { createGoHomeAction } from "./goHome";
|
|
37
|
+
|
|
30
38
|
export { showToastAction } from "./showToast";
|
|
39
|
+
|
|
40
|
+
export { openBottomSheetAction } from "./openBottomSheet";
|
|
41
|
+
|
|
42
|
+
export { dismissBottomSheetAction } from "./dismissBottomSheet";
|
|
@@ -13,7 +13,7 @@ const { log_info, log_error } = createLogger({
|
|
|
13
13
|
*/
|
|
14
14
|
export interface NavigateToScreenOptions {
|
|
15
15
|
/** The screen type to navigate to (from content types mapping) */
|
|
16
|
-
typeMapping
|
|
16
|
+
typeMapping?: string;
|
|
17
17
|
|
|
18
18
|
/** Navigation action: push adds to history, replace replaces current screen */
|
|
19
19
|
navigationAction?: "push" | "replace";
|
|
@@ -25,6 +25,19 @@ export interface NavigateToScreenOptions {
|
|
|
25
25
|
* - undefined to navigate to screen without entry
|
|
26
26
|
*/
|
|
27
27
|
entry?: "@{entry/}" | ZappEntry;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Arbitrary values passed through to the destination screen.
|
|
31
|
+
*
|
|
32
|
+
* They are stored on the navigation route as `NavigationScreenData.options`
|
|
33
|
+
* and read on the target screen via `useNavigation().data?.options`. Use this
|
|
34
|
+
* to hand per-navigation parameters to a screen instead of routing them
|
|
35
|
+
* through module-level state.
|
|
36
|
+
*
|
|
37
|
+
* Note: `legacyScreenData()` does not carry these values, so they are not
|
|
38
|
+
* visible through `useCurrentScreenData()` / `useRoute()`.
|
|
39
|
+
*/
|
|
40
|
+
navigationOptions?: Record<string, unknown>;
|
|
28
41
|
}
|
|
29
42
|
|
|
30
43
|
/**
|
|
@@ -45,16 +58,9 @@ export function createNavigateToScreenAction(
|
|
|
45
58
|
action,
|
|
46
59
|
context?: ActionExecutionContext
|
|
47
60
|
): Promise<ActionResult> {
|
|
48
|
-
const screenType = action.options?.typeMapping;
|
|
49
|
-
|
|
50
|
-
if (!screenType) {
|
|
51
|
-
log_error("navigateToScreen: typeMapping option is missing");
|
|
52
|
-
|
|
53
|
-
return ActionResult.Error;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
61
|
const navigationAction = action.options?.navigationAction;
|
|
57
62
|
const entrySource = action.options?.entry;
|
|
63
|
+
const navigationOptions = action.options?.navigationOptions;
|
|
58
64
|
|
|
59
65
|
const entry = entrySource
|
|
60
66
|
? entrySource === "@{entry/}"
|
|
@@ -62,61 +68,53 @@ export function createNavigateToScreenAction(
|
|
|
62
68
|
: entrySource
|
|
63
69
|
: null;
|
|
64
70
|
|
|
65
|
-
|
|
66
|
-
if (typeof entry !== "object") {
|
|
67
|
-
log_error(
|
|
68
|
-
`navigateToScreen: entry option is not an object, entry: ${entry}`
|
|
69
|
-
);
|
|
71
|
+
const screenType = action.options?.typeMapping || entry?.type?.value;
|
|
70
72
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
+
const navigate =
|
|
74
|
+
navigationAction === "push" ? navigator.push : navigator.replace;
|
|
75
|
+
|
|
76
|
+
let navigatingEntry: ZappEntry | ZappRiver = entry;
|
|
73
77
|
|
|
78
|
+
if (entry && screenType) {
|
|
74
79
|
log_info(
|
|
75
80
|
`navigateToScreen: navigating to screen type: ${screenType} with entry id: ${entry.id}`
|
|
76
81
|
);
|
|
77
82
|
|
|
78
|
-
|
|
83
|
+
navigatingEntry = {
|
|
79
84
|
...entry,
|
|
80
|
-
type: {
|
|
81
|
-
value: screenType,
|
|
82
|
-
},
|
|
85
|
+
type: { value: screenType },
|
|
83
86
|
};
|
|
87
|
+
} else {
|
|
88
|
+
if (!screenType) {
|
|
89
|
+
log_error(
|
|
90
|
+
"navigateToScreen: options.typeMapping or entry?.type?.value is not provided"
|
|
91
|
+
);
|
|
84
92
|
|
|
85
|
-
|
|
86
|
-
navigator.push(overriddenEntry);
|
|
87
|
-
} else {
|
|
88
|
-
// Use replaceTop for entries since replace() only accepts ZappRiver
|
|
89
|
-
navigator.replaceTop(overriddenEntry);
|
|
93
|
+
return ActionResult.Error;
|
|
90
94
|
}
|
|
91
95
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
const screenId = contentTypes?.[screenType]?.screen_id || null;
|
|
96
|
+
const screenId = contentTypes?.[screenType]?.screen_id || null;
|
|
97
|
+
const river = rivers?.[screenId];
|
|
96
98
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
if (!screenId) {
|
|
100
|
+
log_error(
|
|
101
|
+
`navigateToScreen: can not resolve screen type mapping: ${screenType}`
|
|
102
|
+
);
|
|
101
103
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
+
return ActionResult.Error;
|
|
105
|
+
}
|
|
104
106
|
|
|
105
|
-
|
|
107
|
+
if (!river) {
|
|
108
|
+
log_error("navigateToScreen: can not resolve river");
|
|
106
109
|
|
|
107
|
-
|
|
108
|
-
|
|
110
|
+
return ActionResult.Error;
|
|
111
|
+
}
|
|
109
112
|
|
|
110
|
-
|
|
113
|
+
navigatingEntry = river;
|
|
111
114
|
}
|
|
112
115
|
|
|
113
116
|
context?.callback?.({ success: false, error: null, abort: true });
|
|
114
|
-
|
|
115
|
-
if (navigationAction === "push") {
|
|
116
|
-
navigator.push(river);
|
|
117
|
-
} else {
|
|
118
|
-
navigator.replace(river);
|
|
119
|
-
}
|
|
117
|
+
navigate(navigatingEntry, navigationOptions);
|
|
120
118
|
|
|
121
119
|
return ActionResult.Success;
|
|
122
120
|
};
|