@seamapi/react 2.14.0 → 2.15.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.
Files changed (41) hide show
  1. package/README.md +2 -2
  2. package/dist/elements.js +22404 -15789
  3. package/dist/elements.js.map +1 -1
  4. package/dist/index.css +49 -1
  5. package/dist/index.css.map +1 -1
  6. package/dist/index.min.css +1 -1
  7. package/dist/index.min.css.map +1 -1
  8. package/lib/dates.d.ts +1 -0
  9. package/lib/dates.js +4 -0
  10. package/lib/dates.js.map +1 -1
  11. package/lib/icons/NoiseLevels.d.ts +2 -0
  12. package/lib/icons/NoiseLevels.js +5 -0
  13. package/lib/icons/NoiseLevels.js.map +1 -0
  14. package/lib/seam/components/DeviceDetails/DeviceDetails.js +5 -1
  15. package/lib/seam/components/DeviceDetails/DeviceDetails.js.map +1 -1
  16. package/lib/seam/components/DeviceDetails/NoiseSensorDeviceDetails.d.ts +8 -0
  17. package/lib/seam/components/DeviceDetails/NoiseSensorDeviceDetails.js +15 -0
  18. package/lib/seam/components/DeviceDetails/NoiseSensorDeviceDetails.js.map +1 -0
  19. package/lib/seam/noise-sensors/use-noise-thresholds.d.ts +5 -0
  20. package/lib/seam/noise-sensors/use-noise-thresholds.js +26 -0
  21. package/lib/seam/noise-sensors/use-noise-thresholds.js.map +1 -0
  22. package/lib/ui/layout/DetailRow.d.ts +1 -1
  23. package/lib/ui/layout/DetailSection.d.ts +1 -1
  24. package/lib/ui/noise-sensor/NoiseThresholdsList.d.ts +7 -0
  25. package/lib/ui/noise-sensor/NoiseThresholdsList.js +45 -0
  26. package/lib/ui/noise-sensor/NoiseThresholdsList.js.map +1 -0
  27. package/lib/version.d.ts +1 -1
  28. package/lib/version.js +1 -1
  29. package/package.json +3 -2
  30. package/src/lib/dates.ts +5 -0
  31. package/src/lib/icons/NoiseLevels.tsx +31 -0
  32. package/src/lib/seam/components/DeviceDetails/DeviceDetails.tsx +6 -1
  33. package/src/lib/seam/components/DeviceDetails/NoiseSensorDeviceDetails.tsx +58 -0
  34. package/src/lib/seam/noise-sensors/use-noise-thresholds.ts +46 -0
  35. package/src/lib/ui/layout/DetailRow.tsx +1 -1
  36. package/src/lib/ui/layout/DetailSection.tsx +1 -1
  37. package/src/lib/ui/noise-sensor/NoiseThresholdsList.tsx +141 -0
  38. package/src/lib/version.ts +1 -1
  39. package/src/styles/_device-details.scss +1 -0
  40. package/src/styles/_layout.scss +55 -0
  41. package/src/styles/_thermostat.scss +1 -1
@@ -0,0 +1,5 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ export function NoiseLevelsIcon(props) {
3
+ return (_jsxs("svg", { xmlns: 'http://www.w3.org/2000/svg', width: 18, height: 19, fill: 'none', ...props, children: [_jsx("path", { fill: '#9DA1A9', fillRule: 'evenodd', d: 'M8.744 5.47q.046-.09.097-.18c.547-.966 1.534-1.77 3.412-1.77 1.016 0 1.76.259 2.302.638.546.381.934.916 1.186 1.537.516 1.273.415 2.81-.006 3.762-.362.816-.915 1.949-1.477 3.1-.464.952-.935 1.916-1.308 2.724-.603 1.303-1.939 1.383-2.55.842-.453-.401-.624-.87-.659-1.273-.018-.206 0-.389.034-.528.03-.127.062-.18.062-.18v.002l-.002.001a.767.767 0 0 0-.88-1.203 9.5 9.5 0 0 1-.745 1.489q-.021.264.002.55a3.43 3.43 0 0 0 1.171 2.291c1.467 1.298 3.974.783 4.96-1.346.338-.732.8-1.68 1.264-2.634.583-1.196 1.171-2.403 1.53-3.213.587-1.324.701-3.294.026-4.96-.343-.848-.901-1.64-1.73-2.22-.831-.58-1.89-.914-3.18-.914-2.106 0-3.509.827-4.378 1.983q.501.708.869 1.502M9.93 6.752c.298-.952 1.163-1.623 2.3-1.592.893.024 1.514.445 1.88.967.333.474.469 1.054.402 1.484a.767.767 0 0 1-1.517-.227v-.003a.5.5 0 0 0-.02-.11.8.8 0 0 0-.12-.263c-.106-.149-.289-.304-.666-.314-.45-.012-.701.219-.795.516-.1.32-.043.834.444 1.337.513.53.69 1.182.638 1.75-.046.5-.304 1.138-.898 1.382a.767.767 0 0 1-.665-1.38.4.4 0 0 0 .034-.14.69.69 0 0 0-.211-.544c-.822-.849-1.098-1.933-.806-2.863m.969 3.572.002-.003z', clipRule: 'evenodd' }), _jsx("path", { fill: '#27AE60', d: 'm1.191 8.702-.816.974.844 1.007a1.312 1.312 0 0 0-.028-1.98M2.173 11.82l1.041 1.242a4.4 4.4 0 0 0 1.577-3.383c0-1.36-.614-2.575-1.58-3.385L2.17 7.536A2.79 2.79 0 0 1 3.17 9.679c0 .86-.387 1.628-.997 2.14' }), _jsx("path", { fill: '#27AE60', d: 'm4.154 14.183 1.042 1.242a7.48 7.48 0 0 0 2.679-5.746 7.48 7.48 0 0 0-2.683-5.748L4.151 5.173a5.87 5.87 0 0 1 2.103 4.506 5.87 5.87 0 0 1-2.1 4.503' })] }));
4
+ }
5
+ //# sourceMappingURL=NoiseLevels.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NoiseLevels.js","sourceRoot":"","sources":["../../src/lib/icons/NoiseLevels.tsx"],"names":[],"mappings":";AAKA,MAAM,UAAU,eAAe,CAAC,KAA8B;IAC5D,OAAO,CACL,eACE,KAAK,EAAC,4BAA4B,EAClC,KAAK,EAAE,EAAE,EACT,MAAM,EAAE,EAAE,EACV,IAAI,EAAC,MAAM,KACP,KAAK,aAET,eACE,IAAI,EAAC,SAAS,EACd,QAAQ,EAAC,SAAS,EAClB,CAAC,EAAC,gkCAAgkC,EAClkC,QAAQ,EAAC,SAAS,GAClB,EACF,eACE,IAAI,EAAC,SAAS,EACd,CAAC,EAAC,6MAA6M,GAC/M,EACF,eACE,IAAI,EAAC,SAAS,EACd,CAAC,EAAC,qJAAqJ,GACvJ,IACE,CACP,CAAA;AACH,CAAC"}
@@ -1,7 +1,8 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { isLockDevice, isThermostatDevice } from 'seamapi';
2
+ import { isLockDevice, isNoiseSensorDevice, isThermostatDevice } from 'seamapi';
3
3
  import { withRequiredCommonProps, } from '../../../../lib/seam/components/common-props.js';
