@jobber/components-native 0.110.0 → 0.111.1-fixselect-35e5f17.5

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/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jobber/components-native",
3
- "version": "0.110.0",
3
+ "version": "0.111.1-fixselect-35e5f17.5+35e5f17e",
4
4
  "license": "MIT",
5
5
  "description": "React Native implementation of Atlantis",
6
6
  "repository": {
@@ -74,7 +74,7 @@
74
74
  "@babel/runtime": "^7.29.2",
75
75
  "@gorhom/bottom-sheet": "^5.2.8",
76
76
  "@jobber/design": "0.109.0",
77
- "@jobber/hooks": "2.21.0",
77
+ "@jobber/hooks": "2.21.1-fixselect-35e5f17.128+35e5f17e",
78
78
  "@react-native-community/datetimepicker": "^8.4.5",
79
79
  "@react-native/babel-preset": "^0.82.1",
80
80
  "@storybook/addon-a11y": "10.3.5",
@@ -124,5 +124,5 @@
124
124
  "react-native-screens": ">=4.18.0",
125
125
  "react-native-svg": ">=12.0.0"
126
126
  },
127
- "gitHead": "c81a2b04748119a1bd84cc39f4f5e7a97c410afb"
127
+ "gitHead": "35e5f17e1a76af9c70f7d38a65caf0be8b47cd6a"
128
128
  }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Languages that have been fully released and are safe to surface to users.
3
+ * Any locale not present in this list will fall back to "en".
4
+ *
5
+ * To release a new language, add its BCP 47 language tag here (e.g. "es").
6
+ */
7
+ export const RELEASED_LANGUAGES = ["en"];
8
+ /**
9
+ * Returns the locale to use based on what has been released. Matches on the
10
+ * language part of the locale (before the "-") so that regional variants like
11
+ * "en-CA" or "es-US" resolve correctly:
12
+ *
13
+ * - "en-CA" → "en-CA" (language "en" is released; full locale preserved for
14
+ * date/time formatting)
15
+ * - "es-US" → "en" (language "es" not yet released; falls back to "en")
16
+ * - "fr" → "en" (language "fr" not released; falls back to "en")
17
+ */
18
+ export function getReleasedLocale(locale) {
19
+ const language = locale.split("-")[0];
20
+ return RELEASED_LANGUAGES.includes(language) ? locale : "en";
21
+ }
@@ -1,17 +1,19 @@
1
1
  import { useCallback } from "react";
2
2
  import en from "./locales/en.json";
3
3
  import es from "./locales/es.json";
4
+ import { getReleasedLocale } from "./releasedLanguages";
4
5
  import { dateFormatter } from "./utils/dateFormatter";
5
6
  import { useAtlantisContext } from "../../AtlantisContext";
6
7
  export function useAtlantisI18n() {
7
- const { locale, dateFormat, timeFormat, timeZone } = useAtlantisContext();
8
+ const { locale: contextLocale, dateFormat, timeFormat, timeZone, } = useAtlantisContext();
9
+ const locale = getReleasedLocale(contextLocale);
8
10
  const t = useCallback((messageKey, values) => formatMessage(messageKey, values, locale), [formatMessage, locale]);
9
11
  const formatDate = useCallback((date) => dateFormatter(date, dateFormat, { locale, timeZone }), [dateFormatter, locale]);
10
12
  const formatTime = useCallback((date) => dateFormatter(date, timeFormat, { locale, timeZone }), [dateFormatter, locale]);
11
13
  return { locale, t, formatDate, formatTime };
12
14
  }
