@jobber/components-native 0.44.2 → 0.45.0

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 (150) hide show
  1. package/dist/package.json +88 -0
  2. package/dist/src/AtlantisContext/AtlantisContext.js +1 -0
  3. package/dist/src/BottomSheet/BottomSheet.js +3 -4
  4. package/dist/src/ButtonGroup/ButtonGroup.js +3 -4
  5. package/dist/src/ButtonGroup/utils.js +4 -5
  6. package/dist/src/ContentOverlay/ContentOverlay.js +3 -4
  7. package/dist/src/Form/components/FormErrorBanner/FormErrorBanner.js +5 -13
  8. package/dist/src/Form/components/FormMask/FormMask.js +3 -4
  9. package/dist/src/Form/components/FormMessage/components/InternalFormMessage/InternalFormMessage.js +4 -5
  10. package/dist/src/Form/components/FormSaveButton/FormSaveButton.js +4 -5
  11. package/dist/src/Form/hooks/useOfflineHandler.js +6 -7
  12. package/dist/src/FormatFile/FormatFile.js +3 -4
  13. package/dist/src/FormatFile/components/FileView/FileView.js +3 -3
  14. package/dist/src/FormatFile/components/FormatFileBottomSheet/FormatFileBottomSheet.js +6 -7
  15. package/dist/src/FormatFile/components/MediaView/MediaView.js +3 -3
  16. package/dist/src/FormatFile/utils/computeA11yLabel.js +4 -5
  17. package/dist/src/InputCurrency/InputCurrency.js +3 -3
  18. package/dist/src/InputDate/InputDate.js +4 -5
  19. package/dist/src/InputFieldWrapper/components/ClearAction/ClearAction.js +3 -4
  20. package/dist/src/InputFieldWrapper/components/ClearAction/index.js +0 -1
  21. package/dist/src/InputNumber/InputNumber.js +3 -4
  22. package/dist/src/InputPassword/InputPassword.js +3 -4
  23. package/dist/src/InputTime/InputTime.js +3 -4
  24. package/dist/src/Menu/Menu.js +3 -4
  25. package/dist/src/ProgressBar/ProgressBar.js +14 -8
  26. package/dist/src/Select/Select.js +5 -6
  27. package/dist/src/Select/components/SelectDefaultPicker/SelectDefaultPicker.ios.js +3 -4
  28. package/dist/src/Toast/Toast.js +4 -5
  29. package/dist/src/hooks/useAtlantisI18n/index.js +1 -0
  30. package/dist/src/hooks/useAtlantisI18n/locales/en.json +31 -0
  31. package/dist/src/hooks/useAtlantisI18n/locales/es.json +31 -0
  32. package/dist/src/hooks/useAtlantisI18n/useAtlantisI18n.js +22 -0
  33. package/dist/tsconfig.json +38 -0
  34. package/dist/tsconfig.tsbuildinfo +1 -1
  35. package/dist/types/src/AtlantisContext/AtlantisContext.d.ts +8 -0
  36. package/dist/types/src/FormatFile/utils/computeA11yLabel.d.ts +6 -6
  37. package/dist/types/src/InputFieldWrapper/components/ClearAction/index.d.ts +0 -1
  38. package/dist/types/src/hooks/useAtlantisI18n/index.d.ts +1 -0
  39. package/dist/types/src/hooks/useAtlantisI18n/useAtlantisI18n.d.ts +6 -0
  40. package/package.json +2 -2
  41. package/src/AtlantisContext/AtlantisContext.tsx +10 -0
  42. package/src/BottomSheet/BottomSheet.test.tsx +3 -4
  43. package/src/BottomSheet/BottomSheet.tsx +3 -4
  44. package/src/ButtonGroup/ButtonGroup.test.tsx +8 -9
  45. package/src/ButtonGroup/ButtonGroup.tsx +3 -4
  46. package/src/ButtonGroup/utils.ts +5 -6
  47. package/src/ContentOverlay/ContentOverlay.test.tsx +1 -11
  48. package/src/ContentOverlay/ContentOverlay.tsx +5 -9
  49. package/src/Form/Form.test.tsx +9 -40
  50. package/src/Form/components/FormErrorBanner/FormErrorBanner.test.tsx +9 -72
  51. package/src/Form/components/FormErrorBanner/FormErrorBanner.tsx +6 -15
  52. package/src/Form/components/FormMask/FormMask.tsx +3 -7
  53. package/src/Form/components/FormMessage/components/InternalFormMessage/InternalFormMessage.tsx +4 -5
  54. package/src/Form/components/FormSaveButton/FormSaveButton.test.tsx +3 -7
  55. package/src/Form/components/FormSaveButton/FormSaveButton.tsx +4 -5
  56. package/src/Form/hooks/useOfflineHandler.ts +7 -8
  57. package/src/FormatFile/FormatFile.test.tsx +7 -31
  58. package/src/FormatFile/FormatFile.tsx +3 -7
  59. package/src/FormatFile/components/FileView/FileView.tsx +3 -3
  60. package/src/FormatFile/components/FormatFileBottomSheet/FormatFileBottomSheet.test.tsx +2 -9
  61. package/src/FormatFile/components/FormatFileBottomSheet/FormatFileBottomSheet.tsx +6 -7
  62. package/src/FormatFile/components/MediaView/MediaView.tsx +3 -3
  63. package/src/FormatFile/utils/computeA11yLabel.ts +9 -12
  64. package/src/InputCurrency/InputCurrency.test.tsx +6 -1
  65. package/src/InputCurrency/InputCurrency.tsx +3 -3
  66. package/src/InputDate/InputDate.tsx +6 -5
  67. package/src/InputFieldWrapper/InputFieldWrapper.test.tsx +4 -15
  68. package/src/InputFieldWrapper/components/ClearAction/ClearAction.test.tsx +1 -5
  69. package/src/InputFieldWrapper/components/ClearAction/ClearAction.tsx +3 -4
  70. package/src/InputFieldWrapper/components/ClearAction/index.ts +0 -1
  71. package/src/InputNumber/InputNumber.test.tsx +10 -18
  72. package/src/InputNumber/InputNumber.tsx +3 -4
  73. package/src/InputPassword/InputPassword.test.tsx +1 -2
  74. package/src/InputPassword/InputPassword.tsx +3 -4
  75. package/src/InputSearch/InputSearch.test.tsx +1 -6
  76. package/src/InputText/InputText.test.tsx +10 -38
  77. package/src/InputTime/InputTime.tsx +3 -4
  78. package/src/Menu/Menu.test.tsx +10 -9
  79. package/src/Menu/Menu.tsx +3 -4
  80. package/src/ProgressBar/ProgressBar.tsx +17 -8
  81. package/src/Select/Select.test.tsx +4 -5
  82. package/src/Select/Select.tsx +5 -8
  83. package/src/Select/components/SelectDefaultPicker/SelectDefaultPicker.ios.tsx +3 -4
  84. package/src/Select/components/SelectDefaultPicker/SelectDefaultPicker.test.tsx +1 -2
  85. package/src/Toast/Toast.tsx +4 -9
  86. package/src/hooks/useAtlantisI18n/index.ts +1 -0
  87. package/src/hooks/useAtlantisI18n/locales/en.json +31 -0
  88. package/src/hooks/useAtlantisI18n/locales/es.json +31 -0
  89. package/src/hooks/useAtlantisI18n/useAtlantisI18n.test.ts +53 -0
  90. package/src/hooks/useAtlantisI18n/useAtlantisI18n.ts +43 -0
  91. package/dist/src/BottomSheet/messages.js +0 -8
  92. package/dist/src/ButtonGroup/messages.js +0 -18
  93. package/dist/src/ContentOverlay/messages.js +0 -8
  94. package/dist/src/Form/components/FormErrorBanner/messages.js +0 -13
  95. package/dist/src/Form/components/FormMessage/components/InternalFormMessage/messages.js +0 -8
  96. package/dist/src/Form/components/FormSaveButton/messages.js +0 -8
  97. package/dist/src/Form/messages.js +0 -28
  98. package/dist/src/FormatFile/components/FormatFileBottomSheet/messages.js +0 -13
  99. package/dist/src/FormatFile/messages.js +0 -23
  100. package/dist/src/InputCurrency/messages.js +0 -8
  101. package/dist/src/InputDate/messages.js +0 -8
  102. package/dist/src/InputFieldWrapper/components/ClearAction/messages.js +0 -8
  103. package/dist/src/InputNumber/messages.js +0 -8
  104. package/dist/src/InputPassword/messages.js +0 -8
  105. package/dist/src/InputTime/messages.js +0 -8
  106. package/dist/src/Menu/messages.js +0 -8
  107. package/dist/src/ProgressBar/messages.js +0 -13
  108. package/dist/src/Select/components/SelectDefaultPicker/messages.js +0 -8
  109. package/dist/src/Select/messages.js +0 -13
  110. package/dist/src/Toast/messages.js +0 -13
  111. package/dist/types/src/BottomSheet/messages.d.ts +0 -7
  112. package/dist/types/src/ButtonGroup/messages.d.ts +0 -17
  113. package/dist/types/src/ContentOverlay/messages.d.ts +0 -7
  114. package/dist/types/src/Form/components/FormErrorBanner/messages.d.ts +0 -12
  115. package/dist/types/src/Form/components/FormMessage/components/InternalFormMessage/messages.d.ts +0 -7
  116. package/dist/types/src/Form/components/FormSaveButton/messages.d.ts +0 -7
  117. package/dist/types/src/Form/messages.d.ts +0 -27
  118. package/dist/types/src/FormatFile/components/FormatFileBottomSheet/messages.d.ts +0 -12
  119. package/dist/types/src/FormatFile/messages.d.ts +0 -22
  120. package/dist/types/src/InputCurrency/messages.d.ts +0 -7
  121. package/dist/types/src/InputDate/messages.d.ts +0 -7
  122. package/dist/types/src/InputFieldWrapper/components/ClearAction/messages.d.ts +0 -7
  123. package/dist/types/src/InputNumber/messages.d.ts +0 -7
  124. package/dist/types/src/InputPassword/messages.d.ts +0 -7
  125. package/dist/types/src/InputTime/messages.d.ts +0 -7
  126. package/dist/types/src/Menu/messages.d.ts +0 -7
  127. package/dist/types/src/ProgressBar/messages.d.ts +0 -12
  128. package/dist/types/src/Select/components/SelectDefaultPicker/messages.d.ts +0 -7
  129. package/dist/types/src/Select/messages.d.ts +0 -12
  130. package/dist/types/src/Toast/messages.d.ts +0 -12
  131. package/src/BottomSheet/messages.ts +0 -9
  132. package/src/ButtonGroup/messages.ts +0 -19
  133. package/src/ContentOverlay/messages.ts +0 -9
  134. package/src/Form/components/FormErrorBanner/messages.ts +0 -14
  135. package/src/Form/components/FormMessage/components/InternalFormMessage/messages.ts +0 -10
  136. package/src/Form/components/FormSaveButton/messages.ts +0 -9
  137. package/src/Form/messages.ts +0 -33
  138. package/src/FormatFile/components/FormatFileBottomSheet/messages.ts +0 -14
  139. package/src/FormatFile/messages.ts +0 -24
  140. package/src/InputCurrency/messages.ts +0 -10
  141. package/src/InputDate/messages.ts +0 -9
  142. package/src/InputFieldWrapper/components/ClearAction/messages.ts +0 -9
  143. package/src/InputNumber/messages.ts +0 -10
  144. package/src/InputPassword/messages.ts +0 -9
  145. package/src/InputTime/messages.ts +0 -9
  146. package/src/Menu/messages.ts +0 -9
  147. package/src/ProgressBar/messages.ts +0 -14
  148. package/src/Select/components/SelectDefaultPicker/messages.ts +0 -9
  149. package/src/Select/messages.ts +0 -14
  150. package/src/Toast/messages.ts +0 -14
