@seamapi/react 1.46.4 → 1.48.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 (62) hide show
  1. package/README.md +15 -4
  2. package/dist/elements.js +3624 -3588
  3. package/dist/elements.js.map +1 -1
  4. package/dist/index.css +65 -0
  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/icons/Info.d.ts +2 -0
  9. package/lib/icons/Info.js +7 -0
  10. package/lib/icons/Info.js.map +1 -0
  11. package/lib/icons/InfoDark.d.ts +2 -0
  12. package/lib/icons/InfoDark.js +7 -0
  13. package/lib/icons/InfoDark.js.map +1 -0
  14. package/lib/seam/components/AccessCodeDetails/AccessCodeDetails.js.map +1 -1
  15. package/lib/seam/components/AccessCodeDetails/AccessCodeDevice.js +1 -1
  16. package/lib/seam/components/AccessCodeDetails/AccessCodeDevice.js.map +1 -1
  17. package/lib/seam/components/ClimateSettingScheduleTable/ClimateSettingScheduleTable.d.ts +6 -1
  18. package/lib/seam/components/ClimateSettingScheduleTable/ClimateSettingScheduleTable.js +21 -4
  19. package/lib/seam/components/ClimateSettingScheduleTable/ClimateSettingScheduleTable.js.map +1 -1
  20. package/lib/seam/components/DeviceDetails/DeviceModel.js +2 -2
  21. package/lib/seam/components/DeviceDetails/DeviceModel.js.map +1 -1
  22. package/lib/seam/components/DeviceTable/DeviceRow.js +2 -2
  23. package/lib/seam/components/DeviceTable/DeviceRow.js.map +1 -1
  24. package/lib/seam/components/DeviceTable/DeviceTable.js +2 -2
  25. package/lib/seam/components/DeviceTable/DeviceTable.js.map +1 -1
  26. package/lib/seam/thermostats/climate-setting-schedules/use-climate-setting-schedule.d.ts +5 -0
  27. package/lib/seam/thermostats/climate-setting-schedules/use-climate-setting-schedule.js +24 -0
  28. package/lib/seam/thermostats/climate-setting-schedules/use-climate-setting-schedule.js.map +1 -0
  29. package/lib/seam/thermostats/climate-setting-schedules/use-climate-setting-schedules.js +1 -0
  30. package/lib/seam/thermostats/climate-setting-schedules/use-climate-setting-schedules.js.map +1 -1
  31. package/lib/seam/thermostats/climate-setting-schedules/use-create-climate-setting-schedule.d.ts +5 -0
  32. package/lib/seam/thermostats/climate-setting-schedules/use-create-climate-setting-schedule.js +21 -0
  33. package/lib/seam/thermostats/climate-setting-schedules/use-create-climate-setting-schedule.js.map +1 -0
  34. package/lib/seam/thermostats/climate-setting-schedules/use-delete-climate-setting-schedule.d.ts +5 -0
  35. package/lib/seam/thermostats/climate-setting-schedules/use-delete-climate-setting-schedule.js +27 -0
  36. package/lib/seam/thermostats/climate-setting-schedules/use-delete-climate-setting-schedule.js.map +1 -0
  37. package/lib/ui/Tooltip/Tooltip.d.ts +2 -0
  38. package/lib/ui/Tooltip/Tooltip.js +33 -0
  39. package/lib/ui/Tooltip/Tooltip.js.map +1 -0
  40. package/lib/ui/thermostat/ClimateSettingStatus.js +10 -3
  41. package/lib/ui/thermostat/ClimateSettingStatus.js.map +1 -1
  42. package/lib/version.d.ts +1 -1
  43. package/lib/version.js +1 -1
  44. package/package.json +4 -4
  45. package/src/lib/icons/Info.tsx +36 -0
  46. package/src/lib/icons/InfoDark.tsx +37 -0
  47. package/src/lib/seam/components/AccessCodeDetails/AccessCodeDetails.tsx +0 -2
  48. package/src/lib/seam/components/AccessCodeDetails/AccessCodeDevice.tsx +1 -1
  49. package/src/lib/seam/components/ClimateSettingScheduleTable/ClimateSettingScheduleTable.element.ts +4 -0
  50. package/src/lib/seam/components/ClimateSettingScheduleTable/ClimateSettingScheduleTable.tsx +59 -6
  51. package/src/lib/seam/components/DeviceDetails/DeviceModel.tsx +1 -0
  52. package/src/lib/seam/components/DeviceTable/DeviceRow.tsx +1 -0
  53. package/src/lib/seam/components/DeviceTable/DeviceTable.tsx +2 -2
  54. package/src/lib/seam/thermostats/climate-setting-schedules/use-climate-setting-schedule.ts +47 -0
  55. package/src/lib/seam/thermostats/climate-setting-schedules/use-climate-setting-schedules.ts +1 -0
  56. package/src/lib/seam/thermostats/climate-setting-schedules/use-create-climate-setting-schedule.ts +48 -0
  57. package/src/lib/seam/thermostats/climate-setting-schedules/use-delete-climate-setting-schedule.ts +53 -0
  58. package/src/lib/ui/Tooltip/Tooltip.tsx +64 -0
  59. package/src/lib/ui/thermostat/ClimateSettingStatus.tsx +12 -10
  60. package/src/lib/version.ts +1 -1
  61. package/src/styles/_main.scss +2 -0
  62. package/src/styles/_tooltip.scss +83 -0
