@seamapi/react 4.3.1 → 4.5.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 (30) hide show
  1. package/README.md +2 -2
  2. package/dist/elements.js +8020 -7762
  3. package/dist/elements.js.map +1 -1
  4. package/lib/seam/components/AccessCodeDetails/AccessCodeDevice.js +26 -7
  5. package/lib/seam/components/AccessCodeDetails/AccessCodeDevice.js.map +1 -1
  6. package/lib/seam/components/DeviceDetails/LockDeviceDetails.js +24 -5
  7. package/lib/seam/components/DeviceDetails/LockDeviceDetails.js.map +1 -1
  8. package/lib/seam/locks/use-toggle-lock.d.ts +5 -2
  9. package/lib/seam/locks/use-toggle-lock.js +5 -1
  10. package/lib/seam/locks/use-toggle-lock.js.map +1 -1
  11. package/lib/ui/Snackbar/Snackbar.d.ts +2 -3
  12. package/lib/ui/thermostat/TemperatureControlGroup.js +3 -3
  13. package/lib/ui/thermostat/TemperatureControlGroup.js.map +1 -1
  14. package/lib/version.d.ts +1 -1
  15. package/lib/version.js +1 -1
  16. package/package.json +4 -4
  17. package/src/lib/seam/components/AccessCodeDetails/AccessCodeDevice.tsx +58 -24
  18. package/src/lib/seam/components/DeviceDetails/LockDeviceDetails.tsx +105 -71
  19. package/src/lib/seam/locks/use-toggle-lock.ts +13 -3
  20. package/src/lib/ui/Snackbar/Snackbar.tsx +2 -2
  21. package/src/lib/ui/thermostat/TemperatureControlGroup.tsx +4 -4
  22. package/src/lib/version.ts +1 -1
  23. package/lib/icons/ThermostatCoolLarge.d.ts +0 -2
  24. package/lib/icons/ThermostatCoolLarge.js +0 -7
  25. package/lib/icons/ThermostatCoolLarge.js.map +0 -1
  26. package/lib/icons/ThermostatHeatLarge.d.ts +0 -2
  27. package/lib/icons/ThermostatHeatLarge.js +0 -5
  28. package/lib/icons/ThermostatHeatLarge.js.map +0 -1
  29. package/src/lib/icons/ThermostatCoolLarge.tsx +0 -39
  30. package/src/lib/icons/ThermostatHeatLarge.tsx +0 -24
@@ -1,4 +1,5 @@
1
1
  import classNames from 'classnames'
2
+ import { useState } from 'react'
2
3
 
3
4
  import { ChevronRightIcon } from 'lib/icons/ChevronRight.js'
4
5
  import { useAccessCodes } from 'lib/seam/access-codes/use-access-codes.js'
@@ -16,6 +17,7 @@ import { DeviceImage } from 'lib/ui/device/DeviceImage.js'
16
17
  import { EditableDeviceName } from 'lib/ui/device/EditableDeviceName.js'
17
18
  import { OnlineStatus } from 'lib/ui/device/OnlineStatus.js'
18
19
  import { ContentHeader } from 'lib/ui/layout/ContentHeader.js'
20
+ import { Snackbar, type SnackbarVariant } from 'lib/ui/Snackbar/Snackbar.js'
19
21
  import { useToggle } from 'lib/ui/use-toggle.js'
20
22
 
