@trackunit/react-date-and-time-hooks 0.0.1

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/README.md ADDED
@@ -0,0 +1,22 @@
1
+ > **⚠️ Beta**
2
+ >
3
+ > This is a beta version and subject to change without notice.
4
+
5
+ # Trackunit date and time hooks
6
+
7
+ This library contains React Hooks used to manipulate dates such as:
8
+ - Subtracting days, weeks or months
9
+ - Adding days, weeks or months
10
+ - Finding the start and end of days, weeks, months
11
+ - Finding differences between two dates
12
+ - See if a date is in the future, past or present day
13
+
14
+ Trackunit Iris Apps are used by external developers to integrate custom functionality into [the Trackunit Manager platform](https://www.trackunit.com/services/manager/).
15
+
16
+ For more info and a full guide on Iris App SDK Development, please visit our [Developer Hub](https://developers.trackunit.com/).
17
+
18
+ ## Trackunit
19
+ This package was developed by Trackunit ApS.
20
+ Trackunit is the leading SaaS-based IoT solution for the construction industry, offering an ecosystem of hardware, fleet management software & telematics.
21
+
22
+ ![The Trackunit logo](https://trackunit.com/wp-content/uploads/2022/03/top-logo.svg)
package/index.cjs.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from "./src/index";
package/index.cjs.js ADDED
@@ -0,0 +1,507 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var polyfill = require('@js-temporal/polyfill');
6
+ var dateAndTimeUtils = require('@trackunit/date-and-time-utils');
7
+ var sharedUtils = require('@trackunit/shared-utils');
8
+ var react = require('react');
9
+ var client = require('@apollo/client');
10
+ var reactComponents = require('@trackunit/react-components');
11
+ var reactCoreContextsApi = require('@trackunit/react-core-contexts-api');
12
+ var reactCoreHooks = require('@trackunit/react-core-hooks');
13
+ var zod = require('zod');
14
+
15
+ /**
16
+ * Try to convert to ISO standard. ex. en becomes en-GB if its in United Kingdom.
17
+ * Still looking at the base id.
18
+ *
19
+ * @param userPreferenceLanguage 2 letter language code from the persisted language selection.
20
+ */
21
+ const convertToLocale = (userPreferenceLanguage) => {
22
+ const browserLanguage = navigator.language;
23
+ if (browserLanguage.indexOf("-") !== -1 && browserLanguage.startsWith(userPreferenceLanguage)) {
24
+ return browserLanguage;
25
+ }
26
+ return userPreferenceLanguage;
27
+ };
28
+
29
+ var _a;
30
+ const LANG_STORAGE_KEY = "i18nextLng";
31
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
32
+ const BrowserLocale = (_a = navigator.language) !== null && _a !== void 0 ? _a : "en";
33
+ /**
34
+ *
35
+ */
36
+ const useLocale = () => {
37
+ const savedLanguage = localStorage.getItem(LANG_STORAGE_KEY);
38
+ const selectedLanguage = savedLanguage || BrowserLocale || "en";
39
+ const userLocale = convertToLocale(selectedLanguage);
40
+ return userLocale || BrowserLocale;
41
+ };
42
+
43
+ const GetAssetTimezoneDocument = {
44
+ kind: "Document",
45
+ definitions: [
46
+ {
47
+ kind: "OperationDefinition",
48
+ operation: "query",
49
+ name: { kind: "Name", value: "GetAssetTimezone" },
50
+ variableDefinitions: [
51
+ {
52
+ kind: "VariableDefinition",
53
+ variable: { kind: "Variable", name: { kind: "Name", value: "assetId" } },
54
+ type: { kind: "NonNullType", type: { kind: "NamedType", name: { kind: "Name", value: "ID" } } },
55
+ },
56
+ ],
57
+ selectionSet: {
58
+ kind: "SelectionSet",
59
+ selections: [
60
+ {
61
+ kind: "Field",
62
+ name: { kind: "Name", value: "asset" },
63
+ arguments: [
64
+ {
65
+ kind: "Argument",
66
+ name: { kind: "Name", value: "id" },
67
+ value: { kind: "Variable", name: { kind: "Name", value: "assetId" } },
68
+ },
69
+ ],
70
+ selectionSet: {
71
+ kind: "SelectionSet",
72
+ selections: [
73
+ {
74
+ kind: "Field",
75
+ name: { kind: "Name", value: "locations" },
76
+ selectionSet: {
77
+ kind: "SelectionSet",
78
+ selections: [
79
+ {
80
+ kind: "Field",
81
+ name: { kind: "Name", value: "latest" },
82
+ selectionSet: {
83
+ kind: "SelectionSet",
84
+ selections: [
85
+ {
86
+ kind: "Field",
87
+ name: { kind: "Name", value: "properties" },
88
+ selectionSet: {
89
+ kind: "SelectionSet",
90
+ selections: [{ kind: "Field", name: { kind: "Name", value: "timeZone" } }],
91
+ },
92
+ },
93
+ ],
94
+ },
95
+ },
96
+ ],
97
+ },
98
+ },
99
+ ],
100
+ },
101
+ },
102
+ ],
103
+ },
104
+ },
105
+ ],
106
+ };
107
+
108
+ /**
109
+ *
110
+ */
111
+ const useTimezone = ({ assetId } = {}) => {
112
+ var _a, _b, _c, _d;
113
+ const { timeZonePreference } = reactCoreHooks.useCurrentUserTimeZonePreference();
114
+ const [customTimezone, setCustomTimezone] = reactComponents.useLocalStorage({
115
+ key: "customTimeZone",
116
+ defaultState: null,
117
+ schema: zod.z.string().nullable(),
118
+ });
119
+ const { data: timeZoneData } = client.useQuery(GetAssetTimezoneDocument, {
120
+ variables: {
121
+ // eslint-disable-next-line local-rules/no-typescript-assertion
122
+ assetId: assetId,
123
+ },
124
+ skip: !assetId,
125
+ fetchPolicy: "cache-first",
126
+ });
127
+ const assetTimeZone = react.useMemo(() => {
128
+ var _a, _b, _c, _d;
129
+ const timezone = (_d = (_c = (_b = (_a = timeZoneData === null || timeZoneData === void 0 ? void 0 : timeZoneData.asset) === null || _a === void 0 ? void 0 : _a.locations) === null || _b === void 0 ? void 0 : _b.latest) === null || _c === void 0 ? void 0 : _c.properties) === null || _d === void 0 ? void 0 : _d.timeZone;
130
+ if (!timezone) {
131
+ return null;
132
+ }
133
+ return dateAndTimeUtils.getTimeZone(timezone);
134
+ }, [(_d = (_c = (_b = (_a = timeZoneData === null || timeZoneData === void 0 ? void 0 : timeZoneData.asset) === null || _a === void 0 ? void 0 : _a.locations) === null || _b === void 0 ? void 0 : _b.latest) === null || _c === void 0 ? void 0 : _c.properties) === null || _d === void 0 ? void 0 : _d.timeZone]);
135
+ const current = react.useMemo(() => {
136
+ const id = polyfill.Temporal.Now.timeZoneId();
137
+ if (timeZonePreference === reactCoreContextsApi.TimeZonePreference.CustomTimeZone && customTimezone) {
138
+ return dateAndTimeUtils.getTimeZone(customTimezone);
139
+ }
140
+ return dateAndTimeUtils.getTimeZone(id);
141
+ }, [customTimezone, timeZonePreference]);
142
+ const preferred = react.useMemo(() => {
143
+ if (timeZonePreference === reactCoreContextsApi.TimeZonePreference.MachineTimeZone && assetTimeZone) {
144
+ return assetTimeZone;
145
+ }
146
+ return current;
147
+ }, [timeZonePreference, current, assetTimeZone]);
148
+ return {
149
+ current,
150
+ assetTimeZone,
151
+ preferred,
152
+ setCustomTimezone,
153
+ };
154
+ };
155
+
156
+ /**
157
+ *
158
+ */
159
+ const useDateAndTime = () => {
160
+ const currentLocale = useLocale();
161
+ const { current, assetTimeZone, preferred } = useTimezone();
162
+ const currentTimeZone = current.id || preferred.id || (assetTimeZone === null || assetTimeZone === void 0 ? void 0 : assetTimeZone.id);
163
+ const currentDate = dateAndTimeUtils.toZonedDateTimeUtil(polyfill.Temporal.Now.instant(), currentTimeZone);
164
+ /**
165
+ * Returns the current date and time.
166
+ *
167
+ * @returns {Date}
168
+ */
169
+ const nowDate = dateAndTimeUtils.toDateUtil(currentDate);
170
+ /**
171
+ * Formats a date using the current locale and time zone.
172
+ *
173
+ * @param {Date} date
174
+ * @param {TemporalFormat} format
175
+ * @returns {string}
176
+ */
177
+ const formatDate = react.useCallback((date, format) => {
178
+ return dateAndTimeUtils.formatDateUtil(date, format, currentTimeZone, currentLocale);
179
+ }, [currentLocale, currentTimeZone]);
180
+ /**
181
+ * Formats a date using the custom locale and custom timezone.
182
+ *
183
+ * @param {Date} date
184
+ * @param {TemporalFormat} format
185
+ * @param {string} timezone
186
+ * @param {string} locale
187
+ * @returns {string}
188
+ */
189
+ const formatDateWithTimezone = react.useCallback((date, format, timezone, locale) => {
190
+ return dateAndTimeUtils.formatDateUtil(date, format, timezone !== null && timezone !== void 0 ? timezone : currentTimeZone, locale !== null && locale !== void 0 ? locale : currentLocale);
191
+ }, [currentLocale, currentTimeZone]);
192
+ /**
193
+ * Formats a date range using the current locale and time zone.
194
+ *
195
+ * @param {Date} start
196
+ * @param {Date} end
197
+ * @param {Intl.DateTimeFormatOptions} format
198
+ * @returns {string}
199
+ */
200
+ const formatRange = react.useCallback((range, format) => dateAndTimeUtils.formatRangeUtil(range, currentLocale, format), [currentLocale]);
201
+ /**
202
+ * Subtracts a given amount of time from a date.
203
+ *
204
+ * @param {TemporalDate} date
205
+ * @param {number} amount
206
+ * @param {TemporalArithmeticType} type
207
+ * @returns {Date}
208
+ */
209
+ const subtract = react.useCallback((date, amount, type) => {
210
+ let returnFn;
211
+ switch (type) {
212
+ case "minutes":
213
+ returnFn = dateAndTimeUtils.subtractMinutesUtil(date, amount, currentTimeZone);
214
+ break;
215
+ case "hours":
216
+ returnFn = dateAndTimeUtils.subtractHoursUtil(date, amount, currentTimeZone);
217
+ break;
218
+ case "days":
219
+ returnFn = dateAndTimeUtils.subtractDaysUtil(date, amount, currentTimeZone);
220
+ break;
221
+ case "weeks":
222
+ returnFn = dateAndTimeUtils.subtractWeeksUtil(date, amount, currentTimeZone);
223
+ break;
224
+ case "months":
225
+ returnFn = dateAndTimeUtils.subtractMonthsUtil(date, amount, currentTimeZone);
226
+ break;
227
+ case "years":
228
+ returnFn = dateAndTimeUtils.subtractYearsUtil(date, amount, currentTimeZone);
229
+ break;
230
+ default:
231
+ return sharedUtils.exhaustiveCheck(type);
232
+ }
233
+ return dateAndTimeUtils.toDateUtil(returnFn);
234
+ }, [currentTimeZone]);
235
+ /**
236
+ * Adds a given amount of time to a date.
237
+ *
238
+ * @param {TemporalDate} date
239
+ * @param {number} amount
240
+ * @param {TemporalArithmeticType} type
241
+ */
242
+ const add = react.useCallback((date, amount, type) => {
243
+ let returnFn;
244
+ switch (type) {
245
+ case "minutes":
246
+ returnFn = dateAndTimeUtils.addMinutesUtil(date, amount, currentTimeZone);
247
+ break;
248
+ case "hours":
249
+ returnFn = dateAndTimeUtils.addHoursUtil(date, amount, currentTimeZone);
250
+ break;
251
+ case "days":
252
+ returnFn = dateAndTimeUtils.addDaysUtil(date, amount, currentTimeZone);
253
+ break;
254
+ case "weeks":
255
+ returnFn = dateAndTimeUtils.addWeeksUtil(date, amount, currentTimeZone);
256
+ break;
257
+ case "months":
258
+ returnFn = dateAndTimeUtils.addMonthsUtil(date, amount, currentTimeZone);
259
+ break;
260
+ case "years":
261
+ returnFn = dateAndTimeUtils.addYearsUtil(date, amount, currentTimeZone);
262
+ break;
263
+ default:
264
+ return sharedUtils.exhaustiveCheck(type);
265
+ }
266
+ return dateAndTimeUtils.toDateUtil(returnFn);
267
+ }, [currentTimeZone]);
268
+ /**
269
+ * Returns the start of a given time period.
270
+ *
271
+ * @param {TemporalDate} date
272
+ * @param {TemporalEdgeOfType} type
273
+ * @returns {Date}
274
+ */
275
+ const startOf = react.useCallback((date, type) => {
276
+ let returnFn;
277
+ switch (type) {
278
+ case "minute":
279
+ returnFn = dateAndTimeUtils.startOfMinuteUtil(date, currentTimeZone);
280
+ break;
281
+ case "hour":
282
+ returnFn = dateAndTimeUtils.startOfHourUtil(date, currentTimeZone);
283
+ break;
284
+ case "day":
285
+ returnFn = dateAndTimeUtils.startOfDayUtil(date, currentTimeZone);
286
+ break;
287
+ case "week":
288
+ returnFn = dateAndTimeUtils.startOfWeekUtil(date, currentTimeZone);
289
+ break;
290
+ case "month":
291
+ returnFn = dateAndTimeUtils.startOfMonthUtil(date, currentTimeZone);
292
+ break;
293
+ default:
294
+ return sharedUtils.exhaustiveCheck(type);
295
+ }
296
+ return dateAndTimeUtils.toDateUtil(returnFn);
297
+ }, [currentTimeZone]);
298
+ /**
299
+ * Returns the end of a given time period.
300
+ *
301
+ * @param {TemporalDate} date
302
+ * @param {TemporalEdgeOfType} type
303
+ * @returns {Date}
304
+ */
305
+ const endOf = react.useCallback((date, type) => {
306
+ let returnFn;
307
+ switch (type) {
308
+ case "minute":
309
+ returnFn = dateAndTimeUtils.endOfMinuteUtil(date, currentTimeZone);
310
+ break;
311
+ case "hour":
312
+ returnFn = dateAndTimeUtils.endOfHourUtil(date, currentTimeZone);
313
+ break;
314
+ case "day":
315
+ returnFn = dateAndTimeUtils.endOfDayUtil(date, currentTimeZone);
316
+ break;
317
+ case "week":
318
+ returnFn = dateAndTimeUtils.endOfWeekUtil(date, currentTimeZone);
319
+ break;
320
+ case "month":
321
+ returnFn = dateAndTimeUtils.endOfMonthUtil(date, currentTimeZone);
322
+ break;
323
+ default:
324
+ return sharedUtils.exhaustiveCheck(type);
325
+ }
326
+ return dateAndTimeUtils.toDateUtil(returnFn);
327
+ }, [currentTimeZone]);
328
+ /**
329
+ * Returns the difference between two dates.
330
+ *
331
+ * @param {TemporalDate} from
332
+ * @param {TemporalDate} to
333
+ * @param {TemporalDifferenceType} type
334
+ * @returns {number}
335
+ */
336
+ const difference = react.useCallback((from, to, type) => {
337
+ switch (type) {
338
+ case "minute":
339
+ return dateAndTimeUtils.differenceInMinutesUtil(from, to);
340
+ case "hour":
341
+ return dateAndTimeUtils.differenceInHoursUtil(from, to);
342
+ case "day":
343
+ return dateAndTimeUtils.differenceInDaysUtil(from, to);
344
+ case "week":
345
+ return dateAndTimeUtils.differenceInWeeksUtil(from, to);
346
+ case "month":
347
+ return dateAndTimeUtils.differenceInMonthsUtil(from, to);
348
+ default:
349
+ return sharedUtils.exhaustiveCheck(type);
350
+ }
351
+ }, []);
352
+ /**
353
+ * Returns whether a date is in the past, present or future.
354
+ *
355
+ * @param {TemporalDate} date
356
+ * @param {TemporalIsType} type
357
+ * @returns {boolean}
358
+ */
359
+ const dateIs = react.useCallback((date, type, betweenDates) => {
360
+ switch (type) {
361
+ case "past":
362
+ return dateAndTimeUtils.isPastUtil(date);
363
+ case "future":
364
+ return dateAndTimeUtils.isFutureUtil(date);
365
+ case "present":
366
+ return dateAndTimeUtils.isTodayUtil(date);
367
+ case "between":
368
+ return dateAndTimeUtils.isBetweenUtil(date, betweenDates === null || betweenDates === void 0 ? void 0 : betweenDates.start, betweenDates === null || betweenDates === void 0 ? void 0 : betweenDates.end);
369
+ default:
370
+ return sharedUtils.exhaustiveCheck(type);
371
+ }
372
+ }, []);
373
+ /**
374
+ * Returns whether a date is same day/week/month or year.
375
+ *
376
+ * @param {TemporalDate} date
377
+ * @param {TemporalSameType} type
378
+ * @returns {boolean}
379
+ */
380
+ const same = react.useCallback((date, type) => {
381
+ switch (type) {
382
+ case "day":
383
+ return dateAndTimeUtils.isSameDayUtil(date);
384
+ case "week":
385
+ return dateAndTimeUtils.isSameWeekUtil(date);
386
+ case "month":
387
+ return dateAndTimeUtils.isSameMonthUtil(date);
388
+ case "year":
389
+ return dateAndTimeUtils.isSameYearUtil(date);
390
+ default:
391
+ return sharedUtils.exhaustiveCheck(type);
392
+ }
393
+ }, []);
394
+ /**
395
+ * Returns the time since a given date.
396
+ *
397
+ * @param {TemporalDate} from
398
+ * @param {TemporalDate} to
399
+ * @param {TemporalSinceType} type
400
+ * @returns {string}
401
+ */
402
+ const since = react.useCallback((from, to, type) => {
403
+ switch (type) {
404
+ case "auto":
405
+ return dateAndTimeUtils.timeSinceAuto(from, to, currentTimeZone, currentLocale);
406
+ case "seconds":
407
+ return dateAndTimeUtils.timeSinceInSeconds(from, to, currentTimeZone, currentLocale);
408
+ case "minutes":
409
+ return dateAndTimeUtils.timeSinceInMinutes(from, to, currentTimeZone, currentLocale);
410
+ case "hours":
411
+ return dateAndTimeUtils.timeSinceInHours(from, to, currentTimeZone, currentLocale);
412
+ case "days":
413
+ return dateAndTimeUtils.timeSinceInDays(from, to, currentTimeZone, currentLocale);
414
+ case "months":
415
+ return dateAndTimeUtils.timeSinceInMonths(from, to, currentTimeZone, currentLocale);
416
+ case "years":
417
+ return dateAndTimeUtils.timeSinceInYears(from, to, currentTimeZone, currentLocale);
418
+ default:
419
+ return sharedUtils.exhaustiveCheck(type);
420
+ }
421
+ }, [currentLocale, currentTimeZone]);
422
+ /**
423
+ * Returns a duration from a number
424
+ *
425
+ * @param {Duration} from
426
+ * @param {TemporalDurationType} type
427
+ * @param {TemporalFormat["dayFormat"]} format
428
+ * @example type: "hours", { hours: 230, minutes: 27 } = 230 hours, 27 minutes
429
+ * @example type: "hours", 230.45 = 230 hours, 27 minutes
430
+ * @returns {string}
431
+ */
432
+ const duration = react.useCallback((from, type, format, roundAt) => {
433
+ const durationValue = typeof from === "number"
434
+ ? dateAndTimeUtils.toDuration(from, type, roundAt)
435
+ : polyfill.Temporal.Duration.from(from).round({ smallestUnit: roundAt !== null && roundAt !== void 0 ? roundAt : "minute" });
436
+ return dateAndTimeUtils.getDurationFormat(durationValue, currentLocale, format);
437
+ }, [currentLocale]);
438
+ /**
439
+ * Returns the name of a day.
440
+ *
441
+ * @param {TemporalDate} date
442
+ * @param {TemporalFormatStyle} format
443
+ * @returns {string}
444
+ */
445
+ const dayName = react.useCallback((date, format) => {
446
+ return dateAndTimeUtils.dayNameUtil(date, format, currentLocale);
447
+ }, [currentLocale]);
448
+ const days = react.useCallback((format) => {
449
+ return dateAndTimeUtils.daysUtil(format, currentLocale);
450
+ }, [currentLocale]);
451
+ /**
452
+ * Returns the name of a month.
453
+ *
454
+ * @param {TemporalDate} date
455
+ * @param {TemporalFormatStyle} format
456
+ * @returns {string}
457
+ */
458
+ const monthName = react.useCallback((date, format) => {
459
+ return dateAndTimeUtils.monthNameUtil(date, format, currentLocale);
460
+ }, [currentLocale]);
461
+ const months = react.useCallback((format) => {
462
+ return dateAndTimeUtils.monthsUtil(format, currentLocale);
463
+ }, [currentLocale]);
464
+ return react.useMemo(() => ({
465
+ nowDate,
466
+ formatDate,
467
+ formatDateWithTimezone,
468
+ formatRange,
469
+ startOf,
470
+ endOf,
471
+ add,
472
+ subtract,
473
+ difference,
474
+ since,
475
+ same,
476
+ duration,
477
+ dateIs,
478
+ isEqual: dateAndTimeUtils.isEqualUtil,
479
+ monthName,
480
+ months,
481
+ dayName,
482
+ days,
483
+ }), [
484
+ add,
485
+ dateIs,
486
+ dayName,
487
+ days,
488
+ difference,
489
+ duration,
490
+ endOf,
491
+ formatDate,
492
+ formatDateWithTimezone,
493
+ formatRange,
494
+ monthName,
495
+ months,
496
+ nowDate,
497
+ same,
498
+ since,
499
+ startOf,
500
+ subtract,
501
+ ]);
502
+ };
503
+
504
+ exports.convertToLocale = convertToLocale;
505
+ exports.useDateAndTime = useDateAndTime;
506
+ exports.useLocale = useLocale;
507
+ exports.useTimezone = useTimezone;
package/index.esm.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from "./src/index";