@applicaster/zapp-react-native-utils 16.0.0-rc.53 → 16.0.0-rc.55

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.
@@ -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: 1000,
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: 1000,
82
+ source: "confirmation",
83
+ },
84
+ ]);
85
+
86
+ expect(result).toBe(ActionResult.Success);
87
+ });
88
+ });
@@ -3,12 +3,65 @@ import { ActionResult } from "../ActionExecutor";
3
3
  import { ActionHandler } from "../types";
4
4
  import { postEvent } from "../../reactHooks/useSubscriberFor";
5
5
 
6
+ export const CONFIRMATION_TOAST_SOURCE = "confirmation";
7
+
8
+ export const CONFIRMATION_TOAST_DEFAULT_TIMEOUT = 1000;
9
+
6
10
  /**
7
- * Options for showToast action.
11
+ * Shows a mobile confirmation toast with Theme defaults from
12
+ * `Confirmation Toast / Message` in the base theme plugin.
13
+ *
14
+ * This action is confirmation-only by design: it always stamps
15
+ * `source: "confirmation"` (so Theme confirmation styles apply) and defaults
16
+ * `timeout` to 1000 ms. Non-confirmation toasts (e.g. Offline Experience)
17
+ * must post on the shared `"showToast"` event bus directly and omit `source`.
18
+ * Callers may override individual style fields; Theme supplies the rest.
19
+ *
20
+ * @example From React via ActionExecutorContext
21
+ * ```tsx
22
+ * import React, { useContext } from "react";
23
+ * import { ActionExecutorContext } from "@applicaster/zapp-react-native-utils/actionsExecutor/ActionExecutorContext";
24
+ *
25
+ * function QueueButton() {
26
+ * const { handleAction } = useContext(ActionExecutorContext);
27
+ *
28
+ * const onPress = () => {
29
+ * void handleAction({
30
+ * type: "showToast",
31
+ * options: { message: "Added to queue" },
32
+ * });
33
+ * };
34
+ *
35
+ * return <Button onPress={onPress} title="Add to queue" />;
36
+ * }
37
+ * ```
38
+ *
39
+ * @example From code via the actionExecutor singleton
40
+ * ```ts
41
+ * import { actionExecutor } from "@applicaster/zapp-react-native-utils/actionsExecutor/ActionExecutor";
42
+ *
43
+ * await actionExecutor.handleAction({
44
+ * type: "showToast",
45
+ * options: {
46
+ * message: "Playlist created",
47
+ * style: { backgroundColor: "#00AA55" }, // optional partial override
48
+ * },
49
+ * });
50
+ * ```
51
+ *
52
+ * @example From entry / pipes actions JSON
53
+ * ```json
54
+ * {
55
+ * "type": "showToast",
56
+ * "options": {
57
+ * "message": "Item removed from playlist"
58
+ * }
59
+ * }
60
+ * ```
8
61
  */
9
62
  export interface ShowToastActionOptions {
10
- id: string;
11
- message: string;
63
+ id?: string;
64
+ message?: string;
12
65
  extraMessage?: string;
13
66
  style?: any;
14
67
  timeout?: number;
@@ -17,13 +70,16 @@ export interface ShowToastActionOptions {
17
70
  export const showToastAction: ActionHandler<ShowToastActionOptions> = async (
18
71
  action
19
72
  ): Promise<ActionResult> => {
73
+ const options = action?.options;
74
+
20
75
  postEvent("showToast", [
21
76
  {
22
- id: action.options.id,
23
- message: action.options.message,
24
- extraMessage: action.options.extraMessage,
25
- style: action.options.style,
26
- timeout: action.options.timeout,
77
+ id: options?.id,
78
+ message: options?.message,
79
+ extraMessage: options?.extraMessage,
80
+ style: options?.style,
81
+ timeout: options?.timeout ?? CONFIRMATION_TOAST_DEFAULT_TIMEOUT,
82
+ source: CONFIRMATION_TOAST_SOURCE,
27
83
  },
28
84
  ]);
29
85
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-native-utils",
3
- "version": "16.0.0-rc.53",
3
+ "version": "16.0.0-rc.55",
4
4
  "description": "Applicaster Zapp React Native utilities package",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -27,7 +27,7 @@
27
27
  },
28
28
  "homepage": "https://github.com/applicaster/quickbrick#readme",
29
29
  "dependencies": {
30
- "@applicaster/applicaster-types": "16.0.0-rc.53",
30
+ "@applicaster/applicaster-types": "16.0.0-rc.55",
31
31
  "buffer": "^5.2.1",
32
32
  "camelize": "^1.0.0",
33
33
  "dayjs": "^1.11.10",
@@ -59,6 +59,8 @@ export async function batchSave(
59
59
  return false;
60
60
  }
61
61
 
62
+ const promises = [];
63
+
62
64
  for (const namespace of Object.keys(storageValues)) {
63
65
  const namespaceData = storageValues[namespace];
64
66
 
@@ -66,10 +68,12 @@ export async function batchSave(
66
68
  const value = namespaceData[key];
67
69
 
68
70
  if (!isNilOrEmpty(value)) {
69
- await storage.setItem(key, value, namespace);
71
+ promises.push(storage.setItem(key, value, namespace));
70
72
  }
71
73
  }
72
74
  }
75
+
76
+ await Promise.all(promises);
73
77
  }
74
78
 
75
79
  export async function batchSaveToLocalStorage(
@@ -82,13 +86,17 @@ export async function batchRemoveFromStorage(
82
86
  storageValues: StorageValuesToRemove,
83
87
  storage: Storage = localStorage
84
88
  ) {
89
+ const promises = [];
90
+
85
91
  for (const namespace of Object.keys(storageValues)) {
86
92
  const namespaceData = storageValues[namespace];
87
93
 
88
94
  for (const key of namespaceData) {
89
- await storage.removeItem(key, namespace);
95
+ promises.push(storage.removeItem(key, namespace));
90
96
  }
91
97
  }
98
+
99
+ await Promise.all(promises);
92
100
  }
93
101
 
94
102
  export async function batchRemoveFromLocalStorage(