@@ -36,6 +36,14 @@ export interface AtlantisContextProps {
36
36
  * By accurately defining this value, Atlantis can effectively calculate the layout and alignment of its components.
37
37
  */
38
38
  readonly headerHeight: number;
39
+ /**
40
+ * Change the locale of the components. This updates the strings that comes
41
+ * with the components, updates the date and time formats, and/or the
42
+ * native 3rd-party packages.
43
+ *
44
+ * @default "en"
45
+ */
46
+ readonly locale: string;
39
47
  /**
40
48
  * The `setHeaderHeight` method allows you to set the height of the app header in Atlantis.
41
49
  * Adjusting this height is essential for ensuring the correct positioning and alignment of various elements within the app.
@@ -1,9 +1,9 @@
1
- import { MessageDescriptor } from "react-intl";
1
+ import { useAtlantisI18nValue } from "../../hooks/useAtlantisI18n";
2
2
  interface params {
3
- accessibilityLabel?: string;
4
- showOverlay: boolean;
5
- showError: boolean;
6
- formatMessage: (message: MessageDescriptor) => string;
3
+ readonly accessibilityLabel?: string;
4
+ readonly showOverlay: boolean;
5
+ readonly showError: boolean;
6
+ readonly t: useAtlantisI18nValue["t"];
7
7
  }
8
- export declare function computeA11yLabel({ accessibilityLabel, showOverlay, showError, formatMessage, }: params): string;
8
+ export declare function computeA11yLabel({ accessibilityLabel, showOverlay, showError, t, }: params): string;
9
9
  export {};
@@ -1,2 +1 @@
1
1
  export { ClearAction } from "./ClearAction";
2
- export { messages } from "./messages";
@@ -0,0 +1 @@
1
+ export * from "./useAtlantisI18n";
@@ -0,0 +1,6 @@
1
+ import en from "./locales/en.json";
2
+ export interface useAtlantisI18nValue {
3
+ readonly locale: string;
4
+ readonly t: (message: keyof typeof en, values?: Record<string, string>) => string;
5
+ }
6
+ export declare function useAtlantisI18n(): useAtlantisI18nValue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jobber/components-native",
3
- "version": "0.44.2",
3
+ "version": "0.45.0",
4
4
  "license": "MIT",
5
5
  "description": "React Native implementation of Atlantis",
6
6
  "repository": {
@@ -84,5 +84,5 @@
84
84
  "react-native-reanimated": "^2.17.0",
85
85
  "react-native-safe-area-context": "^4.5.2"
86
86
  },
87
- "gitHead": "4f1eed5cadf29a87143305992d08c90907ee41f4"
87
+ "gitHead": "90e9d2a124e1d65d678364063f6ef57e066939af"
88
88
  }
@@ -47,6 +47,15 @@ export interface AtlantisContextProps {
47
47
  */
48
48
  readonly headerHeight: number;
49
49
 
50
+ /**
51
+ * Change the locale of the components. This updates the strings that comes
52
+ * with the components, updates the date and time formats, and/or the
53
+ * native 3rd-party packages.
54
+ *
55
+ * @default "en"
56
+ */
57
+ readonly locale: string;
58
+
50
59
  /**
51
60
  * The `setHeaderHeight` method allows you to set the height of the app header in Atlantis.
52
61
  * Adjusting this height is essential for ensuring the correct positioning and alignment of various elements within the app.
@@ -67,6 +76,7 @@ export const defaultValues: AtlantisContextProps = {
67
76
  floatSeparators: { group: ",", decimal: "." },
68
77
  currencySymbol: DEFAULT_CURRENCY_SYMBOL,
69
78
  headerHeight: 0,
79
+ locale: "en",
70
80
  setHeaderHeight: _ => {
71
81
  return;
72
82
  },
@@ -4,7 +4,6 @@ import { AccessibilityInfo, View } from "react-native";
4
4
  import { Host, Portal } from "react-native-portalize";
5
5
  import { BottomSheet } from ".";
6
6
  import { BottomSheetRef } from "./BottomSheet";
7
- import { messages } from "./messages";
8
7
  import { waitForUntestableRender } from "../utils/test/wait";
9
8
  import { Text } from "../Text";
10
9
 
@@ -79,7 +78,7 @@ it("BottomSheet can be closed with the cancel action", async () => {
79
78
  ref.current?.open();
80
79
  });
81
80
 
82
- fireEvent.press(getByText(messages.cancel.defaultMessage));
81
+ fireEvent.press(getByText("Cancel"));
83
82
 
84
83
  await waitFor(() => {
85
84
  expect(queryByText("BottomSheet")).toBeNull();
@@ -98,7 +97,7 @@ describe("when loading is provided and true", () => {
98
97
  ref.current?.open();
99
98
  });
100
99
 
101
- expect(queryByText(messages.cancel.defaultMessage)).toBeNull();
100
+ expect(queryByText("Cancel")).toBeNull();
102
101
  });
103
102
  });
104
103
 
@@ -143,7 +142,7 @@ describe("when there is a screen reader enabled", () => {
143
142
  ref.current?.open();
144
143
  });
145
144
 
146
- fireEvent.press(getByText(messages.cancel.defaultMessage));
145
+ fireEvent.press(getByText("Cancel"));
147
146
 
148
147
  await waitFor(() => {
149
148
  expect(queryByText("BottomSheet")).toBeNull();
@@ -2,13 +2,12 @@ import React, { ReactNode, Ref, RefObject, forwardRef, useState } from "react";
2
2
  import { Modalize } from "react-native-modalize";
3
3
  import { useSafeAreaInsets } from "react-native-safe-area-context";
4
4
  import { Keyboard, View } from "react-native";
5
- import { useIntl } from "react-intl";
6
5
  import { BottomSheetOption } from "./components/BottomSheetOption";
7
6
  import { styles } from "./BottomSheet.style";
8
- import { messages } from "./messages";
9
7
  import { useIsScreenReaderEnabled } from "../hooks";
10
8
  import { Divider } from "../Divider";
11
9
  import { Heading } from "../Heading";
10
+ import { useAtlantisI18n } from "../hooks/useAtlantisI18n";
12
11
 
13
12
  export interface BottomSheetProps {
14
13
  readonly children: ReactNode;
@@ -118,7 +117,7 @@ function Footer({
118
117
  onCancel: () => void;
119
118
  }) {
120
119
  const insets = useSafeAreaInsets();
121
- const { formatMessage } = useIntl();
120
+ const { t } = useAtlantisI18n();
122
121
 
123
122
  return (
124
123
  <View style={{ marginBottom: insets.bottom }}>
@@ -128,7 +127,7 @@ function Footer({
128
127
  <Divider />
129
128
  </View>
130
129
  <BottomSheetOption
131
- text={formatMessage(messages.cancel)}
130
+ text={t("cancel")}
132
131
  icon={"remove"}
133
132
  onPress={onCancel}
134
133
  />
@@ -2,7 +2,6 @@ import React from "react";
2
2
  import { fireEvent, render } from "@testing-library/react-native";
3
3
  import { Host } from "react-native-portalize";
4
4
  import { Alert } from "react-native";
5
- import { messages } from "./messages";
6
5
  import { ButtonGroup, ButtonGroupProps } from "./ButtonGroup";
7
6
  import { Button } from "../Button";
8
7
  import * as atlantisContext from "../AtlantisContext/AtlantisContext";
@@ -37,7 +36,7 @@ it("renders a single primary action", () => {
37
36
  );
38
37
 
39
38
  expect(getByText("Create")).not.toBeNull();
40
- expect(queryByLabelText(messages.more.defaultMessage)).toBeNull();
39
+ expect(queryByLabelText("More")).toBeNull();
41
40
  });
42
41
 
43
42
  it("renders 2 primary actions", () => {
@@ -60,7 +59,7 @@ it("renders 2 primary actions", () => {
60
59
 
61
60
  expect(getByText("Create")).not.toBeNull();
62
61
  expect(getByText("Edit")).not.toBeNull();
63
- expect(queryByLabelText(messages.more.defaultMessage)).toBeNull();
62
+ expect(queryByLabelText("More")).toBeNull();
64
63
  });
65
64
 
66
65
  it("does not render more than 2 primary actions but adds a More button", () => {
@@ -90,7 +89,7 @@ it("does not render more than 2 primary actions but adds a More button", () => {
90
89
  expect(getByText("Create")).not.toBeNull();
91
90
  expect(getByText("Edit")).not.toBeNull();
92
91
  expect(queryByText("Mystery")).toBeNull();
93
- expect(getByLabelText(messages.more.defaultMessage)).toBeDefined();
92
+ expect(getByLabelText("More")).toBeDefined();
94
93
  });
95
94
 
96
95
  it("does not render secondary actions", () => {
@@ -119,7 +118,7 @@ it("does not render secondary actions", () => {
119
118
  expect(getByText("Create")).not.toBeNull();
120
119
  expect(queryByText("Edit")).toBeNull();
121
120
  expect(queryByText("Delete")).toBeNull();
122
- expect(getByLabelText(messages.more.defaultMessage)).toBeDefined();
121
+ expect(getByLabelText("More")).toBeDefined();
123
122
  });
124
123
 
125
124
  it("renders first secondary action as a primary action button if no primary action specified", () => {
@@ -141,7 +140,7 @@ it("renders first secondary action as a primary action button if no primary acti
141
140
  );
142
141
  expect(getByText("Edit")).not.toBeNull();
143
142
  expect(queryByText("Delete")).toBeNull();
144
- expect(getByLabelText(messages.more.defaultMessage)).toBeDefined();
143
+ expect(getByLabelText("More")).toBeDefined();
145
144
  });
146
145
 
147
146
  it("fires the press handlers when the primary action buttons are pressed", () => {
@@ -194,7 +193,7 @@ it("opens the secondary action menu when the More button is pressed", () => {
194
193
 
195
194
  expect(queryByText("Edit")).toBeNull();
196
195
 
197
- fireEvent.press(getByLabelText(messages.more.defaultMessage));
196
+ fireEvent.press(getByLabelText("More"));
198
197
 
199
198
  expect(getByText("Edit")).not.toBeNull();
200
199
  expect(getByText("Delete")).not.toBeNull();
@@ -221,7 +220,7 @@ it("renders heading and cancel options if passed in", () => {
221
220
  </ButtonGroupForTest>,
222
221
  );
223
222
 
224
- fireEvent.press(getByLabelText(messages.more.defaultMessage));
223
+ fireEvent.press(getByLabelText("More"));
225
224
 
226
225
  expect(getByText("Heading")).not.toBeNull();
227
226
  expect(getByText("Cancel")).not.toBeNull();
@@ -273,7 +272,7 @@ it("calls onOpenBottomSheet when the secondary actions are opened", () => {
273
272
  </ButtonGroupForTest>,
274
273
  );
275
274
 
276
- fireEvent.press(getByLabelText(messages.more.defaultMessage));
275
+ fireEvent.press(getByLabelText("More"));
277
276
 
278
277
  expect(mockOnOpen).toHaveBeenCalled();
279
278
  });
@@ -1,14 +1,13 @@
1
1
  import React, { useRef } from "react";
2
- import { useIntl } from "react-intl";
3
2
  import { View } from "react-native";
4
3
  import { PrimaryAction, SecondaryAction } from "./ButtonGroupAction";
5
- import { messages } from "./messages";
6
4
  import { styles } from "./ButtonGroup.style";
7
5
  import { SecondaryActionSheet } from "./components/SecondaryActionSheet";
8
6
  import { getActions, usePreventTapWhenOffline } from "./utils";
9
7
  import { ButtonGroupActionElement } from "./types";
10
8
  import { Button } from "../Button";
11
9
  import { BottomSheetRef } from "../BottomSheet/BottomSheet";
10
+ import { useAtlantisI18n } from "../hooks/useAtlantisI18n";
12
11
 
13
12
  export interface ButtonGroupProps {
14
13
  readonly children: ButtonGroupActionElement | ButtonGroupActionElement[];
@@ -47,7 +46,7 @@ export function ButtonGroup({
47
46
  onCloseBottomSheet,
48
47
  allowTapWhenOffline = false,
49
48
  }: ButtonGroupProps): JSX.Element {
50
- const { formatMessage } = useIntl();
49
+ const { t } = useAtlantisI18n();
51
50
  const { handlePress } = usePreventTapWhenOffline();
52
51
  const secondaryActionsRef = useRef<BottomSheetRef>();
53
52
  const { primaryActions, secondaryActions } = getActions(children);
@@ -86,7 +85,7 @@ export function ButtonGroup({
86
85
  <View style={styles.moreButton}>
87
86
  <Button
88
87
  icon={"more"}
89
- accessibilityLabel={formatMessage(messages.more)}
88
+ accessibilityLabel={t("more")}
90
89
  onPress={handlePress(openBottomSheet)}
91
90
  fullHeight={true}
92
91
  />
@@ -1,7 +1,5 @@
1
1
  import React, { useCallback } from "react";
2
- import { useIntl } from "react-intl";
3
2
  import { Alert } from "react-native";
4
- import { messages } from "./messages";
5
3
  import {
6
4
  ButtonGroupActionElement,
7
5
  ButtonGroupPrimaryActionElement,
@@ -12,6 +10,7 @@ import {
12
10
  SecondaryAction,
13
11
  } from "./ButtonGroupAction";
14
12
  import { useAtlantisContext } from "../AtlantisContext/AtlantisContext";
13
+ import { useAtlantisI18n } from "../hooks/useAtlantisI18n";
15
14
 
16
15
  interface UsePreventTapWhenOfflineShape {
17
16
  readonly handlePress: (
@@ -24,7 +23,7 @@ interface UsePreventTapWhenOfflineShape {
24
23
  * online or offline
25
24
  */
26
25
  export function usePreventTapWhenOffline(): UsePreventTapWhenOfflineShape {
27
- const { formatMessage } = useIntl();
26
+ const { t } = useAtlantisI18n();
28
27
  const { isOnline } = useAtlantisContext();
29
28
 
30
29
  const handlePress = useCallback(
@@ -33,11 +32,11 @@ export function usePreventTapWhenOffline(): UsePreventTapWhenOfflineShape {
33
32
 
34
33
  return () =>
35
34
  Alert.alert(
36
- formatMessage(messages.unavailableNetworkTitle),
37
- formatMessage(messages.unavailableNetworkMessage),
35
+ t("networkUnavailableTitle"),
36
+ t("networkUnavailableDescription"),
38
37
  );
39
38
  },
40
- [formatMessage, isOnline],
39
+ [isOnline],
41
40
  );
42
41
 
43
42
  return { handlePress };
@@ -3,13 +3,11 @@ import { fireEvent, render, waitFor } from "@testing-library/react-native";
3
3
  import { AccessibilityInfo, View } from "react-native";
4
4
  import { Host } from "react-native-portalize";
5
5
  import { ReactTestInstance, act } from "react-test-renderer";
6
- import { useIntl } from "react-intl";
7
6
  import {
8
7
  ContentOverlay,
9
8
  ContentOverlayRef,
10
9
  ModalBackgroundColor,
11
10
  } from "./ContentOverlay";
12
- import { messages } from "./messages";
13
11
  import { tokens } from "../utils/design";
14
12
  import { Button } from "../Button";
15
13
  import { Content } from "../Content";
@@ -232,8 +230,6 @@ describe("when accessibilityLabel prop passed to content overlay", () => {
232
230
 
233
231
  describe("when accessibilityLabel prop NOT passed to content overlay", () => {
234
232
  it("should use default accessibilityLabel", () => {
235
- const { formatMessage } = useIntl();
236
-
237
233
  const options: testRendererOptions = {
238
234
  ...getDefaultOptions(),
239
235
  title: "Awesome Title",
@@ -241,14 +237,8 @@ describe("when accessibilityLabel prop NOT passed to content overlay", () => {
241
237
  };
242
238
  const contentOverlayScreen = renderAndOpenContentOverlay(options);
243
239
 
244
- const defaultCloseOverlayA11YLabel = formatMessage(
245
- messages.closeOverlayA11YLabel,
246
- {
247
- title: options.title,
248
- },
249
- );
250
240
  expect(
251
- contentOverlayScreen.getAllByLabelText(defaultCloseOverlayA11YLabel),
241
+ contentOverlayScreen.getAllByLabelText(`Close ${options.title} modal`),
252
242
  ).toHaveLength(2);
253
243
  });
254
244
  });
@@ -19,10 +19,8 @@ import {
19
19
  useWindowDimensions,
20
20
  } from "react-native";
21
21
  import { Portal } from "react-native-portalize";
22
- import { useIntl } from "react-intl";
23
22
  import { useKeyboardVisibility } from "./hooks/useKeyboardVisibility";
24
23
  import { styles } from "./ContentOverlay.style";
25
- import { messages } from "./messages";
26
24
  import { useViewLayoutHeight } from "./hooks/useViewLayoutHeight";
27
25
  import {
28
26
  ContentOverlayProps,
@@ -33,6 +31,7 @@ import { useIsScreenReaderEnabled } from "../hooks";
33
31
  import { IconButton } from "../IconButton";
34
32
  import { tokens } from "../utils/design";
35
33
  import { Heading } from "../Heading";
34
+ import { useAtlantisI18n } from "../hooks/useAtlantisI18n";
36
35
 
37
36
  export const ContentOverlay = forwardRef(ContentOverlayPortal);
38
37
  const ContentOverlayModal = forwardRef(ContentOverlayInternal);
@@ -61,7 +60,7 @@ function ContentOverlayInternal(
61
60
  ): JSX.Element {
62
61
  isDraggable = onBeforeExit ? false : isDraggable;
63
62
  const isCloseableOnOverlayTap = onBeforeExit ? false : true;
64
- const { formatMessage } = useIntl();
63
+ const { t } = useAtlantisI18n();
65
64
  const { width: windowWidth, height: windowHeight } = useWindowDimensions();
66
65
  const insets = useSafeAreaInsets();
67
66
  const [position, setPosition] = useState<"top" | "initial">("initial");
@@ -203,12 +202,9 @@ function ContentOverlayInternal(
203
202
  );
204
203
 
205
204
  function renderHeader() {
206
- const closeOverlayA11YLabel = formatMessage(
207
- messages.closeOverlayA11YLabel,
208
- {
209
- title: title,
210
- },
211
- );
205
+ const closeOverlayA11YLabel = t("ContentOverlay.close", {
206
+ title: title,
207
+ });
212
208
 
213
209
  const headerStyles = [
214
210
  styles.header,
@@ -1,12 +1,8 @@
1
1
  import React from "react";
2
2
  import { act, fireEvent, render, waitFor } from "@testing-library/react-native";
3
3
  import { Alert, Keyboard } from "react-native";
4
- import { useIntl } from "react-intl";
5
4
  import { Host } from "react-native-portalize";
6
5
  import { Form, FormBannerMessage, FormBannerMessageType } from ".";
7
- import { messages as formErrorBannerMessages } from "./components/FormErrorBanner/messages";
8
- import { messages } from "./components/FormSaveButton/messages";
9
- import { messages as formMessages } from "./messages";
10
6
  import { FormBannerErrors, FormSubmitErrorType } from "./types";
11
7
  import { defaultValues as contextDefaultValue } from "../AtlantisContext";
12
8
  import * as atlantisContext from "../AtlantisContext/AtlantisContext";
@@ -74,7 +70,7 @@ const testCheckboxName = "testCheckbox";
74
70
  const switchLabel = "switchLabel";
75
71
  const checkboxLabel = "checkboxLabel";
76
72
  const selectLabel = "selectLabel";
77
- const saveButtonText = messages.saveButton.defaultMessage;
73
+ const saveButtonText = "Save";
78
74
 
79
75
  const requiredInputText = "This field is required";
80
76
  const minLengthText = "Test is too short";
@@ -207,15 +203,15 @@ afterEach(() => {
207
203
  jest.clearAllMocks();
208
204
  });
209
205
 
206
+ const loadingLabel = "Loading";
207
+ const tryAgainLabel = "Try again";
210
208
  describe("Form", () => {
211
209
  describe("Initial Load", () => {
212
210
  it("should show activity indicator", () => {
213
211
  const { getByLabelText } = render(
214
212
  <FormTest initialLoading={true} onSubmit={onSubmitMock} />,
215
213
  );
216
- expect(
217
- getByLabelText(formMessages.loadingA11YLabel.defaultMessage),
218
- ).toBeTruthy();
214
+ expect(getByLabelText(loadingLabel)).toBeTruthy();
219
215
  });
220
216
 
221
217
  it("should be populated with provided initialValues", () => {
@@ -362,9 +358,7 @@ describe("Form", () => {
362
358
  const saveButton = getByLabelText(saveButtonText);
363
359
  fireEvent.press(saveButton);
364
360
 
365
- expect(
366
- getByLabelText(formMessages.loadingA11YLabel.defaultMessage),
367
- ).toBeTruthy();
361
+ expect(getByLabelText(loadingLabel)).toBeTruthy();
368
362
  });
369
363
 
370
364
  it("should call beforeSubmit if one is provided", async () => {
@@ -432,14 +426,13 @@ describe("Form", () => {
432
426
 
433
427
  it("should show offline alert when attempting to save while offline", async () => {
434
428
  const alertSpy = jest.spyOn(Alert, "alert");
435
- const { formatMessage } = useIntl();
436
429
  setup();
437
430
 
438
431
  await act(wait);
439
432
  expect(alertSpy).toHaveBeenCalledTimes(1);
440
433
  expect(alertSpy).toHaveBeenCalledWith(
441
- formatMessage(formMessages.unavailableNetworkTitle),
442
- formatMessage(formMessages.unavailableNetworkMessage),
434
+ "Network Unavailable",
435
+ "Check your internet connection and try again later.",
443
436
  expect.anything(),
444
437
  );
445
438
  });
@@ -450,8 +443,7 @@ describe("Form", () => {
450
443
  await act(wait);
451
444
  const alertActions = alertSpy.mock.calls[0][2];
452
445
  const retryAction = alertActions?.find(
453
- action =>
454
- action.text === formMessages.retryAlertButton.defaultMessage,
446
+ action => action.text === tryAgainLabel,
455
447
  );
456
448
  mockSubmit.mockImplementationOnce(() => Promise.resolve());
457
449
  retryAction?.onPress?.();
@@ -467,8 +459,7 @@ describe("Form", () => {
467
459
  await act(wait);
468
460
  const alertActions = alertSpy.mock.calls[0][2];
469
461
  const retryAction = alertActions?.find(
470
- action =>
471
- action.text === formMessages.retryAlertButton.defaultMessage,
462
+ action => action.text === tryAgainLabel,
472
463
  );
473
464
  retryAction?.onPress?.();
474
465
 
@@ -489,28 +480,6 @@ describe("Form", () => {
489
480
  isOnline: false,
490
481
  });
491
482
 
492
- it("renders Offline Banner when disconnected", async () => {
493
- const { getByText } = render(<FormTest onSubmit={onSubmitMock} />);
494
- const { formatMessage } = useIntl();
495
-
496
- expect(
497
- getByText(formatMessage(formErrorBannerMessages.offlineError)),
498
- ).toBeDefined();
499
- });
500
-
501
- it("does not render Offline Banner when connected", async () => {
502
- atlantisContextSpy.mockReturnValue({
503
- ...contextDefaultValue,
504
- isOnline: true,
505
- });
506
- const { queryByText } = render(<FormTest onSubmit={onSubmitMock} />);
507
- const { formatMessage } = useIntl();
508
-
509
- expect(
510
- queryByText(formatMessage(formErrorBannerMessages.offlineError)),
511
- ).toBeNull();
512
- });
513
-
514
483
  it("renders user errors when provided", async () => {
515
484
  const { getByText } = render(
516
485
  <FormTest onSubmit={onSubmitMock} sendBannerErrors={true} />,
@@ -1,8 +1,6 @@
1
1
  import React from "react";
2
2
  import { cleanup, render } from "@testing-library/react-native";
3
- import { useIntl } from "react-intl";
4
3
  import { FormErrorBanner } from "./FormErrorBanner";
5
- import { messages as formErrorBannerMessages } from "./messages";
6
4
  import { defaultValues as contextDefaultValue } from "../../../AtlantisContext";
7
5
  import * as atlantisContext from "../../../AtlantisContext/AtlantisContext";
8
6
 
@@ -16,65 +14,20 @@ describe("FormErrorBanner", () => {
16
14
  });
17
15
  });
18
16
 
19
- const { formatMessage } = useIntl();
20
- const networkError = new Error();
17
+ const networkError = "An error occurred";
21
18
  const userError = {
22
19
  title: "My error",
23
20
  messages: ["userError1", "userError2"],
24
21
  };
25
- const validationErrors = [
26
- "This is the first validation error",
27
- "This is the second validation error",
28
- ];
29
-
30
- it("should render Offline banner when offline", () => {
31
- atlantisContextSpy.mockReturnValue({
32
- ...contextDefaultValue,
33
- isOnline: false,
34
- });
35
- const { getByText, queryByText } = render(
36
- <FormErrorBanner
37
- // @ts-expect-error tsc-ci
38
- networkError={networkError}
39
- bannerError={userError}
40
- validationErrors={validationErrors}
41
- actionLabel="Action"
42
- />,
43
- );
44
-
45
- // Show: Offline Message
46
- expect(
47
- getByText(formatMessage(formErrorBannerMessages.offlineError)),
48
- ).toBeDefined();
49
-
50
- // Hide: Network Error, User Error, Validation Error
51
- expect(
52
- queryByText(formatMessage(formErrorBannerMessages.networkError)),
53
- ).toBeNull();
54
-
55
- expect(queryByText(userError.title)).toBeNull();
56
- });
22
+ const couldNotSavechanges = "Could not save changes";
57
23
 
58
24
  it("should render network error banner when online and network errors exist", () => {
59
25
  const { getByText, queryByText } = render(
60
- <FormErrorBanner
61
- // @ts-expect-error tsc-ci
62
- networkError={networkError}
63
- bannerError={userError}
64
- actionLabel="action"
65
- />,
26
+ <FormErrorBanner networkError={networkError} bannerError={userError} />,
66
27
  );
67
28
 
68
- // Show: Network Error
69
- expect(
70
- getByText(formatMessage(formErrorBannerMessages.networkError)),
71
- ).toBeDefined();
72
-
73
- // Hide: Offline Message, User Error, Validation Error
74
- expect(
75
- queryByText(formatMessage(formErrorBannerMessages.offlineError)),
76
- ).toBeNull();
77
-
29
+ // Show: Network Error only
30
+ expect(getByText(couldNotSavechanges)).toBeDefined();
78
31
  expect(queryByText(userError.title)).toBeNull();
79
32
  });
80
33
 
@@ -83,19 +36,11 @@ describe("FormErrorBanner", () => {
83
36
  <FormErrorBanner bannerError={userError} />,
84
37
  );
85
38
 
86
- // Show: User Error
39
+ // Show: User Error only
87
40
  expect(getByText(userError.title)).toBeDefined();
88
41
  expect(getByText(userError.messages[0])).toBeDefined();
89
42
  expect(getByText(userError.messages[1])).toBeDefined();
90
-
91
- // Hide: Offline Message, Network Error, Validation Error
92
- expect(
93
- queryByText(formatMessage(formErrorBannerMessages.offlineError)),
94
- ).toBeNull();
95
-
96
- expect(
97
- queryByText(formatMessage(formErrorBannerMessages.networkError)),
98
- ).toBeNull();
43
+ expect(queryByText(couldNotSavechanges)).toBeNull();
99
44
  });
100
45
 
101
46
  it("should render user error banner with just title when online", () => {
@@ -106,17 +51,9 @@ describe("FormErrorBanner", () => {
106
51
  <FormErrorBanner bannerError={userErrorJustTitle} />,
107
52
  );
108
53
 
109
- // Show: User Error
54
+ // Show: User Error only
110
55
  expect(getByText(userErrorJustTitle.title)).toBeDefined();
111
-
112
- // Hide: Offline Message, Network Error, Validation Error
113
- expect(
114
- queryByText(formatMessage(formErrorBannerMessages.offlineError)),
115
- ).toBeNull();
116
-
117
- expect(
118
- queryByText(formatMessage(formErrorBannerMessages.networkError)),
119
- ).toBeNull();
56
+ expect(queryByText(couldNotSavechanges)).toBeNull();
120
57
  });
121
58
  });
122
59
 
@@ -1,25 +1,16 @@
1
1
  import React from "react";
2
- import { useIntl } from "react-intl";
3
- import { messages } from "./messages";
4
2
  import { FormBannerErrors } from "../../types";
5
- import { useAtlantisContext } from "../../../AtlantisContext";
6
3
  import { Banner } from "../../../Banner";
4
+ import { useAtlantisI18n } from "../../../hooks/useAtlantisI18n";
7
5
 
8
6
  export function FormErrorBanner({
9
7
  networkError,
10
8
  bannerError,
11
9
  }: FormBannerErrors): JSX.Element {
12
- const { formatMessage } = useIntl();
13
- const { isOnline } = useAtlantisContext();
10
+ const { t } = useAtlantisI18n();
14
11
 
15
- if (!isOnline) {
16
- return (
17
- <Banner text={formatMessage(messages.offlineError)} type={"error"} />
18
- );
19
- } else if (networkError) {
20
- return (
21
- <Banner text={formatMessage(messages.networkError)} type={"error"} />
22
- );
12
+ if (networkError) {
13
+ return <Banner type={"error"}>{t("errors.couldNotSave")}</Banner>;
23
14
  } else if (bannerError) {
24
15
  return (
25
16
  <Banner
@@ -28,7 +19,7 @@ export function FormErrorBanner({
28
19
  type={"error"}
29
20
  />
30
21
  );
31
- } else {
32
- return <></>;
33
22
  }
23
+
24
+ return <></>;
34
25
  }