21
23
  interface LockDeviceDetailsProps extends NestedSpecificDeviceDetailsProps {
@@ -38,11 +40,25 @@ export function LockDeviceDetails({
38
40
  onEditName,
39
41
  }: LockDeviceDetailsProps): JSX.Element | null {
40
42
  const [accessCodesOpen, toggleAccessCodesOpen] = useToggle()
41
- const toggleLock = useToggleLock()
42
43
  const { accessCodes } = useAccessCodes({
43
44
  device_id: device.device_id,
44
45
  })
45
46
 
47
+ const [snackbarVisible, setSnackbarVisible] = useState(false)
48
+ const [snackbarVariant, setSnackbarVariant] =
49
+ useState<SnackbarVariant>('success')
50
+
51
+ const toggleLock = useToggleLock({
52
+ onSuccess: () => {
53
+ setSnackbarVisible(true)
54
+ setSnackbarVariant('success')
55
+ },
56
+ onError: () => {
57
+ setSnackbarVisible(true)
58
+ setSnackbarVariant('error')
59
+ },
60
+ })
61
+
46
62
  const lockStatus = device.properties.locked ? t.locked : t.unlocked
47
63
  const toggleLockLabel = device.properties.locked ? t.unlock : t.lock
48
64
 
@@ -88,87 +104,103 @@ export function LockDeviceDetails({
88
104
  ]
89
105
 
90
106
  return (
91
- <div className={classNames('seam-device-details', className)}>
92
- <ContentHeader title='Device' onBack={onBack} />
93
- <div className='seam-body'>
94
- <div className='seam-summary'>
95
- <div className='seam-content'>
96
- <div className='seam-image'>
97
- <DeviceImage device={device} />
98
- </div>
99
- <div className='seam-info'>
100
- <span className='seam-label'>{t.device}</span>
101
- <EditableDeviceName
102
- tagName='h4'
103
- value={device.properties.name}
104
- className='seam-device-name'
105
- onEdit={onEditName}
106
- />
107
- <div className='seam-properties'>
108
- <span className='seam-label'>{t.status}:</span>{' '}
109
- <OnlineStatus device={device} />
110
- {device.properties.online && (
111
- <>
112
- <span className='seam-label'>{t.power}:</span>{' '}
113
- <BatteryStatusIndicator device={device} />
114
- </>
115
- )}
116
- <DeviceModel device={device} />
107
+ <>
108
+ <Snackbar
109
+ variant={snackbarVariant}
110
+ visible={snackbarVisible}
111
+ onClose={() => {
112
+ setSnackbarVisible(false)
113
+ }}
114
+ message={
115
+ snackbarVariant === 'success'
116
+ ? t.successfullyUpdated
117
+ : t.failedToUpdate
118
+ }
119
+ autoDismiss
120
+ />
121
+
122
+ <div className={classNames('seam-device-details', className)}>
123
+ <ContentHeader title='Device' onBack={onBack} />
124
+ <div className='seam-body'>
125
+ <div className='seam-summary'>
126
+ <div className='seam-content'>
127
+ <div className='seam-image'>
128
+ <DeviceImage device={device} />
129
+ </div>
130
+ <div className='seam-info'>
131
+ <span className='seam-label'>{t.device}</span>
132
+ <EditableDeviceName
133
+ tagName='h4'
134
+ value={device.properties.name}
135
+ className='seam-device-name'
136
+ onEdit={onEditName}
137
+ />
138
+ <div className='seam-properties'>
139
+ <span className='seam-label'>{t.status}:</span>{' '}
140
+ <OnlineStatus device={device} />
141
+ {device.properties.online && (
142
+ <>
143
+ <span className='seam-label'>{t.power}:</span>{' '}
144
+ <BatteryStatusIndicator device={device} />
145
+ </>
146
+ )}
147
+ <DeviceModel device={device} />
148
+ </div>
117
149
  </div>
118
150
  </div>
151
+ <Alerts alerts={alerts} className='seam-alerts-space-top' />
119
152
  </div>
120
- <Alerts alerts={alerts} className='seam-alerts-space-top' />
121
- </div>
122
- <div className='seam-box'>
123
- <div
124
- className='seam-content seam-access-codes'
125
- onClick={toggleAccessCodesOpen}
126
- >
127
- <span className='seam-value'>
128
- {accessCodeCount} {t.accessCodes}
129
- </span>
130
- <ChevronRightIcon />
153
+ <div className='seam-box'>
154
+ <div
155
+ className='seam-content seam-access-codes'
156
+ onClick={toggleAccessCodesOpen}
157
+ >
158
+ <span className='seam-value'>
159
+ {accessCodeCount} {t.accessCodes}
160
+ </span>
161
+ <ChevronRightIcon />
162
+ </div>
131
163
  </div>
132
- </div>
133
164
 
134
- <div className='seam-box'>
135
- {device.properties.locked && device.properties.online && (
136
- <div className='seam-content seam-lock-status'>
137
- <div>
138
- <span className='seam-label'>{t.lockStatus}</span>
139
- <span className='seam-value'>{lockStatus}</span>
140
- </div>
141
- <div className='seam-right'>
142
- {!disableLockUnlock &&
143
- device.capabilities_supported.includes('lock') && (
144
- <Button
145
- size='small'
146
- onClick={() => {
147
- toggleLock.mutate(device)
148
- }}
149
- >
150
- {toggleLockLabel}
151
- </Button>
152
- )}
165
+ <div className='seam-box'>
166
+ {device.properties.locked && device.properties.online && (
167
+ <div className='seam-content seam-lock-status'>
168
+ <div>
169
+ <span className='seam-label'>{t.lockStatus}</span>
170
+ <span className='seam-value'>{lockStatus}</span>
171
+ </div>
172
+ <div className='seam-right'>
173
+ {!disableLockUnlock &&
174
+ device.capabilities_supported.includes('lock') && (
175
+ <Button
176
+ size='small'
177
+ onClick={() => {
178
+ toggleLock.mutate(device)
179
+ }}
180
+ >
181
+ {toggleLockLabel}
182
+ </Button>
183
+ )}
184
+ </div>
153
185
  </div>
154
- </div>
155
- )}
186
+ )}
156
187
 
157
- <AccessCodeLength
158
- supportedCodeLengths={
159
- device.properties?.supported_code_lengths ?? []
188
+ <AccessCodeLength
189
+ supportedCodeLengths={
190
+ device.properties?.supported_code_lengths ?? []
191
+ }
192
+ />
193
+ </div>
194
+ <DeviceInfo
195
+ device={device}
196
+ disableConnectedAccountInformation={
197
+ disableConnectedAccountInformation
160
198
  }
199
+ disableResourceIds={disableResourceIds}
161
200
  />
162
201
  </div>
163
- <DeviceInfo
164
- device={device}
165
- disableConnectedAccountInformation={
166
- disableConnectedAccountInformation
167
- }
168
- disableResourceIds={disableResourceIds}
169
- />
170
202
  </div>
171
- </div>
203
+ </>
172
204
  )
173
205
  }
174
206
 
@@ -208,4 +240,6 @@ const t = {
208
240
  lockStatus: 'Lock status',
209
241
  status: 'Status',
210
242
  power: 'Power',
243
+ successfullyUpdated: 'Lock status has been successfully updated',
244
+ failedToUpdate: 'Failed to update lock status',
211
245
  }
@@ -12,8 +12,6 @@ import {
12
12
 
13
13
  import { NullSeamClientError, useSeamClient } from 'lib/seam/use-seam-client.js'
14
14
 
15
- export type UseToggleLockParams = never
16
-
17
15
  export type UseToggleLockData = undefined
18
16
 
19
17
  export type UseToggleLockMutationVariables = Pick<Device, 'device_id'> & {
@@ -29,7 +27,14 @@ type MutationError =
29
27
  | SeamActionAttemptFailedError<ToggleLockActionAttempt>
30
28
  | SeamActionAttemptTimeoutError<ToggleLockActionAttempt>
31
29
 
32
- export function useToggleLock(): UseMutationResult<
30
+ interface UseToggleLockParams {
31
+ onError?: () => void
32
+ onSuccess?: () => void
33
+ }
34
+
35
+ export function useToggleLock(
36
+ params: UseToggleLockParams = {}
37
+ ): UseMutationResult<
33
38
  UseToggleLockData,
34
39
  MutationError,
35
40
  UseToggleLockMutationVariables
@@ -92,6 +97,8 @@ export function useToggleLock(): UseMutationResult<
92
97
  )
93
98
  },
94
99
  onError: async (_error, variables) => {
100
+ params.onError?.()
101
+
95
102
  await queryClient.invalidateQueries({
96
103
  queryKey: ['devices', 'list'],
97
104
  })
@@ -99,5 +106,8 @@ export function useToggleLock(): UseMutationResult<
99
106
  queryKey: ['devices', 'get', { device_id: variables.device_id }],
100
107
  })
101
108
  },
109
+ onSuccess() {
110
+ params.onSuccess?.()
111
+ },
102
112
  })