@@ -0,0 +1,24 @@
1
+ import { useQuery } from '@tanstack/react-query';
2
+ import { useSeamClient } from '../../../../lib/seam/use-seam-client.js';
3
+ export function useClimateSettingSchedule(params) {
4
+ const normalizedParams = typeof params === 'string'
5
+ ? { climate_setting_schedule_id: params }
6
+ : params;
7
+ const { client } = useSeamClient();
8
+ const { data, ...rest } = useQuery({
9
+ enabled: client != null,
10
+ queryKey: [
11
+ 'thermostats',
12
+ 'climate_setting_schedules',
13
+ 'get',
14
+ normalizedParams,
15
+ ],
16
+ queryFn: async () => {
17
+ if (client == null)
18
+ return null;
19
+ return await client.thermostats.climateSettingSchedules.get(normalizedParams);
20
+ },
21
+ });
22
+ return { ...rest, climateSettingSchedule: data };
23
+ }
24
+ //# sourceMappingURL=use-climate-setting-schedule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-climate-setting-schedule.js","sourceRoot":"","sources":["../../../../src/lib/seam/thermostats/climate-setting-schedules/use-climate-setting-schedule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AAQhD,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAS3D,MAAM,UAAU,yBAAyB,CACvC,MAAuC;IAEvC,MAAM,gBAAgB,GACpB,OAAO,MAAM,KAAK,QAAQ;QACxB,CAAC,CAAC,EAAE,2BAA2B,EAAE,MAAM,EAAE;QACzC,CAAC,CAAC,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,EAAE,GAAG,aAAa,EAAE,CAAA;IAElC,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,GAAG,QAAQ,CAGhC;QACA,OAAO,EAAE,MAAM,IAAI,IAAI;QACvB,QAAQ,EAAE;YACR,aAAa;YACb,2BAA2B;YAC3B,KAAK;YACL,gBAAgB;SACjB;QACD,OAAO,EAAE,KAAK,IAAI,EAAE;YAClB,IAAI,MAAM,IAAI,IAAI;gBAAE,OAAO,IAAI,CAAA;YAC/B,OAAO,MAAM,MAAM,CAAC,WAAW,CAAC,uBAAuB,CAAC,GAAG,CACzD,gBAAgB,CACjB,CAAA;QACH,CAAC;KACF,CAAC,CAAA;IAEF,OAAO,EAAE,GAAG,IAAI,EAAE,sBAAsB,EAAE,IAAI,EAAE,CAAA;AAClD,CAAC"}
@@ -15,6 +15,7 @@ export function useClimateSettingSchedules(params) {
15
15
  // Prime cache for each schedule.
16
16
  for (const schedule of schedules) {
17
17
  queryClient.setQueryData([
18
+ 'thermostats',
18
19
  'climate_setting_schedules',
19
20
  'get',
20
21
  {
@@ -1 +1 @@
1
- {"version":3,"file":"use-climate-setting-schedules.js","sourceRoot":"","sources":["../../../../src/lib/seam/thermostats/climate-setting-schedules/use-climate-setting-schedules.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAQhE,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAO3D,MAAM,UAAU,0BAA0B,CACxC,MAAwC;IAKxC,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,aAAa,EAAE,2BAA2B,EAAE,MAAM,EAAE,MAAM,CAAC;QACtE,OAAO,EAAE,KAAK,IAAI,EAAE;YAClB,IAAI,MAAM,IAAI,IAAI;gBAAE,OAAO,EAAE,CAAA;YAC7B,OAAO,MAAM,MAAM,CAAC,WAAW,CAAC,uBAAuB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QACtE,CAAC;QACD,SAAS,EAAE,CAAC,SAAS,EAAE,EAAE;YACvB,iCAAiC;YACjC,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE;gBAChC,WAAW,CAAC,YAAY,CACtB;oBACE,2BAA2B;oBAC3B,KAAK;oBACL;wBACE,2BAA2B,EAAE,QAAQ,CAAC,2BAA2B;qBAClE;iBACF,EACD,QAAQ,CACT,CAAA;aACF;QACH,CAAC;KACF,CAAC,CAAA;IAEF,OAAO,EAAE,GAAG,IAAI,EAAE,uBAAuB,EAAE,IAAI,EAAE,CAAA;AACnD,CAAC"}
1
+ {"version":3,"file":"use-climate-setting-schedules.js","sourceRoot":"","sources":["../../../../src/lib/seam/thermostats/climate-setting-schedules/use-climate-setting-schedules.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAQhE,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAO3D,MAAM,UAAU,0BAA0B,CACxC,MAAwC;IAKxC,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,aAAa,EAAE,2BAA2B,EAAE,MAAM,EAAE,MAAM,CAAC;QACtE,OAAO,EAAE,KAAK,IAAI,EAAE;YAClB,IAAI,MAAM,IAAI,IAAI;gBAAE,OAAO,EAAE,CAAA;YAC7B,OAAO,MAAM,MAAM,CAAC,WAAW,CAAC,uBAAuB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QACtE,CAAC;QACD,SAAS,EAAE,CAAC,SAAS,EAAE,EAAE;YACvB,iCAAiC;YACjC,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE;gBAChC,WAAW,CAAC,YAAY,CACtB;oBACE,aAAa;oBACb,2BAA2B;oBAC3B,KAAK;oBACL;wBACE,2BAA2B,EAAE,QAAQ,CAAC,2BAA2B;qBAClE;iBACF,EACD,QAAQ,CACT,CAAA;aACF;QACH,CAAC;KACF,CAAC,CAAA;IAEF,OAAO,EAAE,GAAG,IAAI,EAAE,uBAAuB,EAAE,IAAI,EAAE,CAAA;AACnD,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { type UseMutationResult } from '@tanstack/react-query';
2
+ import type { ClimateSettingSchedule, ClimateSettingScheduleCreateRequest, SeamError } from 'seamapi';
3
+ export type UseCreateClimateSettingScheduleData = ClimateSettingSchedule;
4
+ export type UseCreateClimateSettingScheduleMutationParams = ClimateSettingScheduleCreateRequest;
5
+ export declare function useCreateClimateSettingSchedule(): UseMutationResult<UseCreateClimateSettingScheduleData, SeamError, UseCreateClimateSettingScheduleMutationParams>;
@@ -0,0 +1,21 @@
1
+ import { useMutation, useQueryClient, } from '@tanstack/react-query';
2
+ import { NullSeamClientError, useSeamClient } from '../../../../lib/seam/use-seam-client.js';
3
+ export function useCreateClimateSettingSchedule() {
4
+ const { client } = useSeamClient();
5
+ const queryClient = useQueryClient();
6
+ return useMutation({
7
+ mutationFn: async (mutationParams) => {
8
+ if (client === null)
9
+ throw new NullSeamClientError();
10
+ return await client.thermostats.climateSettingSchedules.create(mutationParams);
11
+ },
12
+ onSuccess: () => {
13
+ void queryClient.invalidateQueries([
14
+ 'thermostats',
15
+ 'climate_setting_schedules',
16
+ 'list',
17
+ ]);
18
+ },
19
+ });
20
+ }
21
+ //# sourceMappingURL=use-create-climate-setting-schedule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-create-climate-setting-schedule.js","sourceRoot":"","sources":["../../../../src/lib/seam/thermostats/climate-setting-schedules/use-create-climate-setting-schedule.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EAEX,cAAc,GACf,MAAM,uBAAuB,CAAA;AAQ9B,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAMhF,MAAM,UAAU,+BAA+B;IAK7C,MAAM,EAAE,MAAM,EAAE,GAAG,aAAa,EAAE,CAAA;IAClC,MAAM,WAAW,GAAG,cAAc,EAAE,CAAA;IAEpC,OAAO,WAAW,CAIhB;QACA,UAAU,EAAE,KAAK,EACf,cAA6D,EAC7D,EAAE;YACF,IAAI,MAAM,KAAK,IAAI;gBAAE,MAAM,IAAI,mBAAmB,EAAE,CAAA;YACpD,OAAO,MAAM,MAAM,CAAC,WAAW,CAAC,uBAAuB,CAAC,MAAM,CAC5D,cAAc,CACf,CAAA;QACH,CAAC;QACD,SAAS,EAAE,GAAG,EAAE;YACd,KAAK,WAAW,CAAC,iBAAiB,CAAC;gBACjC,aAAa;gBACb,2BAA2B;gBAC3B,MAAM;aACP,CAAC,CAAA;QACJ,CAAC;KACF,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { type UseMutationResult } from '@tanstack/react-query';
2
+ import type { ClimateSettingScheduleDeleteRequest, ClimateSettingScheduleDeleteResponse, SeamError } from 'seamapi';
3
+ export type UseDeleteClimateSettingScheduleMutationParams = ClimateSettingScheduleDeleteRequest;
4
+ export type UseDeleteClimateSettingScheduleData = ClimateSettingScheduleDeleteResponse;
5
+ export declare function useDeleteClimateSettingSchedule(): UseMutationResult<UseDeleteClimateSettingScheduleData, SeamError, UseDeleteClimateSettingScheduleMutationParams>;
@@ -0,0 +1,27 @@
1
+ import { useMutation, useQueryClient, } from '@tanstack/react-query';
2
+ import { NullSeamClientError, useSeamClient } from '../../../../lib/seam/use-seam-client.js';
3
+ export function useDeleteClimateSettingSchedule() {
4
+ const { client } = useSeamClient();
5
+ const queryClient = useQueryClient();
6
+ return useMutation({
7
+ mutationFn: async (mutationParams) => {
8
+ if (client === null)
9
+ throw new NullSeamClientError();
10
+ await client.thermostats.climateSettingSchedules.delete(mutationParams);
11
+ },
12
+ onSuccess: (_data, variables) => {
13
+ void queryClient.invalidateQueries([
14
+ 'thermostats',
15
+ 'climate_setting_schedules',
16
+ 'get',
17
+ { climate_setting_schedule_id: variables.climate_setting_schedule_id },
18
+ ]);
19
+ void queryClient.invalidateQueries([
20
+ 'thermostats',
21
+ 'climate_setting_schedules',
22
+ 'list',
23
+ ]);
24
+ },
25
+ });
26
+ }
27
+ //# sourceMappingURL=use-delete-climate-setting-schedule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-delete-climate-setting-schedule.js","sourceRoot":"","sources":["../../../../src/lib/seam/thermostats/climate-setting-schedules/use-delete-climate-setting-schedule.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EAEX,cAAc,GACf,MAAM,uBAAuB,CAAA;AAO9B,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAQhF,MAAM,UAAU,+BAA+B;IAK7C,MAAM,EAAE,MAAM,EAAE,GAAG,aAAa,EAAE,CAAA;IAClC,MAAM,WAAW,GAAG,cAAc,EAAE,CAAA;IAEpC,OAAO,WAAW,CAIhB;QACA,UAAU,EAAE,KAAK,EACf,cAA6D,EAC7D,EAAE;YACF,IAAI,MAAM,KAAK,IAAI;gBAAE,MAAM,IAAI,mBAAmB,EAAE,CAAA;YACpD,MAAM,MAAM,CAAC,WAAW,CAAC,uBAAuB,CAAC,MAAM,CAAC,cAAc,CAAC,CAAA;QACzE,CAAC;QACD,SAAS,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE;YAC9B,KAAK,WAAW,CAAC,iBAAiB,CAAC;gBACjC,aAAa;gBACb,2BAA2B;gBAC3B,KAAK;gBACL,EAAE,2BAA2B,EAAE,SAAS,CAAC,2BAA2B,EAAE;aACvE,CAAC,CAAA;YACF,KAAK,WAAW,CAAC,iBAAiB,CAAC;gBACjC,aAAa;gBACb,2BAA2B;gBAC3B,MAAM;aACP,CAAC,CAAA;QACJ,CAAC;KACF,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { type PropsWithChildren } from 'react';
2
+ export declare function Tooltip({ children }: PropsWithChildren): JSX.Element;
@@ -0,0 +1,33 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useState, } from 'react';
3
+ import { InfoIcon } from '../../../lib/icons/Info.js';
4
+ import { InfoDarkIcon } from '../../../lib/icons/InfoDark.js';
5
+ export function Tooltip({ children }) {
6
+ const [isOpen, setIsOpen] = useState(false);
7
+ useEffect(() => {
8
+ const handleClose = () => {
9
+ setIsOpen(false);
10
+ };
11
+ const handleEscape = (event) => {
12
+ if (event.key === 'Escape') {
13
+ handleClose();
14
+ }
15
+ };
16
+ if (isOpen) {
17
+ globalThis.document?.addEventListener('click', handleClose);
18
+ globalThis.addEventListener?.('keydown', handleEscape);
19
+ }
20
+ return () => {
21
+ globalThis.document?.removeEventListener('click', handleClose);
22
+ globalThis.removeEventListener?.('keydown', handleEscape);
23
+ };
24
+ }, [isOpen, setIsOpen]);
25
+ const handleToggle = (event) => {
26
+ event.stopPropagation();
27
+ setIsOpen((prev) => !prev);
28
+ };
29
+ return (_jsxs("div", { className: 'seam-tooltip', children: [_jsx("div", { className: 'seam-tooltip-trigger-wrap', children: _jsxs("button", { onClick: handleToggle, className: 'seam-tooltip-button', children: [_jsx("div", { className: 'seam-tooltip-button-icon seam-tooltip-button-icon-default', children: _jsx(InfoIcon, {}) }), _jsx("div", { className: 'seam-tooltip-button-icon seam-tooltip-button-icon-hover', children: _jsx(InfoDarkIcon, {}) })] }) }), _jsx("div", { className: 'seam-tooltip-popover', "aria-expanded": isOpen, onClick: (event) => {
30
+ event.stopPropagation();
31
+ }, children: _jsx("p", { className: 'seam-tooltip-text', children: children }) })] }));
32
+ }
33
+ //# sourceMappingURL=Tooltip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Tooltip.js","sourceRoot":"","sources":["../../../src/lib/ui/Tooltip/Tooltip.tsx"],"names":[],"mappings":";AAAA,OAAO,EAGL,SAAS,EACT,QAAQ,GACT,MAAM,OAAO,CAAA;AAEd,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAEpD,MAAM,UAAU,OAAO,CAAC,EAAE,QAAQ,EAAqB;IACrD,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAE3C,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,WAAW,GAAG,GAAS,EAAE;YAC7B,SAAS,CAAC,KAAK,CAAC,CAAA;QAClB,CAAC,CAAA;QAED,MAAM,YAAY,GAAG,CAAC,KAAoB,EAAQ,EAAE;YAClD,IAAI,KAAK,CAAC,GAAG,KAAK,QAAQ,EAAE;gBAC1B,WAAW,EAAE,CAAA;aACd;QACH,CAAC,CAAA;QACD,IAAI,MAAM,EAAE;YACV,UAAU,CAAC,QAAQ,EAAE,gBAAgB,CAAC,OAAO,EAAE,WAAW,CAAC,CAAA;YAC3D,UAAU,CAAC,gBAAgB,EAAE,CAAC,SAAS,EAAE,YAAY,CAAC,CAAA;SACvD;QAED,OAAO,GAAG,EAAE;YACV,UAAU,CAAC,QAAQ,EAAE,mBAAmB,CAAC,OAAO,EAAE,WAAW,CAAC,CAAA;YAC9D,UAAU,CAAC,mBAAmB,EAAE,CAAC,SAAS,EAAE,YAAY,CAAC,CAAA;QAC3D,CAAC,CAAA;IACH,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAA;IAEvB,MAAM,YAAY,GAAyC,CAAC,KAAK,EAAQ,EAAE;QACzE,KAAK,CAAC,eAAe,EAAE,CAAA;QACvB,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAA;IAC5B,CAAC,CAAA;IAED,OAAO,CACL,eAAK,SAAS,EAAC,cAAc,aAC3B,cAAK,SAAS,EAAC,2BAA2B,YACxC,kBAAQ,OAAO,EAAE,YAAY,EAAE,SAAS,EAAC,qBAAqB,aAC5D,cAAK,SAAS,EAAC,2DAA2D,YACxE,KAAC,QAAQ,KAAG,GACR,EACN,cAAK,SAAS,EAAC,yDAAyD,YACtE,KAAC,YAAY,KAAG,GACZ,IACC,GACL,EAEN,cACE,SAAS,EAAC,sBAAsB,mBACjB,MAAM,EACrB,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;oBACjB,KAAK,CAAC,eAAe,EAAE,CAAA;gBACzB,CAAC,YAED,YAAG,SAAS,EAAC,mBAAmB,YAAE,QAAQ,GAAK,GAC3C,IACF,CACP,CAAA;AACH,CAAC"}
@@ -4,11 +4,11 @@ import { ThermostatHeatIcon } from '../../../lib/icons/ThermostatHeat.js';
4
4
  import { ThermostatHeatCoolIcon } from '../../../lib/icons/ThermostatHeatCool.js';
5
5
  import { ThermostatOffIcon } from '../../../lib/icons/ThermostatOff.js';
6
6
  export function ClimateSettingStatus({ climateSetting, temperatureUnit = 'fahrenheit', iconPlacement = 'left', }) {
7
- return (_jsxs("div", { className: 'seam-climate-setting-status', children: [iconPlacement === 'left' && (_jsx(ClimateSettingIcon, { mode: climateSetting.hvac_mode_setting })), _jsx(Content, { mode: climateSetting.hvac_mode_setting, coolingSetPoint: temperatureUnit === 'fahrenheit'
7
+ return (_jsxs("div", { className: 'seam-climate-setting-status', children: [iconPlacement === 'left' && (_jsx(ClimateSettingIcon, { mode: climateSetting.hvac_mode_setting })), _jsx(Content, { mode: climateSetting.hvac_mode_setting, coolingSetPoint: formatTemperatureValue(temperatureUnit === 'fahrenheit'
8
8
  ? climateSetting.cooling_set_point_fahrenheit
9
- : climateSetting.cooling_set_point_celsius, heatingSetPoint: temperatureUnit === 'fahrenheit'
9
+ : climateSetting.cooling_set_point_celsius), heatingSetPoint: formatTemperatureValue(temperatureUnit === 'fahrenheit'
10
10
  ? climateSetting.heating_set_point_fahrenheit
11
- : climateSetting.heating_set_point_celsius, temperatureUnit: temperatureUnit }), iconPlacement === 'right' && (_jsx(ClimateSettingIcon, { mode: climateSetting.hvac_mode_setting }))] }));
11
+ : climateSetting.heating_set_point_celsius), temperatureUnit: temperatureUnit }), iconPlacement === 'right' && (_jsx(ClimateSettingIcon, { mode: climateSetting.hvac_mode_setting }))] }));
12
12
  }
13
13
  function ClimateSettingIcon(props) {
14
14
  const { mode } = props;
@@ -29,6 +29,13 @@ function Content(props) {
29
29
  return _jsx("span", { children: t.off });
30
30
  return null;
31
31
  }
32
+ const formatTemperatureValue = (value) => {
33
+ if (value == null)
34
+ return '0';
35
+ if (Number.isInteger(value))
36
+ return value.toFixed();
37
+ return value.toFixed(1);
38
+ };
32
39
  const t = {
33
40
  degreeFahrenheit: '°F',
34
41
  degreeCelsius: '°C',
@@ -1 +1 @@
1
- {"version":3,"file":"ClimateSettingStatus.js","sourceRoot":"","sources":["../../../src/lib/ui/thermostat/ClimateSettingStatus.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAA;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAA;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAA;AACxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AAQ9D,MAAM,UAAU,oBAAoB,CAAC,EACnC,cAAc,EACd,eAAe,GAAG,YAAY,EAC9B,aAAa,GAAG,MAAM,GACI;IAC1B,OAAO,CACL,eAAK,SAAS,EAAC,6BAA6B,aACzC,aAAa,KAAK,MAAM,IAAI,CAC3B,KAAC,kBAAkB,IAAC,IAAI,EAAE,cAAc,CAAC,iBAAiB,GAAI,CAC/D,EACD,KAAC,OAAO,IACN,IAAI,EAAE,cAAc,CAAC,iBAAiB,EACtC,eAAe,EACb,eAAe,KAAK,YAAY;oBAC9B,CAAC,CAAC,cAAc,CAAC,4BAA4B;oBAC7C,CAAC,CAAC,cAAc,CAAC,yBAAyB,EAE9C,eAAe,EACb,eAAe,KAAK,YAAY;oBAC9B,CAAC,CAAC,cAAc,CAAC,4BAA4B;oBAC7C,CAAC,CAAC,cAAc,CAAC,yBAAyB,EAE9C,eAAe,EAAE,eAAe,GAChC,EACD,aAAa,KAAK,OAAO,IAAI,CAC5B,KAAC,kBAAkB,IAAC,IAAI,EAAE,cAAc,CAAC,iBAAiB,GAAI,CAC/D,IACG,CACP,CAAA;AACH,CAAC;AAED,SAAS,kBAAkB,CAAC,KAE3B;IACC,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,CAAA;IAEtB,OAAO,CACL,eAAK,SAAS,EAAC,kCAAkC,aAC9C,IAAI,KAAK,MAAM,IAAI,KAAC,kBAAkB,KAAG,EACzC,IAAI,KAAK,MAAM,IAAI,KAAC,kBAAkB,KAAG,EACzC,IAAI,KAAK,UAAU,IAAI,KAAC,sBAAsB,KAAG,EACjD,IAAI,KAAK,KAAK,IAAI,KAAC,iBAAiB,KAAG,IACpC,CACP,CAAA;AACH,CAAC;AAED,SAAS,OAAO,CAAC,KAShB;IACC,MAAM,EAAE,IAAI,EAAE,eAAe,EAAE,eAAe,EAAE,eAAe,EAAE,GAAG,KAAK,CAAA;IACzE,MAAM,kBAAkB,GAAG,eAAe,KAAK,SAAS,CAAA;IACxD,MAAM,kBAAkB,GAAG,eAAe,KAAK,SAAS,CAAA;IACxD,MAAM,IAAI,GACR,eAAe,KAAK,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAA;IAEzE,IAAI,IAAI,KAAK,MAAM,IAAI,kBAAkB;QACvC,OAAO,yBAAO,GAAG,eAAe,GAAG,IAAI,EAAE,GAAQ,CAAA;IAEnD,IAAI,IAAI,KAAK,MAAM,IAAI,kBAAkB;QACvC,OAAO,yBAAO,GAAG,eAAe,GAAG,IAAI,EAAE,GAAQ,CAAA;IAEnD,IAAI,IAAI,KAAK,UAAU,IAAI,kBAAkB,IAAI,kBAAkB;QACjE,OAAO,CACL,yBAAO,GAAG,eAAe,GAAG,IAAI,MAAM,eAAe,GAAG,IAAI,EAAE,GAAQ,CACvE,CAAA;IAEH,IAAI,IAAI,KAAK,KAAK;QAAE,OAAO,yBAAO,CAAC,CAAC,GAAG,GAAQ,CAAA;IAE/C,OAAO,IAAI,CAAA;AACb,CAAC;AAED,MAAM,CAAC,GAAG;IACR,gBAAgB,EAAE,IAAI;IACtB,aAAa,EAAE,IAAI;IACnB,GAAG,EAAE,KAAK;CACX,CAAA"}
1
+ {"version":3,"file":"ClimateSettingStatus.js","sourceRoot":"","sources":["../../../src/lib/ui/thermostat/ClimateSettingStatus.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAA;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAA;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAA;AACxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AAQ9D,MAAM,UAAU,oBAAoB,CAAC,EACnC,cAAc,EACd,eAAe,GAAG,YAAY,EAC9B,aAAa,GAAG,MAAM,GACI;IAC1B,OAAO,CACL,eAAK,SAAS,EAAC,6BAA6B,aACzC,aAAa,KAAK,MAAM,IAAI,CAC3B,KAAC,kBAAkB,IAAC,IAAI,EAAE,cAAc,CAAC,iBAAiB,GAAI,CAC/D,EACD,KAAC,OAAO,IACN,IAAI,EAAE,cAAc,CAAC,iBAAiB,EACtC,eAAe,EAAE,sBAAsB,CACrC,eAAe,KAAK,YAAY;oBAC9B,CAAC,CAAC,cAAc,CAAC,4BAA4B;oBAC7C,CAAC,CAAC,cAAc,CAAC,yBAAyB,CAC7C,EACD,eAAe,EAAE,sBAAsB,CACrC,eAAe,KAAK,YAAY;oBAC9B,CAAC,CAAC,cAAc,CAAC,4BAA4B;oBAC7C,CAAC,CAAC,cAAc,CAAC,yBAAyB,CAC7C,EACD,eAAe,EAAE,eAAe,GAChC,EACD,aAAa,KAAK,OAAO,IAAI,CAC5B,KAAC,kBAAkB,IAAC,IAAI,EAAE,cAAc,CAAC,iBAAiB,GAAI,CAC/D,IACG,CACP,CAAA;AACH,CAAC;AAED,SAAS,kBAAkB,CAAC,KAE3B;IACC,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,CAAA;IAEtB,OAAO,CACL,eAAK,SAAS,EAAC,kCAAkC,aAC9C,IAAI,KAAK,MAAM,IAAI,KAAC,kBAAkB,KAAG,EACzC,IAAI,KAAK,MAAM,IAAI,KAAC,kBAAkB,KAAG,EACzC,IAAI,KAAK,UAAU,IAAI,KAAC,sBAAsB,KAAG,EACjD,IAAI,KAAK,KAAK,IAAI,KAAC,iBAAiB,KAAG,IACpC,CACP,CAAA;AACH,CAAC;AAED,SAAS,OAAO,CAAC,KAKhB;IACC,MAAM,EAAE,IAAI,EAAE,eAAe,EAAE,eAAe,EAAE,eAAe,EAAE,GAAG,KAAK,CAAA;IACzE,MAAM,kBAAkB,GAAG,eAAe,KAAK,SAAS,CAAA;IACxD,MAAM,kBAAkB,GAAG,eAAe,KAAK,SAAS,CAAA;IACxD,MAAM,IAAI,GACR,eAAe,KAAK,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAA;IAEzE,IAAI,IAAI,KAAK,MAAM,IAAI,kBAAkB;QACvC,OAAO,yBAAO,GAAG,eAAe,GAAG,IAAI,EAAE,GAAQ,CAAA;IAEnD,IAAI,IAAI,KAAK,MAAM,IAAI,kBAAkB;QACvC,OAAO,yBAAO,GAAG,eAAe,GAAG,IAAI,EAAE,GAAQ,CAAA;IAEnD,IAAI,IAAI,KAAK,UAAU,IAAI,kBAAkB,IAAI,kBAAkB;QACjE,OAAO,CACL,yBAAO,GAAG,eAAe,GAAG,IAAI,MAAM,eAAe,GAAG,IAAI,EAAE,GAAQ,CACvE,CAAA;IAEH,IAAI,IAAI,KAAK,KAAK;QAAE,OAAO,yBAAO,CAAC,CAAC,GAAG,GAAQ,CAAA;IAE/C,OAAO,IAAI,CAAA;AACb,CAAC;AAED,MAAM,sBAAsB,GAAG,CAAC,KAAyB,EAAU,EAAE;IACnE,IAAI,KAAK,IAAI,IAAI;QAAE,OAAO,GAAG,CAAA;IAC7B,IAAI,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,OAAO,EAAE,CAAA;IACnD,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;AACzB,CAAC,CAAA;AAED,MAAM,CAAC,GAAG;IACR,gBAAgB,EAAE,IAAI;IACtB,aAAa,EAAE,IAAI;IACnB,GAAG,EAAE,KAAK;CACX,CAAA"}
package/lib/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- declare const seamapiReactVersion = "1.46.4";
1
+ declare const seamapiReactVersion = "1.48.0";
2
2
  export default seamapiReactVersion;
package/lib/version.js CHANGED
@@ -1,3 +1,3 @@
1
- const seamapiReactVersion = '1.46.4';
1
+ const seamapiReactVersion = '1.48.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": "1.46.4",
3
+ "version": "1.48.0",
4
4
  "description": "Seam Components.",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -122,7 +122,7 @@
122
122
  "@tanstack/react-query": "^4.28.0",
123
123
  "classnames": "^2.3.2",
124
124
  "luxon": "^3.3.0",
125
- "seamapi": "^8.2.4",
125
+ "seamapi": "^8.6.3",
126
126
  "uuid": "^9.0.0"
127
127
  },
128
128
  "devDependencies": {
@@ -133,7 +133,7 @@
133
133
  "@mui/icons-material": "^5.11.16",
134
134
  "@mui/material": "^5.12.2",
135
135
  "@rxfork/r2wc-react-to-web-component": "^2.3.0",
136
- "@seamapi/fake-seam-connect": "^1.5.0",
136
+ "@seamapi/fake-seam-connect": "^1.6.0",
137
137
  "@storybook/addon-designs": "^7.0.1",
138
138
  "@storybook/addon-essentials": "^7.0.2",
139
139
  "@storybook/addon-links": "^7.0.2",
@@ -155,7 +155,7 @@
155
155
  "copy-webpack-plugin": "^11.0.0",
156
156
  "del-cli": "^5.0.0",
157
157
  "eslint": "^8.9.0",
158
- "eslint-config-prettier": "^8.4.0",
158
+ "eslint-config-prettier": "^9.0.0",
159
159
  "eslint-config-standard": "^17.1.0",
160
160
  "eslint-config-standard-jsx": "^11.0.0",
161
161
  "eslint-config-standard-react": "^13.0.0",
@@ -0,0 +1,36 @@
1
+ /*
2
+ * Automaically 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 InfoIcon(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
+ <mask
16
+ id='info_svg__a'
17
+ width={18}
18
+ height={19}
19
+ x={0}
20
+ y={0}
21
+ maskUnits='userSpaceOnUse'
22
+ style={{
23
+ maskType: 'alpha',
24
+ }}
25
+ >
26
+ <path fill='#D9D9D9' d='M0 .5h18v18H0z' />
27
+ </mask>
28
+ <g mask='url(#info_svg__a)'>
29
+ <path
30
+ fill='#D5D8DC'
31
+ d='M8.25 13.25h1.5v-4.5h-1.5v4.5Zm.75-6c.213 0 .39-.072.535-.216A.725.725 0 0 0 9.75 6.5a.728.728 0 0 0-.215-.535A.728.728 0 0 0 9 5.75a.725.725 0 0 0-.534.215.726.726 0 0 0-.216.535c0 .213.072.39.216.534A.724.724 0 0 0 9 7.25ZM9 17a7.3 7.3 0 0 1-2.925-.591 7.569 7.569 0 0 1-2.381-1.603 7.569 7.569 0 0 1-1.603-2.381A7.3 7.3 0 0 1 1.5 9.5a7.3 7.3 0 0 1 .591-2.925 7.569 7.569 0 0 1 1.603-2.381A7.58 7.58 0 0 1 6.075 2.59 7.307 7.307 0 0 1 9 2c1.037 0 2.012.197 2.925.59a7.58 7.58 0 0 1 2.381 1.604 7.569 7.569 0 0 1 1.603 2.381A7.3 7.3 0 0 1 16.5 9.5a7.3 7.3 0 0 1-.591 2.925 7.569 7.569 0 0 1-1.603 2.381 7.569 7.569 0 0 1-2.381 1.603A7.3 7.3 0 0 1 9 17Zm0-1.5c1.675 0 3.094-.581 4.256-1.744C14.42 12.594 15 11.175 15 9.5c0-1.675-.581-3.094-1.744-4.256C12.094 4.08 10.675 3.5 9 3.5c-1.675 0-3.094.581-4.256 1.744C3.58 6.406 3 7.825 3 9.5c0 1.675.581 3.094 1.744 4.256C5.906 14.92 7.325 15.5 9 15.5Z'
32
+ />
33
+ </g>
34
+ </svg>
35
+ )
36
+ }
@@ -0,0 +1,37 @@
1
+ /*
2
+ * Automaically 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 InfoDarkIcon(props: SVGProps<SVGSVGElement>): JSX.Element {
7
+ return (
8
+ <svg
9
+ xmlns='http://www.w3.org/2000/svg'
10
+ width={19}
11
+ height={19}
12
+ fill='none'
13
+ {...props}
14
+ >
15
+ <circle cx={9.755} cy={9.416} r={6.655} fill='#E9EDEF' />
16
+ <mask
17
+ id='info-dark_svg__a'
18
+ width={19}
19
+ height={19}
20
+ x={0}
21
+ y={0}
22
+ maskUnits='userSpaceOnUse'
23
+ style={{
24
+ maskType: 'alpha',
25
+ }}
26
+ >
27
+ <path fill='#D9D9D9' d='M.755.416h18v18h-18z' />
28
+ </mask>
29
+ <g mask='url(#info-dark_svg__a)'>
30
+ <path
31
+ fill='#9DA1A9'
32
+ d='M9.005 13.166h1.5v-4.5h-1.5v4.5Zm.75-6c.213 0 .391-.072.535-.216a.725.725 0 0 0 .215-.534.728.728 0 0 0-.215-.534.728.728 0 0 0-.535-.216.725.725 0 0 0-.534.216.726.726 0 0 0-.216.534c0 .213.072.39.216.534a.724.724 0 0 0 .534.216Zm0 9.75a7.3 7.3 0 0 1-2.925-.59 7.569 7.569 0 0 1-2.38-1.603 7.568 7.568 0 0 1-1.604-2.382 7.3 7.3 0 0 1-.59-2.925 7.3 7.3 0 0 1 .59-2.925 7.569 7.569 0 0 1 1.603-2.38A7.58 7.58 0 0 1 6.83 2.506a7.307 7.307 0 0 1 2.925-.59c1.038 0 2.013.196 2.925.59a7.579 7.579 0 0 1 2.382 1.603 7.569 7.569 0 0 1 1.602 2.381 7.3 7.3 0 0 1 .591 2.925 7.3 7.3 0 0 1-.59 2.925 7.569 7.569 0 0 1-1.603 2.382 7.569 7.569 0 0 1-2.382 1.602 7.3 7.3 0 0 1-2.925.591Zm0-1.5c1.675 0 3.094-.58 4.257-1.743 1.162-1.163 1.743-2.582 1.743-4.257 0-1.675-.58-3.093-1.743-4.256-1.163-1.162-2.582-1.744-4.257-1.744-1.675 0-3.093.582-4.256 1.744-1.162 1.163-1.744 2.581-1.744 4.256 0 1.675.582 3.094 1.744 4.257 1.163 1.162 2.581 1.743 4.256 1.743Z'
33
+ />
34
+ </g>
35
+ </svg>
36
+ )
37
+ }
@@ -87,9 +87,7 @@ export function AccessCodeDetails({
87
87
  <Duration accessCode={accessCode} />
88
88
  </div>
89
89
  </div>
90
-
91
90
  <Alerts alerts={alerts} className='seam-alerts-padded' />
92
-
93
91
  <AccessCodeDevice
94
92
  deviceId={accessCode.device_id}
95
93
  disableLockUnlock={disableLockUnlock}
@@ -56,7 +56,7 @@ function Content(props: {
56
56
  <DeviceImage device={device} />
57
57
  </div>
58
58
  <div className='seam-body'>
59
- <div className='seam-model'>{device.properties.model.display_name}</div>
59
+ <div>{device.properties.name}</div>
60
60
  <TextButton
61
61
  onClick={() => {
62
62
  onSelectDevice(device.device_id)
@@ -6,7 +6,11 @@ export const name = 'seam-climate-setting-schedule-table'
6
6
 
7
7
  export const props: ElementProps<ClimateSettingScheduleTableProps> = {
8
8
  deviceId: 'string',
9
+ disableSearch: 'boolean',
10
+ climateSettingScheduleFilter: 'object',
11
+ climateSettingScheduleComparator: 'object',
9
12
  onBack: 'object',
13
+ heading: 'string',
10
14
  className: 'string',
11
15
  }
12
16
 
@@ -1,5 +1,8 @@
1
1
  import classNames from 'classnames'
2
+ import { useMemo, useState } from 'react'
3
+ import type { ClimateSettingSchedule } from 'seamapi'
2
4
 
5
+ import { compareByCreatedAtDesc } from 'lib/dates.js'
3
6
  import {
4
7
  useClimateSettingSchedules,
5
8
  type UseClimateSettingSchedulesData,
@@ -9,19 +12,44 @@ import { EmptyPlaceholder } from 'lib/ui/Table/EmptyPlaceholder.js'
9
12
  import { TableBody } from 'lib/ui/Table/TableBody.js'
10
13
  import { TableHeader } from 'lib/ui/Table/TableHeader.js'
11
14
  import { TableTitle } from 'lib/ui/Table/TableTitle.js'
15
+ import { SearchTextField } from 'lib/ui/TextField/SearchTextField.js'
12
16
  import { Caption } from 'lib/ui/typography/Caption.js'
13
17
 
14
18
  import { ClimateSettingScheduleRow } from './ClimateSettingScheduleRow.js'
15
19
 
16
20
  export interface ClimateSettingScheduleTableProps {
17
21
  deviceId: string
22
+ disableSearch?: boolean
23
+ climateSettingScheduleFilter?: (
24
+ climateSettingSchedule: ClimateSettingSchedule,
25
+ searchInputValue: string
26
+ ) => boolean
27
+ climateSettingScheduleComparator?: (
28
+ climateSettingScheduleA: ClimateSettingSchedule,
29
+ climateSettingScheduleB: ClimateSettingSchedule
30
+ ) => number
18
31
  onBack?: () => void
32
+ heading?: string | null
19
33
  className?: string
20
34
  }
21
35
 
36
+ const defaultClimateSettingScheduleFilter = (
37
+ climateSettingSchedule: ClimateSettingSchedule,
38
+ searchInputValue: string
39
+ ): boolean => {
40
+ const value = searchInputValue.trim().toLowerCase()
41
+ if (value === '') return true
42
+ const name = climateSettingSchedule.name ?? ''
43
+ return name.trim().toLowerCase().includes(value)
44
+ }
45
+
22
46
  export function ClimateSettingScheduleTable({
23
47
  deviceId,
48
+ disableSearch = false,
49
+ climateSettingScheduleFilter = defaultClimateSettingScheduleFilter,
50
+ climateSettingScheduleComparator = compareByCreatedAtDesc,
24
51
  onBack,
52
+ heading = t.climateSettingSchedules,
25
53
  className,
26
54
  }: ClimateSettingScheduleTableProps): JSX.Element {
27
55
  const { climateSettingSchedules, isLoading, isError, error } =
@@ -29,8 +57,22 @@ export function ClimateSettingScheduleTable({
29
57
  device_id: deviceId,
30
58
  })
31
59
 
32
- // TODO filtering
33
- const filteredClimateSettingSchedules = climateSettingSchedules ?? []
60
+ const [searchInputValue, setSearchInputValue] = useState('')
61
+
62
+ const filteredClimateSettingSchedules = useMemo(
63
+ () =>
64
+ climateSettingSchedules
65
+ ?.filter((schedule) =>
66
+ climateSettingScheduleFilter(schedule, searchInputValue)
67
+ )
68
+ ?.sort(climateSettingScheduleComparator) ?? [],
69
+ [
70
+ climateSettingSchedules,
71
+ searchInputValue,
72
+ climateSettingScheduleFilter,
73
+ climateSettingScheduleComparator,
74
+ ]
75
+ )
34
76
 
35
77
  if (isLoading) {
36
78
  return <p className={className}>...</p>
@@ -44,10 +86,21 @@ export function ClimateSettingScheduleTable({
44
86
  <div className={classNames('seam-table', className)}>
45
87
  <ContentHeader onBack={onBack} />
46
88
  <TableHeader>
47
- <TableTitle>
48
- {t.climateSettingSchedules}{' '}
49
- <Caption>({filteredClimateSettingSchedules.length})</Caption>
50
- </TableTitle>
89
+ {heading != null ? (
90
+ <TableTitle>
91
+ {heading ?? t.climateSettingSchedules}{' '}
92
+ <Caption>({filteredClimateSettingSchedules.length})</Caption>
93
+ </TableTitle>
94
+ ) : (
95
+ <div className='seam-fragment' />
96
+ )}
97
+ {!disableSearch && (
98
+ <SearchTextField
99
+ value={searchInputValue}
100
+ onChange={setSearchInputValue}
101
+ disabled={(climateSettingSchedules?.length ?? 0) === 0}
102
+ />
103
+ )}
51
104
  </TableHeader>
52
105
  <TableBody>
53
106
  <Content
@@ -9,6 +9,7 @@ export function DeviceModel({ device }: DeviceModelProps): JSX.Element | null {
9
9
  <>
10
10
  <span className='seam-label'>{t.model}:</span>{' '}
11
11
  <div className='seam-device-model'>
12
+ {device.properties.model.manufacturer_display_name}{' '}
12
13
  {device.properties.model.display_name}
13
14
  </div>
14
15
  </>
@@ -57,6 +57,7 @@ export function DeviceRow({
57
57
  'seam-offline-fade': isDisconnected,
58
58
  })}
59
59
  >
60
+ {device.properties.model.manufacturer_display_name}{' '}
60
61
  {device.properties.model.display_name}
61
62
  </span>
62
63
  <div className='seam-device-statuses'>
@@ -1,6 +1,6 @@
1
1
  import classNames from 'classnames'
2
2
  import { useCallback, useMemo, useState } from 'react'
3
- import { isLockDevice } from 'seamapi'
3
+ import { isLockDevice, isThermostatDevice } from 'seamapi'
4
4
 
5
5
  import { compareByCreatedAtDesc } from 'lib/dates.js'
6
6
  import { DeviceDetails } from 'lib/seam/components/DeviceDetails/DeviceDetails.js'
@@ -76,7 +76,7 @@ export function DeviceTable({
76
76
  const filteredDevices = useMemo(
77
77
  () =>
78
78
  devices
79
- ?.filter(isLockDevice)
79
+ ?.filter((device) => isLockDevice(device) || isThermostatDevice(device))
80
80
  ?.filter((device) => deviceFilter(device, searchInputValue))
81
81
  ?.sort(deviceComparator) ?? [],
82
82
  [devices, searchInputValue, deviceFilter, deviceComparator]
@@ -0,0 +1,47 @@
1
+ import { useQuery } from '@tanstack/react-query'
2
+ import type {
3
+ ClimateSettingSchedule,
4
+ ClimateSettingScheduleGetRequest,
5
+ ClimateSettingScheduleGetResponse,
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 UseClimateSettingScheduleParams =
13
+ | ClimateSettingScheduleGetRequest
14
+ | string
15
+
16
+ export type UseClimateSettingScheduleData = ClimateSettingSchedule | null
17
+
18
+ export function useClimateSettingSchedule(
19
+ params: UseClimateSettingScheduleParams
20
+ ): UseSeamQueryResult<'climateSettingSchedule', UseClimateSettingScheduleData> {
21
+ const normalizedParams =
22
+ typeof params === 'string'
23
+ ? { climate_setting_schedule_id: params }
24
+ : params
25
+ const { client } = useSeamClient()
26
+
27
+ const { data, ...rest } = useQuery<
28
+ ClimateSettingScheduleGetResponse['climate_setting_schedule'] | null,
29
+ SeamError
30
+ >({
31
+ enabled: client != null,
32
+ queryKey: [
33
+ 'thermostats',
34
+ 'climate_setting_schedules',
35
+ 'get',
36
+ normalizedParams,
37
+ ],
38
+ queryFn: async () => {
39
+ if (client == null) return null
40
+ return await client.thermostats.climateSettingSchedules.get(
41
+ normalizedParams
42
+ )
43
+ },
44
+ })
45
+
46
+ return { ...rest, climateSettingSchedule: data }
47
+ }
@@ -37,6 +37,7 @@ export function useClimateSettingSchedules(
37
37
  for (const schedule of schedules) {
38
38
  queryClient.setQueryData(
39
39
  [
40
+ 'thermostats',
40
41
  'climate_setting_schedules',
41
42
  'get',
42
43
  {
@@ -0,0 +1,48 @@
1
+ import {
2
+ useMutation,
3
+ type UseMutationResult,
4
+ useQueryClient,
5
+ } from '@tanstack/react-query'
6
+ import type {
7
+ ClimateSettingSchedule,
8
+ ClimateSettingScheduleCreateRequest,
9
+ ClimateSettingScheduleCreateResponse,
10
+ SeamError,
11
+ } from 'seamapi'
12
+
13
+ import { NullSeamClientError, useSeamClient } from 'lib/seam/use-seam-client.js'
14
+
15
+ export type UseCreateClimateSettingScheduleData = ClimateSettingSchedule
16
+ export type UseCreateClimateSettingScheduleMutationParams =
17
+ ClimateSettingScheduleCreateRequest
18
+
19
+ export function useCreateClimateSettingSchedule(): UseMutationResult<
20
+ UseCreateClimateSettingScheduleData,
21
+ SeamError,
22
+ UseCreateClimateSettingScheduleMutationParams
23
+ > {
24
+ const { client } = useSeamClient()
25
+ const queryClient = useQueryClient()
26
+
27
+ return useMutation<
28
+ ClimateSettingScheduleCreateResponse['climate_setting_schedule'],
29
+ SeamError,
30
+ ClimateSettingScheduleCreateRequest
31
+ >({
32
+ mutationFn: async (
33
+ mutationParams: UseCreateClimateSettingScheduleMutationParams
34
+ ) => {
35
+ if (client === null) throw new NullSeamClientError()
36
+ return await client.thermostats.climateSettingSchedules.create(
37
+ mutationParams
38
+ )
39
+ },
40
+ onSuccess: () => {
41
+ void queryClient.invalidateQueries([
42
+ 'thermostats',
43
+ 'climate_setting_schedules',
44
+ 'list',
45
+ ])
46
+ },
47
+ })
48
+ }