4
4
  import { LockDeviceDetails } from '../../../../lib/seam/components/DeviceDetails/LockDeviceDetails.js';
5
+ import { NoiseSensorDeviceDetails } from '../../../../lib/seam/components/DeviceDetails/NoiseSensorDeviceDetails.js';
5
6
  import { ThermostatDeviceDetails } from '../../../../lib/seam/components/DeviceDetails/ThermostatDeviceDetails.js';
6
7
  import { useDevice } from '../../../../lib/seam/devices/use-device.js';
7
8
  import { useComponentTelemetry } from '../../../../lib/telemetry/index.js';
@@ -33,6 +34,9 @@ export function DeviceDetails({ deviceId, errorFilter = () => true, warningFilte
33
34
  if (isThermostatDevice(device)) {
34
35
  return _jsx(ThermostatDeviceDetails, { device: device, ...props });
35
36
  }
37
+ if (isNoiseSensorDevice(device)) {
38
+ return _jsx(NoiseSensorDeviceDetails, { device: device, ...props });
39
+ }
36
40
  return null;
37
41
  }
38
42
  //# sourceMappingURL=DeviceDetails.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"DeviceDetails.js","sourceRoot":"","sources":["../../../../src/lib/seam/components/DeviceDetails/DeviceDetails.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAE1D,OAAO,EAEL,uBAAuB,GACxB,MAAM,qCAAqC,CAAA;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,wDAAwD,CAAA;AAC1F,OAAO,EAAE,uBAAuB,EAAE,MAAM,8DAA8D,CAAA;AACtG,OAAO,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAA;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAA;AAM9D,MAAM,CAAC,MAAM,mBAAmB,GAAG,uBAAuB,CAAC,aAAa,CAAC,CAAA;AAQzE,MAAM,UAAU,aAAa,CAAC,EAC5B,QAAQ,EACR,WAAW,GAAG,GAAG,EAAE,CAAC,IAAI,EACxB,aAAa,GAAG,GAAG,EAAE,CAAC,IAAI,EAC1B,iBAAiB,GAAG,KAAK,EACzB,uBAAuB,GAAG,KAAK,EAC/B,kBAAkB,GAAG,KAAK,EAC1B,kCAAkC,GAAG,KAAK,EAC1C,uBAAuB,GAAG,KAAK,EAC/B,qBAAqB,GAAG,KAAK,EAC7B,8BAA8B,GAAG,KAAK,EACtC,MAAM,EACN,SAAS,GACU;IACnB,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAEtC,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;QAC3B,SAAS,EAAE,QAAQ;KACpB,CAAC,CAAA;IAEF,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;QACnB,OAAO,IAAI,CAAA;IACb,CAAC;IAED,MAAM,KAAK,GAAqC;QAC9C,WAAW;QACX,aAAa;QACb,iBAAiB;QACjB,uBAAuB;QACvB,kBAAkB;QAClB,kCAAkC;QAClC,uBAAuB;QACvB,qBAAqB;QACrB,8BAA8B;QAC9B,MAAM;QACN,SAAS;KACV,CAAA;IAED,IAAI,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC;QACzB,OAAO,KAAC,iBAAiB,IAAC,MAAM,EAAE,MAAM,KAAM,KAAK,GAAI,CAAA;IACzD,CAAC;IAED,IAAI,kBAAkB,CAAC,MAAM,CAAC,EAAE,CAAC;QAC/B,OAAO,KAAC,uBAAuB,IAAC,MAAM,EAAE,MAAM,KAAM,KAAK,GAAI,CAAA;IAC/D,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC"}
1
+ {"version":3,"file":"DeviceDetails.js","sourceRoot":"","sources":["../../../../src/lib/seam/components/DeviceDetails/DeviceDetails.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAE/E,OAAO,EAEL,uBAAuB,GACxB,MAAM,qCAAqC,CAAA;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,wDAAwD,CAAA;AAC1F,OAAO,EAAE,wBAAwB,EAAE,MAAM,+DAA+D,CAAA;AACxG,OAAO,EAAE,uBAAuB,EAAE,MAAM,8DAA8D,CAAA;AACtG,OAAO,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAA;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAA;AAM9D,MAAM,CAAC,MAAM,mBAAmB,GAAG,uBAAuB,CAAC,aAAa,CAAC,CAAA;AAQzE,MAAM,UAAU,aAAa,CAAC,EAC5B,QAAQ,EACR,WAAW,GAAG,GAAG,EAAE,CAAC,IAAI,EACxB,aAAa,GAAG,GAAG,EAAE,CAAC,IAAI,EAC1B,iBAAiB,GAAG,KAAK,EACzB,uBAAuB,GAAG,KAAK,EAC/B,kBAAkB,GAAG,KAAK,EAC1B,kCAAkC,GAAG,KAAK,EAC1C,uBAAuB,GAAG,KAAK,EAC/B,qBAAqB,GAAG,KAAK,EAC7B,8BAA8B,GAAG,KAAK,EACtC,MAAM,EACN,SAAS,GACU;IACnB,qBAAqB,CAAC,eAAe,CAAC,CAAA;IAEtC,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;QAC3B,SAAS,EAAE,QAAQ;KACpB,CAAC,CAAA;IAEF,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;QACnB,OAAO,IAAI,CAAA;IACb,CAAC;IAED,MAAM,KAAK,GAAqC;QAC9C,WAAW;QACX,aAAa;QACb,iBAAiB;QACjB,uBAAuB;QACvB,kBAAkB;QAClB,kCAAkC;QAClC,uBAAuB;QACvB,qBAAqB;QACrB,8BAA8B;QAC9B,MAAM;QACN,SAAS;KACV,CAAA;IAED,IAAI,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC;QACzB,OAAO,KAAC,iBAAiB,IAAC,MAAM,EAAE,MAAM,KAAM,KAAK,GAAI,CAAA;IACzD,CAAC;IAED,IAAI,kBAAkB,CAAC,MAAM,CAAC,EAAE,CAAC;QAC/B,OAAO,KAAC,uBAAuB,IAAC,MAAM,EAAE,MAAM,KAAM,KAAK,GAAI,CAAA;IAC/D,CAAC;IAED,IAAI,mBAAmB,CAAC,MAAM,CAAC,EAAE,CAAC;QAChC,OAAO,KAAC,wBAAwB,IAAC,MAAM,EAAE,MAAM,KAAM,KAAK,GAAI,CAAA;IAChE,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC"}
@@ -0,0 +1,8 @@
1
+ /// <reference types="react" resolution-mode="require"/>
2
+ import type { NoiseSensorDevice } from 'seamapi';
3
+ import type { NestedSpecificDeviceDetailsProps } from '../../../../lib/seam/components/DeviceDetails/DeviceDetails.js';
4
+ interface NoiseSensorDeviceDetailsProps extends NestedSpecificDeviceDetailsProps {
5
+ device: NoiseSensorDevice;
6
+ }
7
+ export declare function NoiseSensorDeviceDetails({ device, disableConnectedAccountInformation, disableResourceIds, }: NoiseSensorDeviceDetailsProps): JSX.Element | null;
8
+ export {};
@@ -0,0 +1,15 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { DeviceInfo } from '../../../../lib/seam/components/DeviceDetails/DeviceInfo.js';
3
+ import { DeviceModel } from '../../../../lib/seam/components/DeviceDetails/DeviceModel.js';
4
+ import { DeviceImage } from '../../../../lib/ui/device/DeviceImage.js';
5
+ import { OnlineStatus } from '../../../../lib/ui/device/OnlineStatus.js';
6
+ import { NoiseThresholdsList } from '../../../../lib/ui/noise-sensor/NoiseThresholdsList.js';
7
+ export function NoiseSensorDeviceDetails({ device, disableConnectedAccountInformation, disableResourceIds, }) {
8
+ return (_jsx("div", { className: 'seam-device-details', children: _jsxs("div", { className: 'seam-body', children: [_jsx("div", { className: 'seam-summary', children: _jsxs("div", { className: 'seam-content', children: [_jsx("div", { className: 'seam-image', children: _jsx(DeviceImage, { device: device }) }), _jsxs("div", { className: 'seam-info', children: [_jsx("span", { className: 'seam-label', children: t.noiseSensor }), _jsx("h4", { className: 'seam-device-name', children: device.properties.name }), _jsxs("div", { className: 'seam-properties', children: [_jsxs("span", { className: 'seam-label', children: [t.status, ":"] }), ' ', _jsx(OnlineStatus, { device: device }), _jsx(DeviceModel, { device: device })] })] })] }) }), _jsx(NoiseThresholdsList, { device: device }), _jsx(DeviceInfo, { device: device, disableConnectedAccountInformation: disableConnectedAccountInformation, disableResourceIds: disableResourceIds })] }) }));
9
+ }
10
+ const t = {
11
+ noiseSensor: 'Noise Sensor',
12
+ status: 'Status',
13
+ noiseLevel: 'Noise level',
14
+ };
15
+ //# sourceMappingURL=NoiseSensorDeviceDetails.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NoiseSensorDeviceDetails.js","sourceRoot":"","sources":["../../../../src/lib/seam/components/DeviceDetails/NoiseSensorDeviceDetails.tsx"],"names":[],"mappings":";AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,iDAAiD,CAAA;AAC5E,OAAO,EAAE,WAAW,EAAE,MAAM,kDAAkD,CAAA;AAC9E,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAA;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAA;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,4CAA4C,CAAA;AAOhF,MAAM,UAAU,wBAAwB,CAAC,EACvC,MAAM,EACN,kCAAkC,EAClC,kBAAkB,GACY;IAC9B,OAAO,CACL,cAAK,SAAS,EAAC,qBAAqB,YAClC,eAAK,SAAS,EAAC,WAAW,aACxB,cAAK,SAAS,EAAC,cAAc,YAC3B,eAAK,SAAS,EAAC,cAAc,aAC3B,cAAK,SAAS,EAAC,YAAY,YACzB,KAAC,WAAW,IAAC,MAAM,EAAE,MAAM,GAAI,GAC3B,EACN,eAAK,SAAS,EAAC,WAAW,aACxB,eAAM,SAAS,EAAC,YAAY,YAAE,CAAC,CAAC,WAAW,GAAQ,EACnD,aAAI,SAAS,EAAC,kBAAkB,YAAE,MAAM,CAAC,UAAU,CAAC,IAAI,GAAM,EAC9D,eAAK,SAAS,EAAC,iBAAiB,aAC9B,gBAAM,SAAS,EAAC,YAAY,aAAE,CAAC,CAAC,MAAM,SAAS,EAAC,GAAG,EACnD,KAAC,YAAY,IAAC,MAAM,EAAE,MAAM,GAAI,EAChC,KAAC,WAAW,IAAC,MAAM,EAAE,MAAM,GAAI,IAC3B,IACF,IACF,GACF,EAEN,KAAC,mBAAmB,IAAC,MAAM,EAAE,MAAM,GAAI,EAEvC,KAAC,UAAU,IACT,MAAM,EAAE,MAAM,EACd,kCAAkC,EAChC,kCAAkC,EAEpC,kBAAkB,EAAE,kBAAkB,GACtC,IACE,GACF,CACP,CAAA;AACH,CAAC;AAED,MAAM,CAAC,GAAG;IACR,WAAW,EAAE,cAAc;IAC3B,MAAM,EAAE,QAAQ;IAChB,UAAU,EAAE,aAAa;CAC1B,CAAA"}
@@ -0,0 +1,5 @@
1
+ import type { NoiseThresholds, NoiseThresholdsListRequest } from 'seamapi';
2
+ import type { UseSeamQueryResult } from '../../../lib/seam/use-seam-query-result.js';
3
+ export type UseNoiseThresholdsParams = NoiseThresholdsListRequest;
4
+ export type UseNoiseThresholdsData = NoiseThresholds[];
5
+ export declare function useNoiseThresholds(params: UseNoiseThresholdsParams): UseSeamQueryResult<'noiseThresholds', UseNoiseThresholdsData>;
@@ -0,0 +1,26 @@
1
+ import { useQuery, useQueryClient } from '@tanstack/react-query';
2
+ import { useSeamClient } from '../../../lib/seam/use-seam-client.js';
3
+ export function useNoiseThresholds(params) {
4
+ const { client } = useSeamClient();
5
+ const queryClient = useQueryClient();
6
+ const { data, ...rest } = useQuery({
7
+ enabled: client != null,
8
+ queryKey: ['noise_thresholds', 'list', params],
9
+ queryFn: async () => {
10
+ if (client == null)
11
+ return [];
12
+ return await client.noiseThresholds.list(params);
13
+ },
14
+ onSuccess: (noiseThresholds) => {
15
+ for (const noiseThreshold of noiseThresholds) {
16
+ queryClient.setQueryData([
17
+ 'noise_thresholds',
18
+ 'get',
19
+ { noise_threshold_id: noiseThreshold.noise_threshold_id },
20
+ ], noiseThreshold);
21
+ }
22
+ },
23
+ });
24
+ return { ...rest, noiseThresholds: data };
25
+ }
26
+ //# sourceMappingURL=use-noise-thresholds.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-noise-thresholds.js","sourceRoot":"","sources":["../../../src/lib/seam/noise-sensors/use-noise-thresholds.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAQhE,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAM3D,MAAM,UAAU,kBAAkB,CAChC,MAAgC;IAEhC,MAAM,EAAE,MAAM,EAAE,GAAG,aAAa,EAAE,CAAA;IAClC,MAAM,WAAW,GAAG,cAAc,EAAE,CAAA;IAEpC,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,GAAG,QAAQ,CAGhC;QACA,OAAO,EAAE,MAAM,IAAI,IAAI;QACvB,QAAQ,EAAE,CAAC,kBAAkB,EAAE,MAAM,EAAE,MAAM,CAAC;QAC9C,OAAO,EAAE,KAAK,IAAI,EAAE;YAClB,IAAI,MAAM,IAAI,IAAI;gBAAE,OAAO,EAAE,CAAA;YAC7B,OAAO,MAAM,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAClD,CAAC;QACD,SAAS,EAAE,CAAC,eAAe,EAAE,EAAE;YAC7B,KAAK,MAAM,cAAc,IAAI,eAAe,EAAE,CAAC;gBAC7C,WAAW,CAAC,YAAY,CACtB;oBACE,kBAAkB;oBAClB,KAAK;oBACL,EAAE,kBAAkB,EAAE,cAAc,CAAC,kBAAkB,EAAE;iBAC1D,EACD,cAAc,CACf,CAAA;YACH,CAAC;QACH,CAAC;KACF,CAAC,CAAA;IAEF,OAAO,EAAE,GAAG,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,CAAA;AAC3C,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import type { PropsWithChildren } from 'react';
2
2
  interface DetailRowProps {
3
- label: string;
3
+ label: JSX.Element | string;
4
4
  sublabel?: string;
5
5
  onClick?: () => void;
6
6
  }
@@ -1,7 +1,7 @@
1
1
  import type { PropsWithChildren } from 'react';
2
2
  interface DetailSectionProps {
3
3
  label?: string;
4
- tooltipContent?: string;
4
+ tooltipContent?: JSX.Element | string;
5
5
  }
6
6
  export declare function DetailSection({ label, tooltipContent, children, }: PropsWithChildren<DetailSectionProps>): JSX.Element;
7
7
  export {};
@@ -0,0 +1,7 @@
1
+ /// <reference types="react" resolution-mode="require"/>
2
+ import type { NoiseSensorDevice } from 'seamapi';
3
+ interface NoiseThresholdsListProps {
4
+ device: NoiseSensorDevice;
5
+ }
6
+ export declare function NoiseThresholdsList({ device, }: NoiseThresholdsListProps): JSX.Element;
7
+ export {};
@@ -0,0 +1,45 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ZonedTime } from 'zoned-time';
3
+ import { formatTime, formatTimeZone } from '../../../lib/dates.js';
4
+ import { ArrowRightIcon } from '../../../lib/icons/ArrowRight.js';
5
+ import { useNoiseThresholds } from '../../../lib/seam/noise-sensors/use-noise-thresholds.js';
6
+ import { DetailRow } from '../../../lib/ui/layout/DetailRow.js';
7
+ import { DetailSection } from '../../../lib/ui/layout/DetailSection.js';
8
+ import { DetailSectionGroup } from '../../../lib/ui/layout/DetailSectionGroup.js';
9
+ export function NoiseThresholdsList({ device, }) {
10
+ const { noiseThresholds, isInitialLoading } = useNoiseThresholds({
11
+ device_id: device.device_id,
12
+ });
13
+ return (_jsx(DetailSectionGroup, { children: _jsxs("div", { className: 'seam-detail-section-wrap', children: [_jsx(DetailSection, { label: t.noiseThresholds, tooltipContent: device.device_type === 'minut_sensor' ? (_jsxs("div", { className: 'seam-detail-section-tooltip-inner-content', children: [_jsx("span", { className: 'seam-tooltip-content', children: t.minutTooltipFirst }), _jsx("span", { className: 'seam-tooltip-content', children: t.minutTooltipSecond })] })) : (t.tooltip), children: _jsx(Content, { isInitialLoading: isInitialLoading, noiseThresholds: noiseThresholds }) }), _jsxs("div", { className: 'seam-detail-section-footer', children: [_jsx("div", { className: 'seam-empty-div' }), _jsx("div", { className: 'seam-detail-section-footer-content', children: _jsx("div", { className: 'seam-detail-section-footer-content-text', children: _jsx("p", { children: getTimeZoneCaption(device, noiseThresholds) }) }) })] })] }) }));
14
+ }
15
+ function Content({ isInitialLoading, noiseThresholds, }) {
16
+ if (isInitialLoading) {
17
+ return (_jsx(DetailRow, { label: _jsx("span", { className: 'seam-detail-row-empty-label', children: t.loading }) }));
18
+ }
19
+ if (noiseThresholds == null || noiseThresholds.length === 0) {
20
+ return (_jsx(DetailRow, { label: _jsx("span", { className: 'seam-detail-row-empty-label', children: t.none }) }));
21
+ }
22
+ return noiseThresholds?.map((noiseThreshold) => (_jsx(DetailRow, { label: _jsxs("div", { className: 'seam-detail-row-label-column', children: [noiseThreshold.name !== '' && (_jsx("span", { className: 'seam-detail-row-label', children: noiseThreshold.name })), _jsxs("div", { className: 'seam-detail-row-label-block', children: [_jsx("span", { className: 'seam-row-sublabel seam-row-sublabel-text-default', children: formatTime(noiseThreshold.starts_daily_at) }), _jsx(ArrowRightIcon, {}), _jsx("span", { className: 'seam-row-sublabel seam-row-sublabel-text-default', children: formatTime(noiseThreshold.ends_daily_at) })] })] }), children: _jsxs("p", { children: [noiseThreshold.noise_threshold_decibels, " ", t.decibel] }) }, noiseThreshold.noise_threshold_id)));
23
+ }
24
+ const getTimeZoneCaption = (device, thresholds) => {
25
+ if (device.location?.timezone != null) {
26
+ return `${t.allTimesIn} ${formatTimeZone(device.location.timezone)}`;
27
+ }
28
+ const firstThreshold = thresholds?.[0];
29
+ if (firstThreshold != null) {
30
+ const zonedTime = ZonedTime.from(firstThreshold.starts_daily_at);
31
+ return `${t.allTimesIn} ${formatTimeZone(zonedTime.timeZone)}`;
32
+ }
33
+ return null;
34
+ };
35
+ const t = {
36
+ noiseThresholds: 'Noise thresholds',
37
+ tooltip: 'A noise threshold is the highest noise level (in dB) you want to allow for a given time range in the day.',
38
+ minutTooltipFirst: 'A noise threshold is the highest noise level (in dB) you want to allow.',
39
+ minutTooltipSecond: 'Quiet hours is a separate threshold that takes effect only for a specified time range.',
40
+ none: 'None',
41
+ loading: 'Loading...',
42
+ decibel: 'dB',
43
+ allTimesIn: 'All times in',
44
+ };
45
+ //# sourceMappingURL=NoiseThresholdsList.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NoiseThresholdsList.js","sourceRoot":"","sources":["../../../src/lib/ui/noise-sensor/NoiseThresholdsList.tsx"],"names":[],"mappings":"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"}
package/lib/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- declare const seamapiReactVersion = "2.14.0";
1
+ declare const seamapiReactVersion = "2.15.0";
2
2
  export default seamapiReactVersion;
package/lib/version.js CHANGED
@@ -1,3 +1,3 @@
1
- const seamapiReactVersion = '2.14.0';
1
+ const seamapiReactVersion = '2.15.0';
2
2
  export default seamapiReactVersion;
3
3
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seamapi/react",
3
- "version": "2.14.0",
3
+ "version": "2.15.0",
4
4
  "description": "Seam Components.",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -133,7 +133,8 @@
133
133
  "queue": "^7.0.0",
134
134
  "react-hook-form": "^7.46.1",
135
135
  "seamapi": "^8.22.0",
136
- "uuid": "^9.0.0"
136
+ "uuid": "^9.0.0",
137
+ "zoned-time": "^1.1.2"
137
138
  },
