@trackunit/react-date-and-time-hooks 2.1.4 → 2.1.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/index.cjs.js CHANGED
@@ -1,14 +1,13 @@
1
1
  'use strict';
2
2
 
3
- var react = require('react');
4
3
  var dateAndTimeUtils = require('@trackunit/date-and-time-utils');
5
4
  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');
7
8
  var reactCoreHooks = require('@trackunit/react-core-hooks');
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);
9
+ var reactGraphqlHooks = require('@trackunit/react-graphql-hooks');
10
+ var zod = require('zod');
12
11
 
13
12
  /**
14
13
  * Try to convert to ISO standard. ex. en becomes en-GB if its in United Kingdom.
@@ -40,28 +39,78 @@ const useLocale = () => {
40
39
  return userLocale || BrowserLocale;
41
40
  };
42
41
 
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
- return typeof parsed === "string" ? parsed : null;
51
- }
52
- catch {
53
- return null;
54
- }
42
+ const GetAssetTimezoneDocument = {
43
+ kind: "Document",
44
+ definitions: [
45
+ {
46
+ kind: "OperationDefinition",
47
+ operation: "query",
48
+ name: { kind: "Name", value: "GetAssetTimezone" },
49
+ variableDefinitions: [
50
+ {
51
+ kind: "VariableDefinition",
52
+ variable: { kind: "Variable", name: { kind: "Name", value: "assetId" } },
53
+ type: { kind: "NonNullType", type: { kind: "NamedType", name: { kind: "Name", value: "ID" } } },
54
+ },
55
+ ],
56
+ selectionSet: {
57
+ kind: "SelectionSet",
58
+ selections: [
59
+ {
60
+ kind: "Field",
61
+ name: { kind: "Name", value: "asset" },
62
+ arguments: [
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
+ ],
55
105
  };
106
+
107
+ const customTimeZoneSchema = zod.z.string().nullable();
56
108
  /**
57
109
  * Resolves the active timezone based on user preference, custom override, and optional asset location.
58
110
  *
59
111
  * Returns `current` (browser or custom override), `preferred` (resolved per user settings
60
112
  * and optional asset), and `assetTimeZone` (fetched from the asset's GPS location).
61
113
  *
62
- * The asset timezone is resolved by the nearest `AssetTimezoneProvider` in the component tree.
63
- * Use `AssetTimezoneProvider` on asset-detail pages to enable machine-timezone resolution.
64
- *
65
114
  * **When to use:**
66
115
  * - Use `useTimezone` whenever you need to display or calculate dates in the correct
67
116
  * timezone — especially on asset-detail pages where the machine's timezone may differ
@@ -70,23 +119,28 @@ const readTimezoneFromStorage = () => {
70
119
  * - Do **not** rely on `Intl.DateTimeFormat().resolvedOptions().timeZone` directly —
71
120
  * this hook respects the user's preference setting (browser, machine, or custom).
72
121
  */