103
113
  }
@@ -5,9 +5,9 @@ import { CheckGreenIcon } from 'lib/icons/CheckGreen.js'
5
5
  import { CloseWhiteIcon } from 'lib/icons/CloseWhite.js'
6
6
  import { ExclamationCircleIcon } from 'lib/icons/ExclamationCircle.js'
7
7
 
8
- type SnackbarVariant = 'success' | 'error'
8
+ export type SnackbarVariant = 'success' | 'error'
9
9
 
10
- interface SnackbarProps {
10
+ export interface SnackbarProps {
11
11
  message: string
12
12
  variant: SnackbarVariant
13
13
  visible: boolean
@@ -1,7 +1,7 @@
1
1
  import { useCallback, useEffect, useMemo } from 'react'
2
2
 
3
- import { ThermostatCoolLargeIcon } from 'lib/icons/ThermostatCoolLarge.js'
4
- import { ThermostatHeatLargeIcon } from 'lib/icons/ThermostatHeatLarge.js'
3
+ import { ThermostatCoolIcon } from 'lib/icons/ThermostatCool.js'
4
+ import { ThermostatHeatIcon } from 'lib/icons/ThermostatHeat.js'
5
5
  import {
6
6
  getCoolBounds,
7
7
  getHeatBounds,
@@ -138,7 +138,7 @@ export function TemperatureControlGroup({
138
138
  <div className='seam-temperature-control-group'>
139
139
  {showHeat && (
140
140
  <div className='seam-temperature-control-group-block'>
141
- <ThermostatHeatLargeIcon className='seam-temperature-control-group-block-thermostat-icon' />
141
+ <ThermostatHeatIcon className='seam-temperature-control-group-block-thermostat-icon' />
142
142
  <TemperatureControl
143
143
  variant='heat'
144
144
  value={heatValue}
@@ -151,7 +151,7 @@ export function TemperatureControlGroup({
151
151
 
152
152
  {showCool && (
153
153
  <div className='seam-temperature-control-group-block'>
154
- <ThermostatCoolLargeIcon className='seam-temperature-control-group-block-thermostat-icon' />
154
+ <ThermostatCoolIcon className='seam-temperature-control-group-block-thermostat-icon' />
155
155
  <TemperatureControl
156
156
  variant='cool'
157
157
  value={coolValue}
@@ -1,3 +1,3 @@
1
- const seamapiReactVersion = '4.3.1'
1
+ const seamapiReactVersion = '4.5.0'
2
2
 
3
3
  export default seamapiReactVersion
@@ -1,2 +0,0 @@
1
- import type { SVGProps } from 'react';
2
- export declare function ThermostatCoolLargeIcon(props: SVGProps<SVGSVGElement>): JSX.Element;
@@ -1,7 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- export function ThermostatCoolLargeIcon(props) {
3
- return (_jsxs("svg", { xmlns: 'http://www.w3.org/2000/svg', width: '1em', height: '1em', fill: 'none', viewBox: '0 0 24 24', ...props, children: [_jsx("mask", { id: 'thermostat-cool-large_svg__a', width: 24, height: 24, x: 0, y: 0, maskUnits: 'userSpaceOnUse', style: {
4
- maskType: 'alpha',
5
- }, children: _jsx("path", { fill: '#D9D9D9', d: 'M0 0h24v24H0z' }) }), _jsx("g", { mask: 'url(#thermostat-cool-large_svg__a)', children: _jsx("path", { fill: '#6B95FF', d: 'M11 22v-4.15l-3.25 3.2-1.4-1.4L11 15v-2H9l-4.65 4.65-1.4-1.4L6.15 13H2v-2h4.15l-3.2-3.25 1.4-1.4L9 11h2V9L6.35 4.35l1.4-1.4L11 6.15V2h2v4.15l3.25-3.2 1.4 1.4L13 9v2h2l4.65-4.65 1.4 1.4-3.2 3.25H22v2h-4.15l3.2 3.25-1.4 1.4L15 13h-2v2l4.65 4.65-1.4 1.4-3.25-3.2V22z' }) })] }));
6
- }
7
- //# sourceMappingURL=ThermostatCoolLarge.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ThermostatCoolLarge.js","sourceRoot":"","sources":["../../src/lib/icons/ThermostatCoolLarge.tsx"],"names":[],"mappings":";AAKA,MAAM,UAAU,uBAAuB,CACrC,KAA8B;IAE9B,OAAO,CACL,eACE,KAAK,EAAC,4BAA4B,EAClC,KAAK,EAAC,KAAK,EACX,MAAM,EAAC,KAAK,EACZ,IAAI,EAAC,MAAM,EACX,OAAO,EAAC,WAAW,KACf,KAAK,aAET,eACE,EAAE,EAAC,8BAA8B,EACjC,KAAK,EAAE,EAAE,EACT,MAAM,EAAE,EAAE,EACV,CAAC,EAAE,CAAC,EACJ,CAAC,EAAE,CAAC,EACJ,SAAS,EAAC,gBAAgB,EAC1B,KAAK,EAAE;oBACL,QAAQ,EAAE,OAAO;iBAClB,YAED,eAAM,IAAI,EAAC,SAAS,EAAC,CAAC,EAAC,eAAe,GAAG,GACpC,EACP,YAAG,IAAI,EAAC,oCAAoC,YAC1C,eACE,IAAI,EAAC,SAAS,EACd,CAAC,EAAC,yQAAyQ,GAC3Q,GACA,IACA,CACP,CAAA;AACH,CAAC"}
@@ -1,2 +0,0 @@
1
- import type { SVGProps } from 'react';
2
- export declare function ThermostatHeatLargeIcon(props: SVGProps<SVGSVGElement>): JSX.Element;
@@ -1,5 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- export function ThermostatHeatLargeIcon(props) {
3
- return (_jsx("svg", { xmlns: 'http://www.w3.org/2000/svg', width: '1em', height: '1em', fill: 'none', viewBox: '0 0 24 24', ...props, children: _jsx("path", { fill: '#FC8E28', d: 'M4 14q0-2.625 1.25-4.675T8 5.875t2.75-2.137L12 3v3.3q0 .925.625 1.463.625.537 1.4.537.425 0 .813-.175t.712-.575L16 7q1.8 1.05 2.9 2.912Q20 11.776 20 14q0 2.2-1.075 4.012a8.1 8.1 0 0 1-2.825 2.863q.425-.6.662-1.312.238-.714.238-1.513a4.8 4.8 0 0 0-.375-1.887 5 5 0 0 0-1.075-1.588L12 11.1l-3.525 3.475a5.1 5.1 0 0 0-1.1 1.6A4.7 4.7 0 0 0 7 18.05q0 .8.237 1.512.238.713.663 1.313a8.1 8.1 0 0 1-2.825-2.863Q4 16.2 4 14m8-.1 2.125 2.075q.425.425.65.95T15 18.05q0 1.225-.875 2.087T12 21t-2.125-.863A2.82 2.82 0 0 1 9 18.05q0-.575.225-1.113.225-.537.65-.962z' }) }));
4
- }
5
- //# sourceMappingURL=ThermostatHeatLarge.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ThermostatHeatLarge.js","sourceRoot":"","sources":["../../src/lib/icons/ThermostatHeatLarge.tsx"],"names":[],"mappings":";AAKA,MAAM,UAAU,uBAAuB,CACrC,KAA8B;IAE9B,OAAO,CACL,cACE,KAAK,EAAC,4BAA4B,EAClC,KAAK,EAAC,KAAK,EACX,MAAM,EAAC,KAAK,EACZ,IAAI,EAAC,MAAM,EACX,OAAO,EAAC,WAAW,KACf,KAAK,YAET,eACE,IAAI,EAAC,SAAS,EACd,CAAC,EAAC,0iBAA0iB,GAC5iB,GACE,CACP,CAAA;AACH,CAAC"}
@@ -1,39 +0,0 @@
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 ThermostatCoolLargeIcon(
7
- props: SVGProps<SVGSVGElement>
8
- ): JSX.Element {
9
- return (
10
- <svg
11
- xmlns='http://www.w3.org/2000/svg'
12
- width='1em'
13
- height='1em'
14
- fill='none'
15
- viewBox='0 0 24 24'
16
- {...props}
17
- >
18
- <mask
19
- id='thermostat-cool-large_svg__a'
20
- width={24}
21
- height={24}
22
- x={0}
23
- y={0}
24
- maskUnits='userSpaceOnUse'
25
- style={{
26
- maskType: 'alpha',
27
- }}
28
- >
29
- <path fill='#D9D9D9' d='M0 0h24v24H0z' />
30
- </mask>
31
- <g mask='url(#thermostat-cool-large_svg__a)'>
32
- <path
33
- fill='#6B95FF'
34
- d='M11 22v-4.15l-3.25 3.2-1.4-1.4L11 15v-2H9l-4.65 4.65-1.4-1.4L6.15 13H2v-2h4.15l-3.2-3.25 1.4-1.4L9 11h2V9L6.35 4.35l1.4-1.4L11 6.15V2h2v4.15l3.25-3.2 1.4 1.4L13 9v2h2l4.65-4.65 1.4 1.4-3.2 3.25H22v2h-4.15l3.2 3.25-1.4 1.4L15 13h-2v2l4.65 4.65-1.4 1.4-3.25-3.2V22z'
35
- />
36
- </g>
37
- </svg>
38
- )
39
- }
@@ -1,24 +0,0 @@
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 ThermostatHeatLargeIcon(
7
- props: SVGProps<SVGSVGElement>
8
- ): JSX.Element {
9
- return (
10
- <svg
11
- xmlns='http://www.w3.org/2000/svg'
12
- width='1em'
13
- height='1em'
14
- fill='none'
15
- viewBox='0 0 24 24'
16
- {...props}
17
- >
18
- <path
19
- fill='#FC8E28'
20
- d='M4 14q0-2.625 1.25-4.675T8 5.875t2.75-2.137L12 3v3.3q0 .925.625 1.463.625.537 1.4.537.425 0 .813-.175t.712-.575L16 7q1.8 1.05 2.9 2.912Q20 11.776 20 14q0 2.2-1.075 4.012a8.1 8.1 0 0 1-2.825 2.863q.425-.6.662-1.312.238-.714.238-1.513a4.8 4.8 0 0 0-.375-1.887 5 5 0 0 0-1.075-1.588L12 11.1l-3.525 3.475a5.1 5.1 0 0 0-1.1 1.6A4.7 4.7 0 0 0 7 18.05q0 .8.237 1.512.238.713.663 1.313a8.1 8.1 0 0 1-2.825-2.863Q4 16.2 4 14m8-.1 2.125 2.075q.425.425.65.95T15 18.05q0 1.225-.875 2.087T12 21t-2.125-.863A2.82 2.82 0 0 1 9 18.05q0-.575.225-1.113.225-.537.65-.962z'
21
- />
22
- </svg>
23
- )
24
- }