138
139
  "devDependencies": {
139
140
  "@emotion/styled": "^11.10.6",
package/src/lib/dates.ts CHANGED
@@ -23,6 +23,11 @@ export const formatTimeZone = (timeZone: string): string => {
23
23
  return `${timeZone.replaceAll('_', ' ')} (${offset})`
24
24
  }
25
25
 
26
+ export const formatTime = (time: string): string => {
27
+ const dateTime = DateTime.fromISO(time)
28
+ return dateTime.isValid ? dateTime.toLocaleString(DateTime.TIME_SIMPLE) : ''
29
+ }
30
+
26
31
  export const serializeDateTimePickerValue = (
27
32
  dateTime: DateTime,
28
33
  timeZone: string
@@ -0,0 +1,31 @@
1
+ /*
2
+ * Automatically generated by SVGR from assets/icons/*.svg.
3
+ * Do not edit this file or add other components to this directory.
4
+ */
5
+ import type { SVGProps } from 'react'
6
+ export function NoiseLevelsIcon(props: SVGProps<SVGSVGElement>): JSX.Element {
7
+ return (
8
+ <svg
9
+ xmlns='http://www.w3.org/2000/svg'
10
+ width={18}
11
+ height={19}
12
+ fill='none'
13
+ {...props}
14
+ >
15
+ <path
16
+ fill='#9DA1A9'
17
+ fillRule='evenodd'
18
+ d='M8.744 5.47q.046-.09.097-.18c.547-.966 1.534-1.77 3.412-1.77 1.016 0 1.76.259 2.302.638.546.381.934.916 1.186 1.537.516 1.273.415 2.81-.006 3.762-.362.816-.915 1.949-1.477 3.1-.464.952-.935 1.916-1.308 2.724-.603 1.303-1.939 1.383-2.55.842-.453-.401-.624-.87-.659-1.273-.018-.206 0-.389.034-.528.03-.127.062-.18.062-.18v.002l-.002.001a.767.767 0 0 0-.88-1.203 9.5 9.5 0 0 1-.745 1.489q-.021.264.002.55a3.43 3.43 0 0 0 1.171 2.291c1.467 1.298 3.974.783 4.96-1.346.338-.732.8-1.68 1.264-2.634.583-1.196 1.171-2.403 1.53-3.213.587-1.324.701-3.294.026-4.96-.343-.848-.901-1.64-1.73-2.22-.831-.58-1.89-.914-3.18-.914-2.106 0-3.509.827-4.378 1.983q.501.708.869 1.502M9.93 6.752c.298-.952 1.163-1.623 2.3-1.592.893.024 1.514.445 1.88.967.333.474.469 1.054.402 1.484a.767.767 0 0 1-1.517-.227v-.003a.5.5 0 0 0-.02-.11.8.8 0 0 0-.12-.263c-.106-.149-.289-.304-.666-.314-.45-.012-.701.219-.795.516-.1.32-.043.834.444 1.337.513.53.69 1.182.638 1.75-.046.5-.304 1.138-.898 1.382a.767.767 0 0 1-.665-1.38.4.4 0 0 0 .034-.14.69.69 0 0 0-.211-.544c-.822-.849-1.098-1.933-.806-2.863m.969 3.572.002-.003z'
19
+ clipRule='evenodd'
20
+ />
21
+ <path
22
+ fill='#27AE60'
23
+ d='m1.191 8.702-.816.974.844 1.007a1.312 1.312 0 0 0-.028-1.98M2.173 11.82l1.041 1.242a4.4 4.4 0 0 0 1.577-3.383c0-1.36-.614-2.575-1.58-3.385L2.17 7.536A2.79 2.79 0 0 1 3.17 9.679c0 .86-.387 1.628-.997 2.14'
24
+ />
25
+ <path
26
+ fill='#27AE60'
27
+ d='m4.154 14.183 1.042 1.242a7.48 7.48 0 0 0 2.679-5.746 7.48 7.48 0 0 0-2.683-5.748L4.151 5.173a5.87 5.87 0 0 1 2.103 4.506 5.87 5.87 0 0 1-2.1 4.503'
28
+ />
29
+ </svg>
30
+ )
31
+ }
@@ -1,10 +1,11 @@
1
- import { isLockDevice, isThermostatDevice } from 'seamapi'
1
+ import { isLockDevice, isNoiseSensorDevice, isThermostatDevice } from 'seamapi'
2
2
 
3
3
  import {
4
4
  type CommonProps,
5
5
  withRequiredCommonProps,
6
6
  } from 'lib/seam/components/common-props.js'
7
7
  import { LockDeviceDetails } from 'lib/seam/components/DeviceDetails/LockDeviceDetails.js'
8
+ import { NoiseSensorDeviceDetails } from 'lib/seam/components/DeviceDetails/NoiseSensorDeviceDetails.js'
8
9
  import { ThermostatDeviceDetails } from 'lib/seam/components/DeviceDetails/ThermostatDeviceDetails.js'
9
10
  import { useDevice } from 'lib/seam/devices/use-device.js'
10
11
  import { useComponentTelemetry } from 'lib/telemetry/index.js'
@@ -67,5 +68,9 @@ export function DeviceDetails({
67
68
  return <ThermostatDeviceDetails device={device} {...props} />
68
69
  }
69
70
 
71
+ if (isNoiseSensorDevice(device)) {
72
+ return <NoiseSensorDeviceDetails device={device} {...props} />
73
+ }
74
+
70
75
  return null
71
76
  }
@@ -0,0 +1,58 @@
1
+ import type { NoiseSensorDevice } from 'seamapi'
2
+
3
+ import type { NestedSpecificDeviceDetailsProps } from 'lib/seam/components/DeviceDetails/DeviceDetails.js'
4
+ import { DeviceInfo } from 'lib/seam/components/DeviceDetails/DeviceInfo.js'
5
+ import { DeviceModel } from 'lib/seam/components/DeviceDetails/DeviceModel.js'
6
+ import { DeviceImage } from 'lib/ui/device/DeviceImage.js'
7
+ import { OnlineStatus } from 'lib/ui/device/OnlineStatus.js'
8
+ import { NoiseThresholdsList } from 'lib/ui/noise-sensor/NoiseThresholdsList.js'
9
+
10
+ interface NoiseSensorDeviceDetailsProps
11
+ extends NestedSpecificDeviceDetailsProps {
12
+ device: NoiseSensorDevice
13
+ }
14
+
15
+ export function NoiseSensorDeviceDetails({
16
+ device,
17
+ disableConnectedAccountInformation,
18
+ disableResourceIds,
19
+ }: NoiseSensorDeviceDetailsProps): JSX.Element | null {
20
+ return (
21
+ <div className='seam-device-details'>
22
+ <div className='seam-body'>
23
+ <div className='seam-summary'>
24
+ <div className='seam-content'>
25
+ <div className='seam-image'>
26
+ <DeviceImage device={device} />
27
+ </div>
28
+ <div className='seam-info'>
29
+ <span className='seam-label'>{t.noiseSensor}</span>
30
+ <h4 className='seam-device-name'>{device.properties.name}</h4>
31
+ <div className='seam-properties'>
32
+ <span className='seam-label'>{t.status}:</span>{' '}
33
+ <OnlineStatus device={device} />
34
+ <DeviceModel device={device} />
35
+ </div>
36
+ </div>
37
+ </div>
38
+ </div>
39
+
40
+ <NoiseThresholdsList device={device} />
41
+
42
+ <DeviceInfo
43
+ device={device}
44
+ disableConnectedAccountInformation={
45
+ disableConnectedAccountInformation
46
+ }
47
+ disableResourceIds={disableResourceIds}
48
+ />
49
+ </div>
50
+ </div>
51
+ )
52
+ }
53
+
54
+ const t = {
55
+ noiseSensor: 'Noise Sensor',
56
+ status: 'Status',
57
+ noiseLevel: 'Noise level',
58
+ }
@@ -0,0 +1,46 @@
1
+ import { useQuery, useQueryClient } from '@tanstack/react-query'
2
+ import type {
3
+ NoiseThresholds,
4
+ NoiseThresholdsListRequest,
5
+ NoiseThresholdsListResponse,
6
+ SeamError,
7
+ } from 'seamapi'
8
+
9
+ import { useSeamClient } from 'lib/seam/use-seam-client.js'
10
+ import type { UseSeamQueryResult } from 'lib/seam/use-seam-query-result.js'
11
+
12
+ export type UseNoiseThresholdsParams = NoiseThresholdsListRequest
13
+ export type UseNoiseThresholdsData = NoiseThresholds[]
14
+
15
+ export function useNoiseThresholds(
16
+ params: UseNoiseThresholdsParams
17
+ ): UseSeamQueryResult<'noiseThresholds', UseNoiseThresholdsData> {
18
+ const { client } = useSeamClient()
19
+ const queryClient = useQueryClient()
20
+
21
+ const { data, ...rest } = useQuery<
22
+ NoiseThresholdsListResponse['noise_thresholds'],
23
+ SeamError
24
+ >({
25
+ enabled: client != null,
26
+ queryKey: ['noise_thresholds', 'list', params],
27
+ queryFn: async () => {
28
+ if (client == null) return []
29
+ return await client.noiseThresholds.list(params)
30
+ },
31
+ onSuccess: (noiseThresholds) => {
32
+ for (const noiseThreshold of noiseThresholds) {
33
+ queryClient.setQueryData(
34
+ [
35
+ 'noise_thresholds',
36
+ 'get',
37
+ { noise_threshold_id: noiseThreshold.noise_threshold_id },
38
+ ],
39
+ noiseThreshold
40
+ )
41
+ }
42
+ },
43
+ })
44
+
45
+ return { ...rest, noiseThresholds: data }
46
+ }
@@ -2,7 +2,7 @@ import classNames from 'classnames'
2
2
  import type { PropsWithChildren } from 'react'
3
3
 
4
4
  interface DetailRowProps {
5
- label: string
5
+ label: JSX.Element | string
6
6
  sublabel?: string
7
7
  onClick?: () => void
8
8
  }
@@ -4,7 +4,7 @@ import { Tooltip } from 'lib/ui/Tooltip/Tooltip.js'
4
4
 
5
5
  interface DetailSectionProps {
6
6
  label?: string
7
- tooltipContent?: string
7
+ tooltipContent?: JSX.Element | string
8
8
  }
9
9
 
10
10
  export function DetailSection({
@@ -0,0 +1,141 @@
1
+ import type { NoiseSensorDevice, NoiseThresholds } from 'seamapi'
2
+ import { ZonedTime } from 'zoned-time'
3
+
4
+ import { formatTime, formatTimeZone } from 'lib/dates.js'
5
+ import { ArrowRightIcon } from 'lib/icons/ArrowRight.js'
6
+ import { useNoiseThresholds } from 'lib/seam/noise-sensors/use-noise-thresholds.js'
7
+ import { DetailRow } from 'lib/ui/layout/DetailRow.js'
8
+ import { DetailSection } from 'lib/ui/layout/DetailSection.js'
9
+ import { DetailSectionGroup } from 'lib/ui/layout/DetailSectionGroup.js'
10
+
11
+ interface NoiseThresholdsListProps {
12
+ device: NoiseSensorDevice
13
+ }
14
+
15
+ export function NoiseThresholdsList({
16
+ device,
17
+ }: NoiseThresholdsListProps): JSX.Element {
18
+ const { noiseThresholds, isInitialLoading } = useNoiseThresholds({
19
+ device_id: device.device_id,
20
+ })
21
+
22
+ return (
23
+ <DetailSectionGroup>
24
+ <div className='seam-detail-section-wrap'>
25
+ <DetailSection
26
+ label={t.noiseThresholds}
27
+ tooltipContent={
28
+ device.device_type === 'minut_sensor' ? (
29
+ <div className='seam-detail-section-tooltip-inner-content'>
30
+ <span className='seam-tooltip-content'>
31
+ {t.minutTooltipFirst}
32
+ </span>
33
+ <span className='seam-tooltip-content'>
34
+ {t.minutTooltipSecond}
35
+ </span>
36
+ </div>
37
+ ) : (
38
+ t.tooltip
39
+ )
40
+ }
41
+ >
42
+ <Content
43
+ isInitialLoading={isInitialLoading}
44
+ noiseThresholds={noiseThresholds}
45
+ />
46
+ </DetailSection>
47
+
48
+ <div className='seam-detail-section-footer'>
49
+ <div className='seam-empty-div' />
50
+ <div className='seam-detail-section-footer-content'>
51
+ <div className='seam-detail-section-footer-content-text'>
52
+ <p>{getTimeZoneCaption(device, noiseThresholds)}</p>
53
+ </div>
54
+ </div>
55
+ </div>
56
+ </div>
57
+ </DetailSectionGroup>
58
+ )
59
+ }
60
+
61
+ function Content({
62
+ isInitialLoading,
63
+ noiseThresholds,
64
+ }: {
65
+ isInitialLoading: boolean
66
+ noiseThresholds: NoiseThresholds[] | undefined
67
+ }): JSX.Element | JSX.Element[] {
68
+ if (isInitialLoading) {
69
+ return (
70
+ <DetailRow
71
+ label={<span className='seam-detail-row-empty-label'>{t.loading}</span>}
72
+ />
73
+ )
74
+ }
75
+
76
+ if (noiseThresholds == null || noiseThresholds.length === 0) {
77
+ return (
78
+ <DetailRow
79
+ label={<span className='seam-detail-row-empty-label'>{t.none}</span>}
80
+ />
81
+ )
82
+ }
83
+
84
+ return noiseThresholds?.map((noiseThreshold) => (
85
+ <DetailRow
86
+ key={noiseThreshold.noise_threshold_id}
87
+ label={
88
+ <div className='seam-detail-row-label-column'>
89
+ {noiseThreshold.name !== '' && (
90
+ <span className='seam-detail-row-label'>{noiseThreshold.name}</span>
91
+ )}
92
+ <div className='seam-detail-row-label-block'>
93
+ <span className='seam-row-sublabel seam-row-sublabel-text-default'>
94
+ {formatTime(noiseThreshold.starts_daily_at)}
95
+ </span>
96
+ <ArrowRightIcon />
97
+ <span className='seam-row-sublabel seam-row-sublabel-text-default'>
98
+ {formatTime(noiseThreshold.ends_daily_at)}
99
+ </span>
100
+ </div>
101
+ </div>
102
+ }
103
+ >
104
+ <p>
105
+ {noiseThreshold.noise_threshold_decibels} {t.decibel}
106
+ </p>
107
+ </DetailRow>
108
+ ))
109
+ }
110
+
111
+ const getTimeZoneCaption = (
112
+ device: NoiseSensorDevice,
113
+ thresholds: NoiseThresholds[] | undefined
114
+ ): string | null => {
115
+ if (device.location?.timezone != null) {
116
+ return `${t.allTimesIn} ${formatTimeZone(device.location.timezone)}`
117
+ }
118
+
119
+ const firstThreshold = thresholds?.[0]
120
+
121
+ if (firstThreshold != null) {
122
+ const zonedTime = ZonedTime.from(firstThreshold.starts_daily_at)
123
+ return `${t.allTimesIn} ${formatTimeZone(zonedTime.timeZone)}`
124
+ }
125
+
126
+ return null
127
+ }
128
+
129
+ const t = {
130
+ noiseThresholds: 'Noise thresholds',
131
+ tooltip:
132
+ 'A noise threshold is the highest noise level (in dB) you want to allow for a given time range in the day.',
133
+ minutTooltipFirst:
134
+ 'A noise threshold is the highest noise level (in dB) you want to allow.',
135
+ minutTooltipSecond:
136
+ 'Quiet hours is a separate threshold that takes effect only for a specified time range.',
137
+ none: 'None',
138
+ loading: 'Loading...',
139
+ decibel: 'dB',
140
+ allTimesIn: 'All times in',
141
+ }
@@ -1,3 +1,3 @@
1
- const seamapiReactVersion = '2.14.0'
1
+ const seamapiReactVersion = '2.15.0'
2
2
 
3
3
  export default seamapiReactVersion
@@ -103,6 +103,7 @@
103
103
 
104
104
  .seam-label {
105
105
  color: colors.$text-gray-2;
106
+ white-space: nowrap;
106
107
  }
107
108
 
108
109
  .seam-status-text {