@trackunit/react-date-and-time-hooks 2.1.5 → 2.1.6
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/index.cjs.js +49 -91
- package/index.esm.js +49 -93
- package/package.json +8 -15
- package/src/AssetTimezoneContext.d.ts +24 -0
- package/src/index.d.ts +1 -0
- package/src/useTimezone.d.ts +7 -23
- package/src/generated/graphql-api/fragment-masking.d.ts +0 -19
- package/src/generated/graphql-api/gql.d.ts +0 -37
- package/src/generated/graphql-api/graphql.d.ts +0 -142
- package/src/generated/graphql-api/index.d.ts +0 -2
- package/src/test/index.d.ts +0 -1
- package/src/test/mocks/mockAssetTimezone.d.ts +0 -17
package/index.cjs.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var react = require('react');
|
|
3
4
|
var dateAndTimeUtils = require('@trackunit/date-and-time-utils');
|
|
4
5
|
var sharedUtils = require('@trackunit/shared-utils');
|
|
5
|
-
var react = require('react');
|
|
6
6
|
var irisAppRuntimeCoreApi = require('@trackunit/iris-app-runtime-core-api');
|
|
7
|
-
var reactComponents = require('@trackunit/react-components');
|
|
8
7
|
var reactCoreHooks = require('@trackunit/react-core-hooks');
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
|
|
9
|
+
const AssetTimezoneContext = react.createContext({ assetTimeZone: null });
|
|
10
|
+
/** Returns the resolved asset timezone from the nearest AssetTimezoneProvider in the component tree. */
|
|
11
|
+
const useAssetTimezoneContext = () => react.useContext(AssetTimezoneContext);
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Try to convert to ISO standard. ex. en becomes en-GB if its in United Kingdom.
|
|
@@ -39,78 +40,38 @@ const useLocale = () => {
|
|
|
39
40
|
return userLocale || BrowserLocale;
|
|
40
41
|
};
|
|
41
42
|
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
kind: "Argument",
|
|
65
|
-
name: { kind: "Name", value: "id" },
|
|
66
|
-
value: { kind: "Variable", name: { kind: "Name", value: "assetId" } },
|
|
67
|
-
},
|
|
68
|
-
],
|
|
69
|
-
selectionSet: {
|
|
70
|
-
kind: "SelectionSet",
|
|
71
|
-
selections: [
|
|
72
|
-
{
|
|
73
|
-
kind: "Field",
|
|
74
|
-
name: { kind: "Name", value: "locations" },
|
|
75
|
-
selectionSet: {
|
|
76
|
-
kind: "SelectionSet",
|
|
77
|
-
selections: [
|
|
78
|
-
{
|
|
79
|
-
kind: "Field",
|
|
80
|
-
name: { kind: "Name", value: "latest" },
|
|
81
|
-
selectionSet: {
|
|
82
|
-
kind: "SelectionSet",
|
|
83
|
-
selections: [
|
|
84
|
-
{
|
|
85
|
-
kind: "Field",
|
|
86
|
-
name: { kind: "Name", value: "properties" },
|
|
87
|
-
selectionSet: {
|
|
88
|
-
kind: "SelectionSet",
|
|
89
|
-
selections: [{ kind: "Field", name: { kind: "Name", value: "timeZone" } }],
|
|
90
|
-
},
|
|
91
|
-
},
|
|
92
|
-
],
|
|
93
|
-
},
|
|
94
|
-
},
|
|
95
|
-
],
|
|
96
|
-
},
|
|
97
|
-
},
|
|
98
|
-
],
|
|
99
|
-
},
|
|
100
|
-
},
|
|
101
|
-
],
|
|
102
|
-
},
|
|
103
|
-
},
|
|
104
|
-
],
|
|
43
|
+
const CUSTOM_TIMEZONE_KEY = "customTimeZone";
|
|
44
|
+
const readTimezoneFromStorage = () => {
|
|
45
|
+
try {
|
|
46
|
+
const raw = localStorage.getItem(CUSTOM_TIMEZONE_KEY);
|
|
47
|
+
if (raw === null)
|
|
48
|
+
return null;
|
|
49
|
+
const parsed = JSON.parse(raw);
|
|
50
|
+
if (typeof parsed === "string")
|
|
51
|
+
return parsed;
|
|
52
|
+
if (parsed !== null &&
|
|
53
|
+
typeof parsed === "object" &&
|
|
54
|
+
"__serializer" in parsed &&
|
|
55
|
+
parsed.__serializer === "superjson" &&
|
|
56
|
+
"json" in parsed &&
|
|
57
|
+
typeof parsed.json === "string") {
|
|
58
|
+
return parsed.json;
|
|
59
|
+
}
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
105
65
|
};
|
|
106
|
-
|
|
107
|
-
const customTimeZoneSchema = zod.z.string().nullable();
|
|
108
66
|
/**
|
|
109
67
|
* Resolves the active timezone based on user preference, custom override, and optional asset location.
|
|
110
68
|
*
|
|
111
69
|
* Returns `current` (browser or custom override), `preferred` (resolved per user settings
|
|
112
70
|
* and optional asset), and `assetTimeZone` (fetched from the asset's GPS location).
|
|
113
71
|
*
|
|
72
|
+
* The asset timezone is resolved by the nearest `AssetTimezoneProvider` in the component tree.
|
|
73
|
+
* Use `AssetTimezoneProvider` on asset-detail pages to enable machine-timezone resolution.
|
|
74
|
+
*
|
|
114
75
|
* **When to use:**
|
|
115
76
|
* - Use `useTimezone` whenever you need to display or calculate dates in the correct
|
|
116
77
|
* timezone — especially on asset-detail pages where the machine's timezone may differ
|
|
@@ -119,28 +80,23 @@ const customTimeZoneSchema = zod.z.string().nullable();
|
|
|
119
80
|
* - Do **not** rely on `Intl.DateTimeFormat().resolvedOptions().timeZone` directly —
|
|
120
81
|
* this hook respects the user's preference setting (browser, machine, or custom).
|
|
121
82
|
*/
|
|
122
|
-
const useTimezone = (
|
|
123
|
-
const {
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
},
|
|
134
|
-
skip: !assetId,
|
|
135
|
-
fetchPolicy: "cache-first",
|
|
136
|
-
});
|
|
137
|
-
const assetTimeZone = react.useMemo(() => {
|
|
138
|
-
const timezone = timeZoneData?.asset?.locations?.latest?.properties?.timeZone;
|
|
139
|
-
if (!timezone) {
|
|
140
|
-
return null;
|
|
83
|
+
const useTimezone = () => {
|
|
84
|
+
const { assetTimeZone } = useAssetTimezoneContext();
|
|
85
|
+
const { timeZonePreference, customTimezone: contextCustomTimezone } = reactCoreHooks.useCurrentUserTimeZonePreference();
|
|
86
|
+
const [localStorageCustomTimezone, setLocalStorageCustomTimezone] = react.useState(readTimezoneFromStorage);
|
|
87
|
+
const setCustomTimezone = react.useCallback((timezone) => {
|
|
88
|
+
setLocalStorageCustomTimezone(timezone);
|
|
89
|
+
if (timezone === null) {
|
|
90
|
+
localStorage.removeItem(CUSTOM_TIMEZONE_KEY);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
localStorage.setItem(CUSTOM_TIMEZONE_KEY, JSON.stringify(timezone));
|
|
141
94
|
}
|
|
142
|
-
|
|
143
|
-
|
|
95
|
+
}, []);
|
|
96
|
+
// undefined → host did not send this field (old host without Penpal support); fall back to localStorage.
|
|
97
|
+
// null → host explicitly has no custom timezone; do NOT fall back to potentially stale iframe localStorage.
|
|
98
|
+
// string → host-provided value; use it directly.
|
|
99
|
+
const customTimezone = contextCustomTimezone !== undefined ? contextCustomTimezone : localStorageCustomTimezone;
|
|
144
100
|
const current = react.useMemo(() => {
|
|
145
101
|
const id = dateAndTimeUtils.Temporal.Now.timeZoneId();
|
|
146
102
|
if (timeZonePreference === irisAppRuntimeCoreApi.TimeZonePreference.CustomTimeZone && customTimezone) {
|
|
@@ -154,7 +110,7 @@ const useTimezone = ({ assetId } = {}) => {
|
|
|
154
110
|
}
|
|
155
111
|
return current;
|
|
156
112
|
}, [timeZonePreference, current, assetTimeZone]);
|
|
157
|
-
return react.useMemo(() => ({ current, assetTimeZone, preferred, setCustomTimezone }), [current, assetTimeZone, preferred, setCustomTimezone]);
|
|
113
|
+
return react.useMemo(() => ({ current, assetTimeZone, preferred, setCustomTimezone, customTimezone }), [current, assetTimeZone, preferred, setCustomTimezone, customTimezone]);
|
|
158
114
|
};
|
|
159
115
|
|
|
160
116
|
/**
|
|
@@ -553,7 +509,9 @@ const useDateAndTime = () => {
|
|
|
553
509
|
]);
|
|
554
510
|
};
|
|
555
511
|
|
|
512
|
+
exports.AssetTimezoneContext = AssetTimezoneContext;
|
|
556
513
|
exports.convertToLocale = convertToLocale;
|
|
514
|
+
exports.useAssetTimezoneContext = useAssetTimezoneContext;
|
|
557
515
|
exports.useDateAndTime = useDateAndTime;
|
|
558
516
|
exports.useLocale = useLocale;
|
|
559
517
|
exports.useTimezone = useTimezone;
|
package/index.esm.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createContext, useContext, useState, useCallback, useMemo } from 'react';
|
|
2
|
+
import { Temporal, getTimeZone, toDateUtil, toZonedDateTimeUtil, formatDateUtil, formatRangeUtil, subtractYearsUtil, subtractMonthsUtil, subtractWeeksUtil, subtractDaysUtil, subtractHoursUtil, subtractMinutesUtil, addYearsUtil, addMonthsUtil, addWeeksUtil, addDaysUtil, addHoursUtil, addMinutesUtil, startOfMonthUtil, startOfWeekUtil, startOfDayUtil, startOfHourUtil, startOfMinuteUtil, endOfMonthUtil, endOfWeekUtil, endOfDayUtil, endOfHourUtil, endOfMinuteUtil, differenceInYearsUtil, differenceInMonthsUtil, differenceInWeeksUtil, differenceInDaysUtil, differenceInHoursUtil, differenceInMinutesUtil, differenceInSecondsUtil, isBetweenUtil, isTodayUtil, isFutureUtil, isPastUtil, isSameYearUtil, isSameMonthUtil, isSameWeekUtil, isSameDayUtil, timeSinceInYears, timeSinceInMonths, timeSinceInDays, timeSinceInHours, timeSinceInMinutes, timeSinceInSeconds, timeSinceAuto, toDuration, getDurationFormat, convertMillisecondsUtil, convertSecondsUtil, convertMinutesUtil, convertHoursUtil, dayNameUtil, daysUtil, monthNameUtil, monthsUtil, getUTCFromTimeZonedUtil, isEqualUtil } from '@trackunit/date-and-time-utils';
|
|
2
3
|
import { exhaustiveCheck } from '@trackunit/shared-utils';
|
|
3
|
-
import { useMemo, useCallback } from 'react';
|
|
4
4
|
import { TimeZonePreference } from '@trackunit/iris-app-runtime-core-api';
|
|
5
|
-
import { useLocalStorage } from '@trackunit/react-components';
|
|
6
5
|
import { useCurrentUserTimeZonePreference } from '@trackunit/react-core-hooks';
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
|
|
7
|
+
const AssetTimezoneContext = createContext({ assetTimeZone: null });
|
|
8
|
+
/** Returns the resolved asset timezone from the nearest AssetTimezoneProvider in the component tree. */
|
|
9
|
+
const useAssetTimezoneContext = () => useContext(AssetTimezoneContext);
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Try to convert to ISO standard. ex. en becomes en-GB if its in United Kingdom.
|
|
@@ -37,78 +38,38 @@ const useLocale = () => {
|
|
|
37
38
|
return userLocale || BrowserLocale;
|
|
38
39
|
};
|
|
39
40
|
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
kind: "Argument",
|
|
63
|
-
name: { kind: "Name", value: "id" },
|
|
64
|
-
value: { kind: "Variable", name: { kind: "Name", value: "assetId" } },
|
|
65
|
-
},
|
|
66
|
-
],
|
|
67
|
-
selectionSet: {
|
|
68
|
-
kind: "SelectionSet",
|
|
69
|
-
selections: [
|
|
70
|
-
{
|
|
71
|
-
kind: "Field",
|
|
72
|
-
name: { kind: "Name", value: "locations" },
|
|
73
|
-
selectionSet: {
|
|
74
|
-
kind: "SelectionSet",
|
|
75
|
-
selections: [
|
|
76
|
-
{
|
|
77
|
-
kind: "Field",
|
|
78
|
-
name: { kind: "Name", value: "latest" },
|
|
79
|
-
selectionSet: {
|
|
80
|
-
kind: "SelectionSet",
|
|
81
|
-
selections: [
|
|
82
|
-
{
|
|
83
|
-
kind: "Field",
|
|
84
|
-
name: { kind: "Name", value: "properties" },
|
|
85
|
-
selectionSet: {
|
|
86
|
-
kind: "SelectionSet",
|
|
87
|
-
selections: [{ kind: "Field", name: { kind: "Name", value: "timeZone" } }],
|
|
88
|
-
},
|
|
89
|
-
},
|
|
90
|
-
],
|
|
91
|
-
},
|
|
92
|
-
},
|
|
93
|
-
],
|
|
94
|
-
},
|
|
95
|
-
},
|
|
96
|
-
],
|
|
97
|
-
},
|
|
98
|
-
},
|
|
99
|
-
],
|
|
100
|
-
},
|
|
101
|
-
},
|
|
102
|
-
],
|
|
41
|
+
const CUSTOM_TIMEZONE_KEY = "customTimeZone";
|
|
42
|
+
const readTimezoneFromStorage = () => {
|
|
43
|
+
try {
|
|
44
|
+
const raw = localStorage.getItem(CUSTOM_TIMEZONE_KEY);
|
|
45
|
+
if (raw === null)
|
|
46
|
+
return null;
|
|
47
|
+
const parsed = JSON.parse(raw);
|
|
48
|
+
if (typeof parsed === "string")
|
|
49
|
+
return parsed;
|
|
50
|
+
if (parsed !== null &&
|
|
51
|
+
typeof parsed === "object" &&
|
|
52
|
+
"__serializer" in parsed &&
|
|
53
|
+
parsed.__serializer === "superjson" &&
|
|
54
|
+
"json" in parsed &&
|
|
55
|
+
typeof parsed.json === "string") {
|
|
56
|
+
return parsed.json;
|
|
57
|
+
}
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
103
63
|
};
|
|
104
|
-
|
|
105
|
-
const customTimeZoneSchema = z.string().nullable();
|
|
106
64
|
/**
|
|
107
65
|
* Resolves the active timezone based on user preference, custom override, and optional asset location.
|
|
108
66
|
*
|
|
109
67
|
* Returns `current` (browser or custom override), `preferred` (resolved per user settings
|
|
110
68
|
* and optional asset), and `assetTimeZone` (fetched from the asset's GPS location).
|
|
111
69
|
*
|
|
70
|
+
* The asset timezone is resolved by the nearest `AssetTimezoneProvider` in the component tree.
|
|
71
|
+
* Use `AssetTimezoneProvider` on asset-detail pages to enable machine-timezone resolution.
|
|
72
|
+
*
|
|
112
73
|
* **When to use:**
|
|
113
74
|
* - Use `useTimezone` whenever you need to display or calculate dates in the correct
|
|
114
75
|
* timezone — especially on asset-detail pages where the machine's timezone may differ
|
|
@@ -117,28 +78,23 @@ const customTimeZoneSchema = z.string().nullable();
|
|
|
117
78
|
* - Do **not** rely on `Intl.DateTimeFormat().resolvedOptions().timeZone` directly —
|
|
118
79
|
* this hook respects the user's preference setting (browser, machine, or custom).
|
|
119
80
|
*/
|
|
120
|
-
const useTimezone = (
|
|
121
|
-
const {
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
const { data: timeZoneData } = useQuery(GetAssetTimezoneDocument, {
|
|
129
|
-
variables: {
|
|
130
|
-
assetId: assetId ?? "",
|
|
131
|
-
},
|
|
132
|
-
skip: !assetId,
|
|
133
|
-
fetchPolicy: "cache-first",
|
|
134
|
-
});
|
|
135
|
-
const assetTimeZone = useMemo(() => {
|
|
136
|
-
const timezone = timeZoneData?.asset?.locations?.latest?.properties?.timeZone;
|
|
137
|
-
if (!timezone) {
|
|
138
|
-
return null;
|
|
81
|
+
const useTimezone = () => {
|
|
82
|
+
const { assetTimeZone } = useAssetTimezoneContext();
|
|
83
|
+
const { timeZonePreference, customTimezone: contextCustomTimezone } = useCurrentUserTimeZonePreference();
|
|
84
|
+
const [localStorageCustomTimezone, setLocalStorageCustomTimezone] = useState(readTimezoneFromStorage);
|
|
85
|
+
const setCustomTimezone = useCallback((timezone) => {
|
|
86
|
+
setLocalStorageCustomTimezone(timezone);
|
|
87
|
+
if (timezone === null) {
|
|
88
|
+
localStorage.removeItem(CUSTOM_TIMEZONE_KEY);
|
|
139
89
|
}
|
|
140
|
-
|
|
141
|
-
|
|
90
|
+
else {
|
|
91
|
+
localStorage.setItem(CUSTOM_TIMEZONE_KEY, JSON.stringify(timezone));
|
|
92
|
+
}
|
|
93
|
+
}, []);
|
|
94
|
+
// undefined → host did not send this field (old host without Penpal support); fall back to localStorage.
|
|
95
|
+
// null → host explicitly has no custom timezone; do NOT fall back to potentially stale iframe localStorage.
|
|
96
|
+
// string → host-provided value; use it directly.
|
|
97
|
+
const customTimezone = contextCustomTimezone !== undefined ? contextCustomTimezone : localStorageCustomTimezone;
|
|
142
98
|
const current = useMemo(() => {
|
|
143
99
|
const id = Temporal.Now.timeZoneId();
|
|
144
100
|
if (timeZonePreference === TimeZonePreference.CustomTimeZone && customTimezone) {
|
|
@@ -152,7 +108,7 @@ const useTimezone = ({ assetId } = {}) => {
|
|
|
152
108
|
}
|
|
153
109
|
return current;
|
|
154
110
|
}, [timeZonePreference, current, assetTimeZone]);
|
|
155
|
-
return useMemo(() => ({ current, assetTimeZone, preferred, setCustomTimezone }), [current, assetTimeZone, preferred, setCustomTimezone]);
|
|
111
|
+
return useMemo(() => ({ current, assetTimeZone, preferred, setCustomTimezone, customTimezone }), [current, assetTimeZone, preferred, setCustomTimezone, customTimezone]);
|
|
156
112
|
};
|
|
157
113
|
|
|
158
114
|
/**
|
|
@@ -551,4 +507,4 @@ const useDateAndTime = () => {
|
|
|
551
507
|
]);
|
|
552
508
|
};
|
|
553
509
|
|
|
554
|
-
export { convertToLocale, useDateAndTime, useLocale, useTimezone };
|
|
510
|
+
export { AssetTimezoneContext, convertToLocale, useAssetTimezoneContext, useDateAndTime, useLocale, useTimezone };
|
package/package.json
CHANGED
|
@@ -1,28 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trackunit/react-date-and-time-hooks",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.6",
|
|
4
4
|
"repository": "https://github.com/Trackunit/manager",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6
6
|
"engines": {
|
|
7
7
|
"node": ">=24.x"
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
|
-
"@
|
|
11
|
-
"@
|
|
12
|
-
"
|
|
13
|
-
"@trackunit/
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
"@trackunit/
|
|
17
|
-
"@trackunit/react-core-hooks": "1.17.18",
|
|
18
|
-
"@trackunit/react-components": "2.1.4",
|
|
19
|
-
"@trackunit/react-graphql-hooks": "2.1.4",
|
|
20
|
-
"@trackunit/iris-app-runtime-core-api": "1.16.14"
|
|
10
|
+
"@trackunit/date-and-time-utils": "1.13.16",
|
|
11
|
+
"@trackunit/iris-app-runtime-core-api": "1.16.15",
|
|
12
|
+
"@trackunit/shared-utils": "1.15.15",
|
|
13
|
+
"@trackunit/react-core-hooks": "1.17.19"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@trackunit/react-core-contexts-test": "1.17.15"
|
|
21
17
|
},
|
|
22
18
|
"peerDependencies": {
|
|
23
|
-
"@apollo/client": "^3.13.8",
|
|
24
|
-
"@tanstack/react-router": "^1.114.29",
|
|
25
|
-
"graphql": "^16.10.0",
|
|
26
19
|
"react": "^19.0.0"
|
|
27
20
|
},
|
|
28
21
|
"module": "./index.esm.js",
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface TimeZone {
|
|
2
|
+
/**
|
|
3
|
+
* The unique id of the timezone
|
|
4
|
+
*
|
|
5
|
+
* @example "America/Denver"
|
|
6
|
+
*/
|
|
7
|
+
id: string;
|
|
8
|
+
/**
|
|
9
|
+
* The human-readable name of the timezone. Combines id and offset.
|
|
10
|
+
*
|
|
11
|
+
* @example "America/Denver (-06:00 MDT)"
|
|
12
|
+
*/
|
|
13
|
+
name: string;
|
|
14
|
+
/**
|
|
15
|
+
* @example "-06:00 MDT"
|
|
16
|
+
*/
|
|
17
|
+
offset: string;
|
|
18
|
+
}
|
|
19
|
+
export interface AssetTimezoneContextValue {
|
|
20
|
+
assetTimeZone: TimeZone | null;
|
|
21
|
+
}
|
|
22
|
+
export declare const AssetTimezoneContext: import("react").Context<AssetTimezoneContextValue>;
|
|
23
|
+
/** Returns the resolved asset timezone from the nearest AssetTimezoneProvider in the component tree. */
|
|
24
|
+
export declare const useAssetTimezoneContext: () => AssetTimezoneContextValue;
|
package/src/index.d.ts
CHANGED
package/src/useTimezone.d.ts
CHANGED
|
@@ -1,30 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
/**
|
|
3
|
-
* The unique id of the timezone
|
|
4
|
-
*
|
|
5
|
-
* @example "America/Denver"
|
|
6
|
-
*/
|
|
7
|
-
id: string;
|
|
8
|
-
/**
|
|
9
|
-
* The human-readable name of the timezone. Combines id and offset.
|
|
10
|
-
*
|
|
11
|
-
* @example "America/Denver (-06:00 MDT)"
|
|
12
|
-
*/
|
|
13
|
-
name: string;
|
|
14
|
-
/**
|
|
15
|
-
* @example "-06:00 MDT"
|
|
16
|
-
*/
|
|
17
|
-
offset: string;
|
|
18
|
-
}
|
|
1
|
+
import { type TimeZone } from "./AssetTimezoneContext";
|
|
19
2
|
interface UseTimezoneReturn {
|
|
20
3
|
current: TimeZone;
|
|
21
4
|
assetTimeZone: TimeZone | null;
|
|
22
5
|
preferred: TimeZone;
|
|
23
6
|
setCustomTimezone: (timezone: string | null) => void;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
/** supply assetId to fetch the timezone for the given machine */
|
|
27
|
-
assetId?: string;
|
|
7
|
+
/** The resolved custom timezone value (e.g. "America/Denver"). Exposed so host apps can pass it to Iris App iframes via Penpal. */
|
|
8
|
+
customTimezone: string | null;
|
|
28
9
|
}
|
|
29
10
|
/**
|
|
30
11
|
* Resolves the active timezone based on user preference, custom override, and optional asset location.
|
|
@@ -32,6 +13,9 @@ interface TimezoneProps {
|
|
|
32
13
|
* Returns `current` (browser or custom override), `preferred` (resolved per user settings
|
|
33
14
|
* and optional asset), and `assetTimeZone` (fetched from the asset's GPS location).
|
|
34
15
|
*
|
|
16
|
+
* The asset timezone is resolved by the nearest `AssetTimezoneProvider` in the component tree.
|
|
17
|
+
* Use `AssetTimezoneProvider` on asset-detail pages to enable machine-timezone resolution.
|
|
18
|
+
*
|
|
35
19
|
* **When to use:**
|
|
36
20
|
* - Use `useTimezone` whenever you need to display or calculate dates in the correct
|
|
37
21
|
* timezone — especially on asset-detail pages where the machine's timezone may differ
|
|
@@ -40,5 +24,5 @@ interface TimezoneProps {
|
|
|
40
24
|
* - Do **not** rely on `Intl.DateTimeFormat().resolvedOptions().timeZone` directly —
|
|
41
25
|
* this hook respects the user's preference setting (browser, machine, or custom).
|
|
42
26
|
*/
|
|
43
|
-
export declare const useTimezone: (
|
|
27
|
+
export declare const useTimezone: () => UseTimezoneReturn;
|
|
44
28
|
export {};
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { ResultOf, DocumentTypeDecoration, TypedDocumentNode } from '@graphql-typed-document-node/core';
|
|
2
|
-
import { Incremental } from './graphql';
|
|
3
|
-
export type FragmentType<TDocumentType extends DocumentTypeDecoration<any, any>> = TDocumentType extends DocumentTypeDecoration<infer TType, any> ? [TType] extends [{
|
|
4
|
-
' $fragmentName'?: infer TKey;
|
|
5
|
-
}] ? TKey extends string ? {
|
|
6
|
-
' $fragmentRefs'?: {
|
|
7
|
-
[key in TKey]: TType;
|
|
8
|
-
};
|
|
9
|
-
} : never : never : never;
|
|
10
|
-
export declare function getFragmentData<TType>(_documentNode: DocumentTypeDecoration<TType, any>, fragmentType: FragmentType<DocumentTypeDecoration<TType, any>>): TType;
|
|
11
|
-
export declare function getFragmentData<TType>(_documentNode: DocumentTypeDecoration<TType, any>, fragmentType: FragmentType<DocumentTypeDecoration<TType, any>> | undefined): TType | undefined;
|
|
12
|
-
export declare function getFragmentData<TType>(_documentNode: DocumentTypeDecoration<TType, any>, fragmentType: FragmentType<DocumentTypeDecoration<TType, any>> | null): TType | null;
|
|
13
|
-
export declare function getFragmentData<TType>(_documentNode: DocumentTypeDecoration<TType, any>, fragmentType: FragmentType<DocumentTypeDecoration<TType, any>> | null | undefined): TType | null | undefined;
|
|
14
|
-
export declare function getFragmentData<TType>(_documentNode: DocumentTypeDecoration<TType, any>, fragmentType: Array<FragmentType<DocumentTypeDecoration<TType, any>>>): Array<TType>;
|
|
15
|
-
export declare function getFragmentData<TType>(_documentNode: DocumentTypeDecoration<TType, any>, fragmentType: Array<FragmentType<DocumentTypeDecoration<TType, any>>> | null | undefined): Array<TType> | null | undefined;
|
|
16
|
-
export declare function getFragmentData<TType>(_documentNode: DocumentTypeDecoration<TType, any>, fragmentType: ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>>): ReadonlyArray<TType>;
|
|
17
|
-
export declare function getFragmentData<TType>(_documentNode: DocumentTypeDecoration<TType, any>, fragmentType: ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>> | null | undefined): ReadonlyArray<TType> | null | undefined;
|
|
18
|
-
export declare function makeFragmentData<F extends DocumentTypeDecoration<any, any>, FT extends ResultOf<F>>(data: FT, _fragment: F): FragmentType<F>;
|
|
19
|
-
export declare function isFragmentReady<TQuery, TFrag>(queryNode: DocumentTypeDecoration<TQuery, any>, fragmentNode: TypedDocumentNode<TFrag>, data: FragmentType<TypedDocumentNode<Incremental<TFrag>, any>> | null | undefined): data is FragmentType<typeof fragmentNode>;
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import * as types from './graphql';
|
|
2
|
-
import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
|
|
3
|
-
/**
|
|
4
|
-
* Map of all GraphQL operations in the project.
|
|
5
|
-
*
|
|
6
|
-
* This map has several performance disadvantages:
|
|
7
|
-
* 1. It is not tree-shakeable, so it will include all operations in the project.
|
|
8
|
-
* 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle.
|
|
9
|
-
* 3. It does not support dead code elimination, so it will add unused operations.
|
|
10
|
-
*
|
|
11
|
-
* Therefore it is highly recommended to use the babel or swc plugin for production.
|
|
12
|
-
* Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size
|
|
13
|
-
*/
|
|
14
|
-
declare const documents: {
|
|
15
|
-
"query GetAssetTimezone($assetId: ID!) {\n asset(id: $assetId) {\n locations {\n latest {\n properties {\n timeZone\n }\n }\n }\n }\n}": DocumentNode<types.GetAssetTimezoneQuery, types.Exact<{
|
|
16
|
-
assetId: types.Scalars["ID"]["input"];
|
|
17
|
-
}>>;
|
|
18
|
-
};
|
|
19
|
-
/**
|
|
20
|
-
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* @example
|
|
24
|
-
* ```ts
|
|
25
|
-
* const query = graphql(`query GetUser($id: ID!) { user(id: $id) { name } }`);
|
|
26
|
-
* ```
|
|
27
|
-
*
|
|
28
|
-
* The query argument is unknown!
|
|
29
|
-
* Please regenerate the types.
|
|
30
|
-
*/
|
|
31
|
-
export declare function graphql(source: string): unknown;
|
|
32
|
-
/**
|
|
33
|
-
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
|
34
|
-
*/
|
|
35
|
-
export declare function graphql(source: "query GetAssetTimezone($assetId: ID!) {\n asset(id: $assetId) {\n locations {\n latest {\n properties {\n timeZone\n }\n }\n }\n }\n}"): (typeof documents)["query GetAssetTimezone($assetId: ID!) {\n asset(id: $assetId) {\n locations {\n latest {\n properties {\n timeZone\n }\n }\n }\n }\n}"];
|
|
36
|
-
export type DocumentType<TDocumentNode extends DocumentNode<any, any>> = TDocumentNode extends DocumentNode<infer TType, any> ? TType : never;
|
|
37
|
-
export {};
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
import { TypedDocumentNode as DocumentNode } from "@graphql-typed-document-node/core";
|
|
2
|
-
import type { PublicIrisAppManifest } from "@trackunit/iris-app-api";
|
|
3
|
-
export type Maybe<T> = T | null;
|
|
4
|
-
export type InputMaybe<T> = Maybe<T> | undefined;
|
|
5
|
-
export type Exact<T extends {
|
|
6
|
-
[key: string]: unknown;
|
|
7
|
-
}> = {
|
|
8
|
-
[K in keyof T]: T[K];
|
|
9
|
-
};
|
|
10
|
-
export type MakeOptional<T, K extends keyof T> = Omit<T, K> & {
|
|
11
|
-
[SubKey in K]?: Maybe<T[SubKey]>;
|
|
12
|
-
};
|
|
13
|
-
export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & {
|
|
14
|
-
[SubKey in K]: Maybe<T[SubKey]>;
|
|
15
|
-
};
|
|
16
|
-
export type MakeEmpty<T extends {
|
|
17
|
-
[key: string]: unknown;
|
|
18
|
-
}, K extends keyof T> = {
|
|
19
|
-
[_ in K]?: never;
|
|
20
|
-
};
|
|
21
|
-
export type Incremental<T> = T | {
|
|
22
|
-
[P in keyof T]?: P extends " $fragmentName" | "__typename" ? T[P] : never;
|
|
23
|
-
};
|
|
24
|
-
export type DateTimeISOString = string;
|
|
25
|
-
/** All built-in and custom scalars, mapped to their actual values */
|
|
26
|
-
export type Scalars = {
|
|
27
|
-
ID: {
|
|
28
|
-
input: string;
|
|
29
|
-
output: string;
|
|
30
|
-
};
|
|
31
|
-
String: {
|
|
32
|
-
input: string;
|
|
33
|
-
output: string;
|
|
34
|
-
};
|
|
35
|
-
Boolean: {
|
|
36
|
-
input: boolean;
|
|
37
|
-
output: boolean;
|
|
38
|
-
};
|
|
39
|
-
Int: {
|
|
40
|
-
input: number;
|
|
41
|
-
output: number;
|
|
42
|
-
};
|
|
43
|
-
Float: {
|
|
44
|
-
input: number;
|
|
45
|
-
output: number;
|
|
46
|
-
};
|
|
47
|
-
/** The ISO 4217 currency code of the monetary field definition. */
|
|
48
|
-
Currency: {
|
|
49
|
-
input: string;
|
|
50
|
-
output: string;
|
|
51
|
-
};
|
|
52
|
-
/** Cursor scalar. */
|
|
53
|
-
Cursor: {
|
|
54
|
-
input: string;
|
|
55
|
-
output: string;
|
|
56
|
-
};
|
|
57
|
-
/** Date without time, Eg. 2019-01-01 */
|
|
58
|
-
Date: {
|
|
59
|
-
input: DateTimeISOString;
|
|
60
|
-
output: DateTimeISOString;
|
|
61
|
-
};
|
|
62
|
-
/** DateTime represents a “date-time” as specified in section 5.6 of RFC 3339 */
|
|
63
|
-
DateTime: {
|
|
64
|
-
input: DateTimeISOString;
|
|
65
|
-
output: DateTimeISOString;
|
|
66
|
-
};
|
|
67
|
-
/** Duration represents an ISO 8601 duration */
|
|
68
|
-
Duration: {
|
|
69
|
-
input: any;
|
|
70
|
-
output: any;
|
|
71
|
-
};
|
|
72
|
-
/** Valid email address according to https://owasp.org/www-community/OWASP_Validation_Regex_Repository */
|
|
73
|
-
EmailAddress: {
|
|
74
|
-
input: string;
|
|
75
|
-
output: string;
|
|
76
|
-
};
|
|
77
|
-
/** A (possiblely multidimensional) set of coordinates following x, y, z order. */
|
|
78
|
-
GeoJSONCoordinates: {
|
|
79
|
-
input: [number, number] | [number, number][] | [number, number][][];
|
|
80
|
-
output: [number, number] | [number, number][] | [number, number][][];
|
|
81
|
-
};
|
|
82
|
-
/** Raw JSON object structure, not serialized to string */
|
|
83
|
-
JSON: {
|
|
84
|
-
input: any;
|
|
85
|
-
output: any;
|
|
86
|
-
};
|
|
87
|
-
/** The `JSONObject` scalar type represents JSON values as a string */
|
|
88
|
-
JSONObject: {
|
|
89
|
-
input: any;
|
|
90
|
-
output: any;
|
|
91
|
-
};
|
|
92
|
-
/** 24-hour clock time string in the format hh:mm:ss.sss or hh:mm:ss if partial seconds is zero */
|
|
93
|
-
LocalTime: {
|
|
94
|
-
input: any;
|
|
95
|
-
output: any;
|
|
96
|
-
};
|
|
97
|
-
/** Javascript `Long`. Type represents a 64 bit integer. */
|
|
98
|
-
Long: {
|
|
99
|
-
input: any;
|
|
100
|
-
output: any;
|
|
101
|
-
};
|
|
102
|
-
/** Phone number in E.164 format */
|
|
103
|
-
PhoneNumber: {
|
|
104
|
-
input: string;
|
|
105
|
-
output: string;
|
|
106
|
-
};
|
|
107
|
-
/** The `PublicIrisAppManifest` scalar type represents an Iris App Manifest as JSON */
|
|
108
|
-
PublicIrisAppManifest: {
|
|
109
|
-
input: PublicIrisAppManifest;
|
|
110
|
-
output: PublicIrisAppManifest;
|
|
111
|
-
};
|
|
112
|
-
/** Uniform resource locator */
|
|
113
|
-
Url: {
|
|
114
|
-
input: string;
|
|
115
|
-
output: string;
|
|
116
|
-
};
|
|
117
|
-
/** YearMonth scalar */
|
|
118
|
-
YearMonth: {
|
|
119
|
-
input: any;
|
|
120
|
-
output: any;
|
|
121
|
-
};
|
|
122
|
-
};
|
|
123
|
-
export type GetAssetTimezoneQueryVariables = Exact<{
|
|
124
|
-
assetId: Scalars["ID"]["input"];
|
|
125
|
-
}>;
|
|
126
|
-
export type GetAssetTimezoneQuery = {
|
|
127
|
-
__typename?: "Query";
|
|
128
|
-
asset: {
|
|
129
|
-
__typename?: "Asset";
|
|
130
|
-
locations: {
|
|
131
|
-
__typename?: "Locations";
|
|
132
|
-
latest: {
|
|
133
|
-
__typename?: "GeoJSONFeatureForAsset";
|
|
134
|
-
properties: {
|
|
135
|
-
__typename?: "GeoJSONPropertiesForAsset";
|
|
136
|
-
timeZone: string | null;
|
|
137
|
-
} | null;
|
|
138
|
-
} | null;
|
|
139
|
-
} | null;
|
|
140
|
-
} | null;
|
|
141
|
-
};
|
|
142
|
-
export declare const GetAssetTimezoneDocument: DocumentNode<GetAssetTimezoneQuery, GetAssetTimezoneQueryVariables>;
|
package/src/test/index.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { mockAssetTimezone } from "./mocks/mockAssetTimezone";
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { MockedResponse } from "@apollo/client/testing";
|
|
2
|
-
import { GetAssetTimezoneQuery } from "../../generated/graphql-api/graphql";
|
|
3
|
-
type AssetTimezoneMockProps = {
|
|
4
|
-
assetId: string;
|
|
5
|
-
timeZone: string;
|
|
6
|
-
};
|
|
7
|
-
/**
|
|
8
|
-
* Mocks the asset timezone query.
|
|
9
|
-
*
|
|
10
|
-
* @param { AssetTimezoneMockProps} props - The properties for the asset timezone query.
|
|
11
|
-
* @param {string} [props.assetId] - The asset id
|
|
12
|
-
* @param {string} [props.timeZone] - The timezone to mock
|
|
13
|
-
*/
|
|
14
|
-
export declare const mockAssetTimezone: ({ assetId, timeZone, }: AssetTimezoneMockProps) => MockedResponse<GetAssetTimezoneQuery> & {
|
|
15
|
-
data: NonNullable<GetAssetTimezoneQuery>;
|
|
16
|
-
};
|
|
17
|
-
export {};
|