73
- const useTimezone = () => {
74
- const { assetTimeZone } = useAssetTimezoneContext();
75
- const { timeZonePreference, customTimezone: contextCustomTimezone } = reactCoreHooks.useCurrentUserTimeZonePreference();
76
- const [localStorageCustomTimezone, setLocalStorageCustomTimezone] = react.useState(readTimezoneFromStorage);
77
- const setCustomTimezone = react.useCallback((timezone) => {
78
- setLocalStorageCustomTimezone(timezone);
79
- if (timezone === null) {
80
- localStorage.removeItem(CUSTOM_TIMEZONE_KEY);
81
- }
82
- else {
83
- localStorage.setItem(CUSTOM_TIMEZONE_KEY, JSON.stringify(timezone));
122
+ const useTimezone = ({ assetId } = {}) => {
123
+ const { timeZonePreference } = reactCoreHooks.useCurrentUserTimeZonePreference();
124
+ const localStorageProps = react.useMemo(() => ({
125
+ key: "customTimeZone",
126
+ defaultState: null,
127
+ schema: customTimeZoneSchema,
128
+ }), []);
129
+ const [customTimezone, setCustomTimezone] = reactComponents.useLocalStorage(localStorageProps);
130
+ const { data: timeZoneData } = reactGraphqlHooks.useQuery(GetAssetTimezoneDocument, {
131
+ variables: {
132
+ assetId: assetId ?? "",
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;
84
141
  }
85
- }, []);
86
- // undefined → host did not send this field (old host without Penpal support); fall back to localStorage.
87
- // null → host explicitly has no custom timezone; do NOT fall back to potentially stale iframe localStorage.
88
- // string → host-provided value; use it directly.
89
- const customTimezone = contextCustomTimezone !== undefined ? contextCustomTimezone : localStorageCustomTimezone;
142
+ return dateAndTimeUtils.getTimeZone(timezone);
143
+ }, [timeZoneData?.asset?.locations?.latest?.properties?.timeZone]);
90
144
  const current = react.useMemo(() => {
91
145
  const id = dateAndTimeUtils.Temporal.Now.timeZoneId();
92
146
  if (timeZonePreference === irisAppRuntimeCoreApi.TimeZonePreference.CustomTimeZone && customTimezone) {
@@ -100,7 +154,7 @@ const useTimezone = () => {
100
154
  }
101
155
  return current;
102
156
  }, [timeZonePreference, current, assetTimeZone]);
103
- return react.useMemo(() => ({ current, assetTimeZone, preferred, setCustomTimezone, customTimezone }), [current, assetTimeZone, preferred, setCustomTimezone, customTimezone]);
157
+ return react.useMemo(() => ({ current, assetTimeZone, preferred, setCustomTimezone }), [current, assetTimeZone, preferred, setCustomTimezone]);
104
158
  };
105
159
 
106
160
  /**
@@ -499,9 +553,7 @@ const useDateAndTime = () => {
499
553
  ]);
500
554
  };
501
555
 
502
- exports.AssetTimezoneContext = AssetTimezoneContext;
503
556
  exports.convertToLocale = convertToLocale;
504
- exports.useAssetTimezoneContext = useAssetTimezoneContext;
505
557
  exports.useDateAndTime = useDateAndTime;
506
558
  exports.useLocale = useLocale;
507
559
  exports.useTimezone = useTimezone;
package/index.esm.js CHANGED
@@ -1,12 +1,11 @@
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';
1
+ import { getTimeZone, Temporal, 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';
3
2
  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';
5
6
  import { useCurrentUserTimeZonePreference } from '@trackunit/react-core-hooks';
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);
7
+ import { useQuery } from '@trackunit/react-graphql-hooks';
8
+ import { z } from 'zod';
10
9
 
11
10
  /**
12
11
  * Try to convert to ISO standard. ex. en becomes en-GB if its in United Kingdom.
@@ -38,28 +37,78 @@ const useLocale = () => {
38
37
  return userLocale || BrowserLocale;
39
38
  };
40
39
 
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
- return typeof parsed === "string" ? parsed : null;
49
- }
50
- catch {
51
- return null;
52
- }
40
+ const GetAssetTimezoneDocument = {
41
+ kind: "Document",
42
+ definitions: [
43
+ {
44
+ kind: "OperationDefinition",
45
+ operation: "query",
46
+ name: { kind: "Name", value: "GetAssetTimezone" },
47
+ variableDefinitions: [
48
+ {
49
+ kind: "VariableDefinition",
50
+ variable: { kind: "Variable", name: { kind: "Name", value: "assetId" } },
51
+ type: { kind: "NonNullType", type: { kind: "NamedType", name: { kind: "Name", value: "ID" } } },
52
+ },
53
+ ],
54
+ selectionSet: {
55
+ kind: "SelectionSet",
56
+ selections: [
57
+ {
58
+ kind: "Field",
59
+ name: { kind: "Name", value: "asset" },
60
+ arguments: [
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
+ ],
53
103
  };
104
+
105
+ const customTimeZoneSchema = z.string().nullable();
54
106
  /**
55
107
  * Resolves the active timezone based on user preference, custom override, and optional asset location.
56
108
  *
57
109
  * Returns `current` (browser or custom override), `preferred` (resolved per user settings
58
110
  * and optional asset), and `assetTimeZone` (fetched from the asset's GPS location).
59
111
  *
60
- * The asset timezone is resolved by the nearest `AssetTimezoneProvider` in the component tree.
61
- * Use `AssetTimezoneProvider` on asset-detail pages to enable machine-timezone resolution.
62
- *
63
112
  * **When to use:**
64
113
  * - Use `useTimezone` whenever you need to display or calculate dates in the correct
65
114
  * timezone — especially on asset-detail pages where the machine's timezone may differ
@@ -68,23 +117,28 @@ const readTimezoneFromStorage = () => {
68
117
  * - Do **not** rely on `Intl.DateTimeFormat().resolvedOptions().timeZone` directly —
69
118
  * this hook respects the user's preference setting (browser, machine, or custom).
70
119
  */
71
- const useTimezone = () => {
72
- const { assetTimeZone } = useAssetTimezoneContext();
73
- const { timeZonePreference, customTimezone: contextCustomTimezone } = useCurrentUserTimeZonePreference();
74
- const [localStorageCustomTimezone, setLocalStorageCustomTimezone] = useState(readTimezoneFromStorage);
75
- const setCustomTimezone = useCallback((timezone) => {
76
- setLocalStorageCustomTimezone(timezone);
77
- if (timezone === null) {
78
- localStorage.removeItem(CUSTOM_TIMEZONE_KEY);
79
- }
80
- else {
81
- localStorage.setItem(CUSTOM_TIMEZONE_KEY, JSON.stringify(timezone));
120
+ const useTimezone = ({ assetId } = {}) => {
121
+ const { timeZonePreference } = useCurrentUserTimeZonePreference();
122
+ const localStorageProps = useMemo(() => ({
123
+ key: "customTimeZone",
124
+ defaultState: null,
125
+ schema: customTimeZoneSchema,
126
+ }), []);
127
+ const [customTimezone, setCustomTimezone] = useLocalStorage(localStorageProps);
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;
82
139
  }
83
- }, []);
84
- // undefined → host did not send this field (old host without Penpal support); fall back to localStorage.
85
- // null → host explicitly has no custom timezone; do NOT fall back to potentially stale iframe localStorage.
86
- // string → host-provided value; use it directly.
87
- const customTimezone = contextCustomTimezone !== undefined ? contextCustomTimezone : localStorageCustomTimezone;
140
+ return getTimeZone(timezone);
141
+ }, [timeZoneData?.asset?.locations?.latest?.properties?.timeZone]);
88
142
  const current = useMemo(() => {
89
143
  const id = Temporal.Now.timeZoneId();
90
144
  if (timeZonePreference === TimeZonePreference.CustomTimeZone && customTimezone) {
@@ -98,7 +152,7 @@ const useTimezone = () => {
98
152
  }
99
153
  return current;
100
154
  }, [timeZonePreference, current, assetTimeZone]);
101
- return useMemo(() => ({ current, assetTimeZone, preferred, setCustomTimezone, customTimezone }), [current, assetTimeZone, preferred, setCustomTimezone, customTimezone]);
155
+ return useMemo(() => ({ current, assetTimeZone, preferred, setCustomTimezone }), [current, assetTimeZone, preferred, setCustomTimezone]);
102
156
  };
103
157
 
104
158
  /**
@@ -497,4 +551,4 @@ const useDateAndTime = () => {
497
551
  ]);
498
552
  };
499
553
 
500
- export { AssetTimezoneContext, convertToLocale, useAssetTimezoneContext, useDateAndTime, useLocale, useTimezone };
554
+ export { convertToLocale, useDateAndTime, useLocale, useTimezone };
package/package.json CHANGED
@@ -1,21 +1,28 @@
1
1
  {
2
2
  "name": "@trackunit/react-date-and-time-hooks",
3
- "version": "2.1.4",
3
+ "version": "2.1.5",
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
- "@trackunit/date-and-time-utils": "1.13.14",
11
- "@trackunit/iris-app-runtime-core-api": "1.16.13",
12
- "@trackunit/shared-utils": "1.15.13",
13
- "@trackunit/react-core-hooks": "1.17.17"
14
- },
15
- "devDependencies": {
16
- "@trackunit/react-core-contexts-test": "1.17.13"
10
+ "@graphql-codegen/cli": "^5.0.3",
11
+ "@graphql-typed-document-node/core": "^3.2.0",
12
+ "zod": "^3.25.76",
13
+ "@trackunit/iris-app-api": "2.0.6",
14
+ "@trackunit/react-core-contexts-test": "1.17.14",
15
+ "@trackunit/date-and-time-utils": "1.13.15",
16
+ "@trackunit/shared-utils": "1.15.14",
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"
17
21
  },
18
22
  "peerDependencies": {
23
+ "@apollo/client": "^3.13.8",
24
+ "@tanstack/react-router": "^1.114.29",
25
+ "graphql": "^16.10.0",
19
26
  "react": "^19.0.0"
20
27
  },
21
28
  "module": "./index.esm.js",
@@ -0,0 +1,19 @@
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>;
@@ -0,0 +1,37 @@
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 {};
@@ -0,0 +1,142 @@
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>;
@@ -0,0 +1,2 @@
1
+ export * from "./fragment-masking";
2
+ export * from "./gql";
package/src/index.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- export * from "./AssetTimezoneContext";
2
1
  export * from "./localeUtils";
3
2
  export * from "./useDateAndTime";
4
3
  export * from "./useLocale";
@@ -0,0 +1 @@
1
+ export { mockAssetTimezone } from "./mocks/mockAssetTimezone";
@@ -0,0 +1,17 @@
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 {};
@@ -1,11 +1,30 @@
1
- import { type TimeZone } from "./AssetTimezoneContext";
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
+ }
2
19
  interface UseTimezoneReturn {
3
20
  current: TimeZone;
4
21
  assetTimeZone: TimeZone | null;
5
22
  preferred: TimeZone;
6
23
  setCustomTimezone: (timezone: string | null) => void;
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;
24
+ }
25
+ interface TimezoneProps {
26
+ /** supply assetId to fetch the timezone for the given machine */
27
+ assetId?: string;
9
28
  }
10
29
  /**
11
30
  * Resolves the active timezone based on user preference, custom override, and optional asset location.
@@ -13,9 +32,6 @@ interface UseTimezoneReturn {
13
32
  * Returns `current` (browser or custom override), `preferred` (resolved per user settings
14
33
  * and optional asset), and `assetTimeZone` (fetched from the asset's GPS location).
15
34
  *
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
- *
19
35
  * **When to use:**
20
36
  * - Use `useTimezone` whenever you need to display or calculate dates in the correct
21
37
  * timezone — especially on asset-detail pages where the machine's timezone may differ
@@ -24,5 +40,5 @@ interface UseTimezoneReturn {
24
40
  * - Do **not** rely on `Intl.DateTimeFormat().resolvedOptions().timeZone` directly —
25
41
  * this hook respects the user's preference setting (browser, machine, or custom).
26
42
  */
27
- export declare const useTimezone: () => UseTimezoneReturn;
43
+ export declare const useTimezone: ({ assetId }?: TimezoneProps) => UseTimezoneReturn;
28
44
  export {};
@@ -1,24 +0,0 @@
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;