@jobber/components-native 0.45.0 → 0.46.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.
- package/dist/package.json +2 -2
- package/dist/src/AutoLink/components/ComposeTextWithLinks/ComposeTextWithLinks.js +3 -3
- package/dist/src/AutoLink/utils.js +14 -3
- package/dist/src/InputDate/InputDate.js +3 -8
- package/dist/src/InputTime/InputTime.js +3 -6
- package/dist/src/hooks/useAtlantisI18n/locales/en.json +4 -0
- package/dist/src/hooks/useAtlantisI18n/locales/es.json +4 -0
- package/dist/src/hooks/useAtlantisI18n/useAtlantisI18n.js +7 -3
- package/dist/src/hooks/useAtlantisI18n/utils/dateFormatter.js +20 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/src/AutoLink/utils.d.ts +2 -2
- package/dist/types/src/hooks/useAtlantisI18n/useAtlantisI18n.d.ts +19 -1
- package/dist/types/src/hooks/useAtlantisI18n/utils/dateFormatter.d.ts +6 -0
- package/package.json +2 -2
- package/src/AutoLink/AutoLink.test.tsx +3 -4
- package/src/AutoLink/components/ComposeTextWithLinks/ComposeTextWithLinks.tsx +3 -3
- package/src/AutoLink/utils.ts +16 -5
- package/src/InputDate/InputDate.tsx +3 -8
- package/src/InputTime/InputTime.tsx +4 -7
- package/src/hooks/useAtlantisI18n/locales/en.json +4 -0
- package/src/hooks/useAtlantisI18n/locales/es.json +4 -0
- package/src/hooks/useAtlantisI18n/useAtlantisI18n.test.ts +82 -2
- package/src/hooks/useAtlantisI18n/useAtlantisI18n.ts +43 -8
- package/src/hooks/useAtlantisI18n/utils/dateFormatter.ts +31 -0
- package/dist/src/AutoLink/messages.js +0 -18
- package/dist/types/src/AutoLink/messages.d.ts +0 -17
- package/src/AutoLink/messages.ts +0 -19
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Match } from "autolinker";
|
|
2
|
-
import {
|
|
2
|
+
import { useAtlantisI18nValue } from "../hooks/useAtlantisI18n";
|
|
3
3
|
export declare function shouldIgnoreURL(text: string, match: Match): boolean;
|
|
4
4
|
export declare function getUrl(match: Match, immediateOpen?: boolean): string;
|
|
5
|
-
export declare function onLongPressLink(match: Match, bottomTabsVisible: boolean,
|
|
5
|
+
export declare function onLongPressLink(match: Match, bottomTabsVisible: boolean, t: useAtlantisI18nValue["t"]): void;
|
|
6
6
|
export declare function onPressLink(match: Match): void;
|
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
import en from "./locales/en.json";
|
|
2
|
+
export type I18nKeys = keyof typeof en;
|
|
2
3
|
export interface useAtlantisI18nValue {
|
|
4
|
+
/**
|
|
5
|
+
* The set locale based on the AtlantisContext.
|
|
6
|
+
*/
|
|
3
7
|
readonly locale: string;
|
|
4
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Returns the translated string depending on the locale. This accepts a 2nd
|
|
10
|
+
* param for string interpolation.
|
|
11
|
+
*/
|
|
12
|
+
readonly t: (message: I18nKeys, values?: Record<string, string>) => string;
|
|
13
|
+
/**
|
|
14
|
+
* Returns a formatted date string based on the locale and the `dateFormat`
|
|
15
|
+
* set in AtlantisContext.
|
|
16
|
+
*/
|
|
17
|
+
readonly formatDate: (date: Date) => string;
|
|
18
|
+
/**
|
|
19
|
+
* Returns a formatted time string based on the locale and the `timeFormat`
|
|
20
|
+
* set in AtlantisContext.
|
|
21
|
+
*/
|
|
22
|
+
readonly formatTime: (date: Date) => string;
|
|
5
23
|
}
|
|
6
24
|
export declare function useAtlantisI18n(): useAtlantisI18nValue;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jobber/components-native",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.46.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": "
|
|
87
|
+
"gitHead": "6ff59b16b38fdf784fa15bcfa41eb97181d2f6b0"
|
|
88
88
|
}
|
|
@@ -2,7 +2,6 @@ import React from "react";
|
|
|
2
2
|
import { fireEvent, render } from "@testing-library/react-native";
|
|
3
3
|
import { copyTextToClipboard } from "./clipboard";
|
|
4
4
|
import { AutoLink } from "./AutoLink";
|
|
5
|
-
import { messages } from "./messages";
|
|
6
5
|
|
|
7
6
|
const mockOpenUrl = jest.fn();
|
|
8
7
|
jest.mock("react-native/Libraries/Linking/Linking", () => ({
|
|
@@ -48,7 +47,7 @@ describe("AutoLink", () => {
|
|
|
48
47
|
fireEvent(getByText(linkText), "onLongPress");
|
|
49
48
|
|
|
50
49
|
const expectedToastConfig = {
|
|
51
|
-
message:
|
|
50
|
+
message: "URL copied",
|
|
52
51
|
bottomTabsVisible: true,
|
|
53
52
|
};
|
|
54
53
|
expect(copyTextToClipboard).toHaveBeenCalledWith(
|
|
@@ -104,7 +103,7 @@ describe("AutoLink", () => {
|
|
|
104
103
|
fireEvent(getByText(emailText), "onLongPress");
|
|
105
104
|
|
|
106
105
|
const expectedToastConfig = {
|
|
107
|
-
message:
|
|
106
|
+
message: "Email copied",
|
|
108
107
|
bottomTabsVisible: true,
|
|
109
108
|
};
|
|
110
109
|
expect(copyTextToClipboard).toHaveBeenCalledWith(
|
|
@@ -158,7 +157,7 @@ describe("AutoLink", () => {
|
|
|
158
157
|
fireEvent(getByText(phoneText), "onLongPress");
|
|
159
158
|
|
|
160
159
|
const expectedToastConfig = {
|
|
161
|
-
message:
|
|
160
|
+
message: "Phone number copied",
|
|
162
161
|
bottomTabsVisible: true,
|
|
163
162
|
};
|
|
164
163
|
expect(copyTextToClipboard).toHaveBeenCalledWith(
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { useIntl } from "react-intl";
|
|
3
2
|
import { Platform } from "react-native";
|
|
4
3
|
import { ComposeTextWithLinksProps } from "../../types";
|
|
5
4
|
import { onLongPressLink, onPressLink } from "../../utils";
|
|
6
5
|
import { Link } from "../Link/Link";
|
|
7
6
|
import { Text } from "../../../Text";
|
|
7
|
+
import { useAtlantisI18n } from "../../../hooks/useAtlantisI18n";
|
|
8
8
|
|
|
9
9
|
export function ComposeTextWithLinks({
|
|
10
10
|
part,
|
|
@@ -13,7 +13,7 @@ export function ComposeTextWithLinks({
|
|
|
13
13
|
bottomTabsVisible,
|
|
14
14
|
selectable = true,
|
|
15
15
|
}: ComposeTextWithLinksProps): JSX.Element {
|
|
16
|
-
const {
|
|
16
|
+
const { t } = useAtlantisI18n();
|
|
17
17
|
|
|
18
18
|
const isLink = match?.getType();
|
|
19
19
|
|
|
@@ -26,7 +26,7 @@ export function ComposeTextWithLinks({
|
|
|
26
26
|
if (selectable && Platform.OS === "android") {
|
|
27
27
|
return;
|
|
28
28
|
}
|
|
29
|
-
onLongPressLink(match, bottomTabsVisible,
|
|
29
|
+
onLongPressLink(match, bottomTabsVisible, t);
|
|
30
30
|
}}
|
|
31
31
|
>
|
|
32
32
|
{match.getAnchorText()}
|
package/src/AutoLink/utils.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { EmailMatch, Match, PhoneMatch } from "autolinker";
|
|
2
|
-
import { MessageDescriptor } from "react-intl";
|
|
3
2
|
import { Linking } from "react-native";
|
|
4
|
-
import { messages } from "./messages";
|
|
5
|
-
import { LinkType } from "./types";
|
|
6
3
|
import { copyTextToClipboard } from "./clipboard";
|
|
4
|
+
import { I18nKeys, useAtlantisI18nValue } from "../hooks/useAtlantisI18n";
|
|
7
5
|
|
|
8
6
|
function hasPrefix(text: string, prefixes: string[]): boolean {
|
|
9
7
|
return prefixes.some(prefix => text.includes(prefix));
|
|
@@ -46,12 +44,12 @@ export function getUrl(match: Match, immediateOpen = true): string {
|
|
|
46
44
|
export function onLongPressLink(
|
|
47
45
|
match: Match,
|
|
48
46
|
bottomTabsVisible: boolean,
|
|
49
|
-
|
|
47
|
+
t: useAtlantisI18nValue["t"],
|
|
50
48
|
): void {
|
|
51
49
|
const linkUrl = getUrl(match, false);
|
|
52
50
|
|
|
53
51
|
const toastConfig = {
|
|
54
|
-
message:
|
|
52
|
+
message: t(getMessageKey(match)),
|
|
55
53
|
bottomTabsVisible,
|
|
56
54
|
};
|
|
57
55
|
copyTextToClipboard(linkUrl, toastConfig);
|
|
@@ -61,3 +59,16 @@ export function onPressLink(match: Match): void {
|
|
|
61
59
|
const linkUrl = getUrl(match);
|
|
62
60
|
Linking.openURL(linkUrl);
|
|
63
61
|
}
|
|
62
|
+
|
|
63
|
+
function getMessageKey(match: Match): I18nKeys {
|
|
64
|
+
switch (match.getType()) {
|
|
65
|
+
case "email":
|
|
66
|
+
return "AutoLink.emailCopied";
|
|
67
|
+
case "phone":
|
|
68
|
+
return "AutoLink.phoneCopied";
|
|
69
|
+
case "url":
|
|
70
|
+
return "AutoLink.urlCopied";
|
|
71
|
+
default:
|
|
72
|
+
return "copied";
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -3,12 +3,9 @@ import DateTimePicker from "react-native-modal-datetime-picker";
|
|
|
3
3
|
import { Platform } from "react-native";
|
|
4
4
|
import { FieldError, UseControllerProps } from "react-hook-form";
|
|
5
5
|
import { XOR } from "ts-xor";
|
|
6
|
-
import { utcToZonedTime } from "date-fns-tz";
|
|
7
|
-
import { format as formatDate } from "date-fns";
|
|
8
6
|
import { Clearable, InputFieldWrapperProps } from "../InputFieldWrapper";
|
|
9
7
|
import { FormField } from "../FormField";
|
|
10
8
|
import { InputPressable } from "../InputPressable";
|
|
11
|
-
import { useAtlantisContext } from "../AtlantisContext";
|
|
12
9
|
import { useAtlantisI18n } from "../hooks/useAtlantisI18n";
|
|
13
10
|
|
|
14
11
|
interface BaseInputDateProps
|
|
@@ -153,8 +150,7 @@ function InternalInputDate({
|
|
|
153
150
|
accessibilityHint,
|
|
154
151
|
}: InputDateProps): JSX.Element {
|
|
155
152
|
const [showPicker, setShowPicker] = useState(false);
|
|
156
|
-
const { t, locale } = useAtlantisI18n();
|
|
157
|
-
const { timeZone, dateFormat } = useAtlantisContext();
|
|
153
|
+
const { t, locale, formatDate } = useAtlantisI18n();
|
|
158
154
|
|
|
159
155
|
const date = useMemo(() => {
|
|
160
156
|
if (typeof value === "string") return new Date(value);
|
|
@@ -163,12 +159,11 @@ function InternalInputDate({
|
|
|
163
159
|
|
|
164
160
|
const formattedDate = useMemo(() => {
|
|
165
161
|
if (date) {
|
|
166
|
-
|
|
167
|
-
return formatDate(zonedTime, dateFormat);
|
|
162
|
+
return formatDate(date);
|
|
168
163
|
}
|
|
169
164
|
|
|
170
165
|
return emptyValueLabel;
|
|
171
|
-
}, [date, emptyValueLabel
|
|
166
|
+
}, [date, emptyValueLabel]);
|
|
172
167
|
|
|
173
168
|
const canClearDate = formattedDate === emptyValueLabel ? "never" : clearable;
|
|
174
169
|
|
|
@@ -3,8 +3,6 @@ import { FieldError, UseControllerProps } from "react-hook-form";
|
|
|
3
3
|
import { XOR } from "ts-xor";
|
|
4
4
|
import DateTimePicker from "react-native-modal-datetime-picker";
|
|
5
5
|
import { View } from "react-native";
|
|
6
|
-
import { utcToZonedTime } from "date-fns-tz";
|
|
7
|
-
import { format as formatTime } from "date-fns";
|
|
8
6
|
import { styles } from "./InputTime.style";
|
|
9
7
|
import { getTimeZoneOffsetInMinutes, roundUpToNearestMinutes } from "./utils";
|
|
10
8
|
import { useAtlantisContext } from "../AtlantisContext";
|
|
@@ -134,9 +132,9 @@ function InternalInputTime({
|
|
|
134
132
|
showIcon = true,
|
|
135
133
|
}: InputTimeProps): JSX.Element {
|
|
136
134
|
const [showPicker, setShowPicker] = useState(false);
|
|
137
|
-
const { t } = useAtlantisI18n();
|
|
138
|
-
|
|
135
|
+
const { t, formatTime } = useAtlantisI18n();
|
|
139
136
|
const { timeZone, timeFormat } = useAtlantisContext();
|
|
137
|
+
|
|
140
138
|
const is24Hour = timeFormat === "HH:mm";
|
|
141
139
|
|
|
142
140
|
const dateTime = useMemo(
|
|
@@ -146,12 +144,11 @@ function InternalInputTime({
|
|
|
146
144
|
|
|
147
145
|
const formattedTime = useMemo(() => {
|
|
148
146
|
if (dateTime) {
|
|
149
|
-
|
|
150
|
-
return formatTime(zonedTime, timeFormat);
|
|
147
|
+
return formatTime(dateTime);
|
|
151
148
|
}
|
|
152
149
|
|
|
153
150
|
return emptyValueLabel;
|
|
154
|
-
}, [dateTime, emptyValueLabel
|
|
151
|
+
}, [dateTime, emptyValueLabel]);
|
|
155
152
|
|
|
156
153
|
const canClearTime = formattedTime === emptyValueLabel ? "never" : clearable;
|
|
157
154
|
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
+
"AutoLink.emailCopied": "Correo electrónico copiado",
|
|
3
|
+
"AutoLink.phoneCopied": "Número de teléfono copiado",
|
|
4
|
+
"AutoLink.urlCopied": "URL copiada",
|
|
2
5
|
"cancel": "Cancelar",
|
|
3
6
|
"confirm": "Confirmar",
|
|
7
|
+
"copied": "Copiado",
|
|
4
8
|
"date": "Fecha",
|
|
5
9
|
"dismiss": "Descartar",
|
|
6
10
|
"done": "Listo",
|
|
@@ -10,6 +10,15 @@ jest.mock("../../AtlantisContext", () => ({
|
|
|
10
10
|
...jest.requireActual("../../AtlantisContext"),
|
|
11
11
|
}));
|
|
12
12
|
|
|
13
|
+
const spy = jest.spyOn(context, "useAtlantisContext");
|
|
14
|
+
const testDate = new Date("2020-01-01T00:00:00.000Z");
|
|
15
|
+
const dateAfterSpringForward = new Date("2020-04-10T00:00:00.000Z");
|
|
16
|
+
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
jest.useFakeTimers();
|
|
19
|
+
jest.setSystemTime(testDate);
|
|
20
|
+
});
|
|
21
|
+
|
|
13
22
|
describe("useAtlantisI18n", () => {
|
|
14
23
|
it("should return english by default", () => {
|
|
15
24
|
const { result } = renderHook(useAtlantisI18n);
|
|
@@ -27,7 +36,6 @@ describe("useAtlantisI18n", () => {
|
|
|
27
36
|
|
|
28
37
|
describe("Español", () => {
|
|
29
38
|
it("should return español", () => {
|
|
30
|
-
const spy = jest.spyOn(context, "useAtlantisContext");
|
|
31
39
|
spy.mockReturnValueOnce({ ...context.defaultValues, locale: "es" });
|
|
32
40
|
const { result } = renderHook(useAtlantisI18n);
|
|
33
41
|
|
|
@@ -37,7 +45,6 @@ describe("useAtlantisI18n", () => {
|
|
|
37
45
|
|
|
38
46
|
describe("Unsupported language", () => {
|
|
39
47
|
it("should return the english translation", () => {
|
|
40
|
-
const spy = jest.spyOn(context, "useAtlantisContext");
|
|
41
48
|
spy.mockReturnValueOnce({ ...context.defaultValues, locale: "fr" });
|
|
42
49
|
const { result } = renderHook(useAtlantisI18n);
|
|
43
50
|
|
|
@@ -50,4 +57,77 @@ describe("useAtlantisI18n", () => {
|
|
|
50
57
|
expect(Object.keys(en)).toEqual(Object.keys(es));
|
|
51
58
|
});
|
|
52
59
|
});
|
|
60
|
+
|
|
61
|
+
describe("formatDate", () => {
|
|
62
|
+
it("should return the formatted date", () => {
|
|
63
|
+
const { result } = renderHook(useAtlantisI18n);
|
|
64
|
+
expect(result.current.formatDate(testDate)).toBe("Jan 1, 2020");
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("should return the date formatted for es", () => {
|
|
68
|
+
spy.mockReturnValueOnce({ ...context.defaultValues, locale: "es" });
|
|
69
|
+
|
|
70
|
+
const { result } = renderHook(useAtlantisI18n);
|
|
71
|
+
expect(result.current.formatDate(testDate)).toBe("1 ene 2020");
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe("Timezone", () => {
|
|
75
|
+
it.each([
|
|
76
|
+
["America/New_York", "Dec 31, 2019"],
|
|
77
|
+
["America/Chicago", "Dec 31, 2019"],
|
|
78
|
+
["America/Denver", "Dec 31, 2019"],
|
|
79
|
+
["Europe/London", "Jan 1, 2020"],
|
|
80
|
+
["Australia/Sydney", "Jan 1, 2020"],
|
|
81
|
+
])("should return the %s time", (timeZone, expected) => {
|
|
82
|
+
spy.mockReturnValueOnce({ ...context.defaultValues, timeZone });
|
|
83
|
+
|
|
84
|
+
const { result } = renderHook(useAtlantisI18n);
|
|
85
|
+
expect(result.current.formatDate(testDate)).toBe(expected);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
describe("formatTime", () => {
|
|
91
|
+
it("should return the formatted time", () => {
|
|
92
|
+
const { result } = renderHook(useAtlantisI18n);
|
|
93
|
+
expect(result.current.formatTime(testDate)).toBe("12:00 AM");
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("should return the date formatted for es", () => {
|
|
97
|
+
spy.mockReturnValueOnce({ ...context.defaultValues, locale: "es" });
|
|
98
|
+
|
|
99
|
+
const { result } = renderHook(useAtlantisI18n);
|
|
100
|
+
expect(result.current.formatTime(testDate)).toBe("00:00");
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe("Timezone", () => {
|
|
104
|
+
it.each([
|
|
105
|
+
["America/New_York", "7:00 PM"],
|
|
106
|
+
["America/Chicago", "6:00 PM"],
|
|
107
|
+
["America/Denver", "5:00 PM"],
|
|
108
|
+
["Europe/London", "12:00 AM"],
|
|
109
|
+
["Australia/Sydney", "11:00 AM"],
|
|
110
|
+
])("should return the %s zoned time", (timeZone, expected) => {
|
|
111
|
+
spy.mockReturnValueOnce({ ...context.defaultValues, timeZone });
|
|
112
|
+
|
|
113
|
+
const { result } = renderHook(useAtlantisI18n);
|
|
114
|
+
expect(result.current.formatTime(testDate)).toBe(expected);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it.each([
|
|
118
|
+
["America/New_York", "8:00 PM"],
|
|
119
|
+
["America/Chicago", "7:00 PM"],
|
|
120
|
+
["America/Denver", "6:00 PM"],
|
|
121
|
+
["Europe/London", "1:00 AM"],
|
|
122
|
+
["Australia/Sydney", "10:00 AM"],
|
|
123
|
+
])("should return the %s spring zoned time", (timeZone, expected) => {
|
|
124
|
+
spy.mockReturnValueOnce({ ...context.defaultValues, timeZone });
|
|
125
|
+
|
|
126
|
+
const { result } = renderHook(useAtlantisI18n);
|
|
127
|
+
expect(result.current.formatTime(dateAfterSpringForward)).toBe(
|
|
128
|
+
expected,
|
|
129
|
+
);
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
});
|
|
53
133
|
});
|
|
@@ -1,21 +1,56 @@
|
|
|
1
|
+
import { useCallback } from "react";
|
|
1
2
|
import en from "./locales/en.json";
|
|
2
3
|
import es from "./locales/es.json";
|
|
4
|
+
import { dateFormatter } from "./utils/dateFormatter";
|
|
3
5
|
import { useAtlantisContext } from "../../AtlantisContext";
|
|
4
6
|
|
|
7
|
+
export type I18nKeys = keyof typeof en;
|
|
8
|
+
|
|
5
9
|
export interface useAtlantisI18nValue {
|
|
10
|
+
/**
|
|
11
|
+
* The set locale based on the AtlantisContext.
|
|
12
|
+
*/
|
|
6
13
|
readonly locale: string;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Returns the translated string depending on the locale. This accepts a 2nd
|
|
17
|
+
* param for string interpolation.
|
|
18
|
+
*/
|
|
19
|
+
readonly t: (message: I18nKeys, values?: Record<string, string>) => string;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Returns a formatted date string based on the locale and the `dateFormat`
|
|
23
|
+
* set in AtlantisContext.
|
|
24
|
+
*/
|
|
25
|
+
readonly formatDate: (date: Date) => string;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Returns a formatted time string based on the locale and the `timeFormat`
|
|
29
|
+
* set in AtlantisContext.
|
|
30
|
+
*/
|
|
31
|
+
readonly formatTime: (date: Date) => string;
|
|
11
32
|
}
|
|
12
33
|
|
|
13
34
|
export function useAtlantisI18n(): useAtlantisI18nValue {
|
|
14
|
-
const { locale } = useAtlantisContext();
|
|
15
|
-
|
|
16
|
-
|
|
35
|
+
const { locale, dateFormat, timeFormat, timeZone } = useAtlantisContext();
|
|
36
|
+
|
|
37
|
+
const t = useCallback(
|
|
38
|
+
(messageKey: keyof typeof en, values?: Record<string, string>) =>
|
|
39
|
+
formatMessage(messageKey, values, locale),
|
|
40
|
+
[formatMessage, locale],
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
const formatDate = useCallback(
|
|
44
|
+
(date: Date) => dateFormatter(date, dateFormat, { locale, timeZone }),
|
|
45
|
+
[dateFormatter, locale],
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
const formatTime = useCallback(
|
|
49
|
+
(date: Date) => dateFormatter(date, timeFormat, { locale, timeZone }),
|
|
50
|
+
[dateFormatter, locale],
|
|
51
|
+
);
|
|
17
52
|
|
|
18
|
-
return { locale, t };
|
|
53
|
+
return { locale, t, formatDate, formatTime };
|
|
19
54
|
}
|
|
20
55
|
|
|
21
56
|
function getLocalizedStrings(locale: string): typeof en {
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { format } from "date-fns";
|
|
2
|
+
import { utcToZonedTime } from "date-fns-tz";
|
|
3
|
+
import { es } from "date-fns/locale";
|
|
4
|
+
|
|
5
|
+
interface DateFormatterOptions {
|
|
6
|
+
readonly locale: string;
|
|
7
|
+
readonly timeZone: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function dateFormatter(
|
|
11
|
+
date: Date,
|
|
12
|
+
dateTimeFormat: string,
|
|
13
|
+
{ locale, timeZone }: DateFormatterOptions,
|
|
14
|
+
): string {
|
|
15
|
+
const zonedTime = utcToZonedTime(date, timeZone);
|
|
16
|
+
return format(zonedTime, dateTimeFormat, {
|
|
17
|
+
locale: getDateFnsLocale(locale),
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Change locale string to date-fns locale object.
|
|
23
|
+
*/
|
|
24
|
+
function getDateFnsLocale(locale?: string): Locale | undefined {
|
|
25
|
+
switch (locale) {
|
|
26
|
+
case "es":
|
|
27
|
+
return es;
|
|
28
|
+
default:
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { defineMessages } from "react-intl";
|
|
2
|
-
export const messages = defineMessages({
|
|
3
|
-
phoneCopied: {
|
|
4
|
-
id: "phoneCopied",
|
|
5
|
-
defaultMessage: "Phone number copied",
|
|
6
|
-
description: "Message shown after copying a phone number",
|
|
7
|
-
},
|
|
8
|
-
emailCopied: {
|
|
9
|
-
id: "emailCopied",
|
|
10
|
-
defaultMessage: "Email copied",
|
|
11
|
-
description: "Message shown after copying an email",
|
|
12
|
-
},
|
|
13
|
-
urlCopied: {
|
|
14
|
-
id: "urlCopied",
|
|
15
|
-
defaultMessage: "URL copied",
|
|
16
|
-
description: "Message shown after copying a URL",
|
|
17
|
-
},
|
|
18
|
-
});
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export declare const messages: {
|
|
2
|
-
phoneCopied: {
|
|
3
|
-
id: string;
|
|
4
|
-
defaultMessage: string;
|
|
5
|
-
description: string;
|
|
6
|
-
};
|
|
7
|
-
emailCopied: {
|
|
8
|
-
id: string;
|
|
9
|
-
defaultMessage: string;
|
|
10
|
-
description: string;
|
|
11
|
-
};
|
|
12
|
-
urlCopied: {
|
|
13
|
-
id: string;
|
|
14
|
-
defaultMessage: string;
|
|
15
|
-
description: string;
|
|
16
|
-
};
|
|
17
|
-
};
|
package/src/AutoLink/messages.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { defineMessages } from "react-intl";
|
|
2
|
-
|
|
3
|
-
export const messages = defineMessages({
|
|
4
|
-
phoneCopied: {
|
|
5
|
-
id: "phoneCopied",
|
|
6
|
-
defaultMessage: "Phone number copied",
|
|
7
|
-
description: "Message shown after copying a phone number",
|
|
8
|
-
},
|
|
9
|
-
emailCopied: {
|
|
10
|
-
id: "emailCopied",
|
|
11
|
-
defaultMessage: "Email copied",
|
|
12
|
-
description: "Message shown after copying an email",
|
|
13
|
-
},
|
|
14
|
-
urlCopied: {
|
|
15
|
-
id: "urlCopied",
|
|
16
|
-
defaultMessage: "URL copied",
|
|
17
|
-
description: "Message shown after copying a URL",
|
|
18
|
-
},
|
|
19
|
-
});
|