13
15
  function getLocalizedStrings(locale) {
14
- switch (locale) {
16
+ switch (locale.split("-")[0]) {
15
17
  case "es":
16
18
  return es;
17
19
  default:
@@ -2,10 +2,15 @@ import { renderHook } from "@testing-library/react-native";
2
2
  import { useAtlantisI18n } from ".";
3
3
  import en from "./locales/en.json";
4
4
  import es from "./locales/es.json";
5
+ import * as releasedLanguages from "./releasedLanguages";
5
6
  import * as context from "../../AtlantisContext";
6
7
  jest.mock("../../AtlantisContext", () => (Object.assign({
7
8
  // need to mark this as a module so that we can spy on it
8
9
  __esModule: true }, jest.requireActual("../../AtlantisContext"))));
10
+ // Mock releasedLanguages so that jest.spyOn can reliably intercept calls from
11
+ // inside the hook. Without this, Babel may resolve the named import as a local
12
+ // binding at module load time, bypassing any spy set up afterwards.
13
+ jest.mock("./releasedLanguages", () => (Object.assign({ __esModule: true }, jest.requireActual("./releasedLanguages"))));
9
14
  const spy = jest.spyOn(context, "useAtlantisContext");
10
15
  const testDate = new Date("2020-01-01T00:00:00.000Z");
11
16
  const dateAfterSpringForward = new Date("2020-04-10T00:00:00.000Z");
@@ -22,18 +27,123 @@ describe("useAtlantisI18n", () => {
22
27
  const { result } = renderHook(useAtlantisI18n);
23
28
  expect(result.current.t("FormatFile.preview", { item: "🔱" })).toBe("Preview 🔱");
24
29
  });
30
+ // These tests bypass the release gate via a spy so we can validate Spanish
31
+ // string correctness as the feature is built, independently of RELEASED_LANGUAGES.
25
32
  describe("Español", () => {
33
+ let getReleasedLocaleSpy;
34
+ beforeEach(() => {
35
+ getReleasedLocaleSpy = jest
36
+ .spyOn(releasedLanguages, "getReleasedLocale")
37
+ .mockImplementation(locale => locale);
38
+ });
39
+ afterEach(() => {
40
+ getReleasedLocaleSpy.mockRestore();
41
+ });
26
42
  it("should return español", () => {
27
43
  spy.mockReturnValueOnce(Object.assign(Object.assign({}, context.atlantisContextDefaultValues), { locale: "es" }));
28
44
  const { result } = renderHook(useAtlantisI18n);
29
45
  expect(result.current.t("cancel")).toBe("Cancelar");
30
46
  });
31
- });
32
- describe("Unsupported language", () => {
33
- it("should return the english translation", () => {
34
- spy.mockReturnValueOnce(Object.assign(Object.assign({}, context.atlantisContextDefaultValues), { locale: "fr" }));
47
+ it("should return español for regional variant es-US", () => {
48
+ spy.mockReturnValueOnce(Object.assign(Object.assign({}, context.atlantisContextDefaultValues), { locale: "es-US" }));
35
49
  const { result } = renderHook(useAtlantisI18n);
36
- expect(result.current.t("cancel")).toBe("Cancel");
50
+ expect(result.current.t("cancel")).toBe("Cancelar");
51
+ });
52
+ describe("formatDate", () => {
53
+ it("should return the date formatted for es", () => {
54
+ spy.mockReturnValueOnce(Object.assign(Object.assign({}, context.atlantisContextDefaultValues), { locale: "es" }));
55
+ const { result } = renderHook(useAtlantisI18n);
56
+ expect(result.current.formatDate(testDate)).toBe("1 ene 2020");
57
+ });
58
+ });
59
+ describe("formatTime", () => {
60
+ it("should return the time formatted for es", () => {
61
+ spy.mockReturnValueOnce(Object.assign(Object.assign({}, context.atlantisContextDefaultValues), { locale: "es" }));
62
+ const { result } = renderHook(useAtlantisI18n);
63
+ expect(result.current.formatTime(testDate)).toBe("00:00");
64
+ });
65
+ });
66
+ });
67
+ describe("RELEASED_LANGUAGES fallback", () => {
68
+ describe("unsupported language (fr)", () => {
69
+ it("should return 'en' as the locale", () => {
70
+ spy.mockReturnValueOnce(Object.assign(Object.assign({}, context.atlantisContextDefaultValues), { locale: "fr" }));
71
+ const { result } = renderHook(useAtlantisI18n);
72
+ expect(result.current.locale).toBe("en");
73
+ });
74
+ it("should return english translations", () => {
75
+ spy.mockReturnValueOnce(Object.assign(Object.assign({}, context.atlantisContextDefaultValues), { locale: "fr" }));
76
+ const { result } = renderHook(useAtlantisI18n);
77
+ expect(result.current.t("cancel")).toBe("Cancel");
78
+ });
79
+ });
80
+ describe("es-US (unreleased locale variant)", () => {
81
+ it("should return 'en' as the locale", () => {
82
+ spy.mockReturnValueOnce(Object.assign(Object.assign({}, context.atlantisContextDefaultValues), { locale: "es-US" }));
83
+ const { result } = renderHook(useAtlantisI18n);
84
+ expect(result.current.locale).toBe("en");
85
+ });
86
+ it("should return english translations", () => {
87
+ spy.mockReturnValueOnce(Object.assign(Object.assign({}, context.atlantisContextDefaultValues), { locale: "es-US" }));
88
+ const { result } = renderHook(useAtlantisI18n);
89
+ expect(result.current.t("cancel")).toBe("Cancel");
90
+ });
91
+ it("should format date using english locale", () => {
92
+ spy.mockReturnValueOnce(Object.assign(Object.assign({}, context.atlantisContextDefaultValues), { locale: "es-US" }));
93
+ const { result } = renderHook(useAtlantisI18n);
94
+ expect(result.current.formatDate(testDate)).toBe("Jan 1, 2020");
95
+ });
96
+ it("should format time using english locale", () => {
97
+ spy.mockReturnValueOnce(Object.assign(Object.assign({}, context.atlantisContextDefaultValues), { locale: "es-US" }));
98
+ const { result } = renderHook(useAtlantisI18n);
99
+ expect(result.current.formatTime(testDate)).toBe("12:00 AM");
100
+ });
101
+ });
102
+ describe("es (not yet released)", () => {
103
+ it("should return 'en' as the locale", () => {
104
+ spy.mockReturnValueOnce(Object.assign(Object.assign({}, context.atlantisContextDefaultValues), { locale: "es" }));
105
+ const { result } = renderHook(useAtlantisI18n);
106
+ expect(result.current.locale).toBe("en");
107
+ });
108
+ it("should return english translations", () => {
109
+ spy.mockReturnValueOnce(Object.assign(Object.assign({}, context.atlantisContextDefaultValues), { locale: "es" }));
110
+ const { result } = renderHook(useAtlantisI18n);
111
+ expect(result.current.t("cancel")).toBe("Cancel");
112
+ });
113
+ it("should format date using english locale", () => {
114
+ spy.mockReturnValueOnce(Object.assign(Object.assign({}, context.atlantisContextDefaultValues), { locale: "es" }));
115
+ const { result } = renderHook(useAtlantisI18n);
116
+ expect(result.current.formatDate(testDate)).toBe("Jan 1, 2020");
117
+ });
118
+ it("should format time using english locale", () => {
119
+ spy.mockReturnValueOnce(Object.assign(Object.assign({}, context.atlantisContextDefaultValues), { locale: "es" }));
120
+ const { result } = renderHook(useAtlantisI18n);
121
+ expect(result.current.formatTime(testDate)).toBe("12:00 AM");
122
+ });
123
+ });
124
+ describe("en-CA (released language, regional variant)", () => {
125
+ it("should preserve the full locale for date formatting", () => {
126
+ spy.mockReturnValueOnce(Object.assign(Object.assign({}, context.atlantisContextDefaultValues), { locale: "en-CA" }));
127
+ const { result } = renderHook(useAtlantisI18n);
128
+ expect(result.current.locale).toBe("en-CA");
129
+ });
130
+ it("should return english translations", () => {
131
+ spy.mockReturnValueOnce(Object.assign(Object.assign({}, context.atlantisContextDefaultValues), { locale: "en-CA" }));
132
+ const { result } = renderHook(useAtlantisI18n);
133
+ expect(result.current.t("cancel")).toBe("Cancel");
134
+ });
135
+ });
136
+ describe("en-GB (released language, regional variant)", () => {
137
+ it("should preserve the full locale for date formatting", () => {
138
+ spy.mockReturnValueOnce(Object.assign(Object.assign({}, context.atlantisContextDefaultValues), { locale: "en-GB" }));
139
+ const { result } = renderHook(useAtlantisI18n);
140
+ expect(result.current.locale).toBe("en-GB");
141
+ });
142
+ it("should return english translations", () => {
143
+ spy.mockReturnValueOnce(Object.assign(Object.assign({}, context.atlantisContextDefaultValues), { locale: "en-GB" }));
144
+ const { result } = renderHook(useAtlantisI18n);
145
+ expect(result.current.t("cancel")).toBe("Cancel");
146
+ });
37
147
  });
38
148
  });
39
149
  describe("Translation files", () => {
@@ -46,11 +156,6 @@ describe("useAtlantisI18n", () => {
46
156
  const { result } = renderHook(useAtlantisI18n);
47
157
  expect(result.current.formatDate(testDate)).toBe("Jan 1, 2020");
48
158
  });
49
- it("should return the date formatted for es", () => {
50
- spy.mockReturnValueOnce(Object.assign(Object.assign({}, context.atlantisContextDefaultValues), { locale: "es" }));
51
- const { result } = renderHook(useAtlantisI18n);
52
- expect(result.current.formatDate(testDate)).toBe("1 ene 2020");
53
- });
54
159
  describe("Timezone", () => {
55
160
  it.each([
56
161
  ["America/New_York", "Dec 31, 2019"],
@@ -70,11 +175,6 @@ describe("useAtlantisI18n", () => {
70
175
  const { result } = renderHook(useAtlantisI18n);
71
176
  expect(result.current.formatTime(testDate)).toBe("12:00 AM");
72
177
  });
73
- it("should return the date formatted for es", () => {
74
- spy.mockReturnValueOnce(Object.assign(Object.assign({}, context.atlantisContextDefaultValues), { locale: "es" }));
75
- const { result } = renderHook(useAtlantisI18n);
76
- expect(result.current.formatTime(testDate)).toBe("00:00");
77
- });
78
178
  describe("Timezone", () => {
79
179
  it.each([
80
180
  ["America/New_York", "7:00 PM"],