@seamapi/react 1.17.0 → 1.18.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.
Files changed (65) hide show
  1. package/README.md +2 -4
  2. package/dist/elements.js +3293 -3204
  3. package/dist/elements.js.map +1 -1
  4. package/lib/seam/components/AccessCodeDetails/AccessCodeDevice.js +11 -7
  5. package/lib/seam/components/AccessCodeDetails/AccessCodeDevice.js.map +1 -1
  6. package/lib/seam/components/AccessCodeTable/AccessCodeTable.js +2 -2
  7. package/lib/seam/components/AccessCodeTable/AccessCodeTable.js.map +1 -1
  8. package/lib/seam/components/DeviceDetails/DeviceDetails.js +6 -69
  9. package/lib/seam/components/DeviceDetails/DeviceDetails.js.map +1 -1
  10. package/lib/seam/components/DeviceDetails/DeviceModel.d.ts +2 -3
  11. package/lib/seam/components/DeviceDetails/DeviceModel.js +1 -11
  12. package/lib/seam/components/DeviceDetails/DeviceModel.js.map +1 -1
  13. package/lib/seam/components/DeviceDetails/LockDeviceDetails.d.ts +7 -0
  14. package/lib/seam/components/DeviceDetails/LockDeviceDetails.js +68 -0
  15. package/lib/seam/components/DeviceDetails/LockDeviceDetails.js.map +1 -0
  16. package/lib/seam/components/DeviceTable/DeviceRow.js +1 -12
  17. package/lib/seam/components/DeviceTable/DeviceRow.js.map +1 -1
  18. package/lib/seam/components/DeviceTable/DeviceTable.js +4 -3
  19. package/lib/seam/components/DeviceTable/DeviceTable.js.map +1 -1
  20. package/lib/seam/device-models/use-device-models.d.ts +1 -1
  21. package/lib/seam/device-models/use-device-models.js +4 -1
  22. package/lib/seam/device-models/use-device-models.js.map +1 -1
  23. package/lib/seam/devices/use-device.d.ts +2 -2
  24. package/lib/seam/devices/use-device.js.map +1 -1
  25. package/lib/seam/devices/use-devices.d.ts +2 -2
  26. package/lib/seam/devices/use-devices.js.map +1 -1
  27. package/lib/seam/devices/use-toggle-lock.d.ts +1 -1
  28. package/lib/seam/devices/use-toggle-lock.js +1 -1
  29. package/lib/seam/devices/use-toggle-lock.js.map +1 -1
  30. package/lib/seam/index.d.ts +0 -1
  31. package/lib/seam/index.js +0 -1
  32. package/lib/seam/index.js.map +1 -1
  33. package/lib/ui/device/BatteryStatus.d.ts +2 -2
  34. package/lib/ui/device/BatteryStatus.js +9 -15
  35. package/lib/ui/device/BatteryStatus.js.map +1 -1
  36. package/lib/ui/device/DeviceImage.d.ts +2 -2
  37. package/lib/ui/device/DeviceImage.js.map +1 -1
  38. package/lib/ui/device/LockStatus.d.ts +3 -3
  39. package/lib/ui/device/LockStatus.js +4 -0
  40. package/lib/ui/device/LockStatus.js.map +1 -1
  41. package/lib/ui/device/OnlineStatus.d.ts +2 -2
  42. package/lib/version.d.ts +1 -1
  43. package/lib/version.js +1 -1
  44. package/package.json +3 -3
  45. package/src/lib/seam/components/AccessCodeDetails/AccessCodeDevice.tsx +13 -8
  46. package/src/lib/seam/components/AccessCodeTable/AccessCodeTable.tsx +2 -2
  47. package/src/lib/seam/components/DeviceDetails/DeviceDetails.tsx +7 -153
  48. package/src/lib/seam/components/DeviceDetails/DeviceModel.tsx +5 -19
  49. package/src/lib/seam/components/DeviceDetails/LockDeviceDetails.tsx +158 -0
  50. package/src/lib/seam/components/DeviceTable/DeviceRow.tsx +3 -15
  51. package/src/lib/seam/components/DeviceTable/DeviceTable.tsx +4 -3
  52. package/src/lib/seam/device-models/use-device-models.ts +8 -2
  53. package/src/lib/seam/devices/use-device.ts +2 -3
  54. package/src/lib/seam/devices/use-devices.ts +2 -3
  55. package/src/lib/seam/devices/use-toggle-lock.ts +7 -8
  56. package/src/lib/seam/index.ts +0 -1
  57. package/src/lib/ui/device/BatteryStatus.tsx +19 -29
  58. package/src/lib/ui/device/DeviceImage.tsx +4 -2
  59. package/src/lib/ui/device/LockStatus.tsx +7 -3
  60. package/src/lib/ui/device/OnlineStatus.tsx +2 -2
  61. package/src/lib/version.ts +1 -1
  62. package/lib/seam/devices/types.d.ts +0 -2
  63. package/lib/seam/devices/types.js +0 -2
  64. package/lib/seam/devices/types.js.map +0 -1
  65. package/src/lib/seam/devices/types.ts +0 -5
@@ -1,5 +1,5 @@
1
1
  import type { HTMLAttributes } from 'react';
2
- import type { LockDevice } from 'seamapi';
2
+ import type { CommonDevice } from 'seamapi';
3
3
  export declare function DeviceImage(props: {
4
- device: LockDevice;
4
+ device: CommonDevice;
5
5
  } & HTMLAttributes<HTMLImageElement>): JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"DeviceImage.js","sourceRoot":"","sources":["../../../src/lib/ui/device/DeviceImage.tsx"],"names":[],"mappings":";AAGA,MAAM,UAAU,WAAW,CACzB,KAAgE;IAEhE,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,EAAE,GAAG,KAAK,CAAA;IAEvC,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,SAAS,IAAI,gBAAgB,CAAA;IAE3D,OAAO,cAAK,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC,IAAI,KAAM,UAAU,GAAI,CAAA;AACvE,CAAC;AAED,MAAM,gBAAgB,GACpB,oEAAoE,CAAA"}
1
+ {"version":3,"file":"DeviceImage.js","sourceRoot":"","sources":["../../../src/lib/ui/device/DeviceImage.tsx"],"names":[],"mappings":";AAGA,MAAM,UAAU,WAAW,CACzB,KAEoC;IAEpC,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,EAAE,GAAG,KAAK,CAAA;IAEvC,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,SAAS,IAAI,gBAAgB,CAAA;IAE3D,OAAO,cAAK,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC,IAAI,KAAM,UAAU,GAAI,CAAA;AACvE,CAAC;AAED,MAAM,gBAAgB,GACpB,oEAAoE,CAAA"}
@@ -1,7 +1,7 @@
1
1
  /// <reference types="react" />
2
- import type { LockDevice } from 'seamapi';
2
+ import { type CommonDevice } from 'seamapi';
3
3
  interface LockStatusProps {
4
- device: LockDevice;
4
+ device: CommonDevice;
5
5
  }
6
- export declare function LockStatus(props: LockStatusProps): JSX.Element;
6
+ export declare function LockStatus(props: LockStatusProps): JSX.Element | null;
7
7
  export {};
@@ -1,7 +1,11 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { isLockDevice } from 'seamapi';
2
3
  import { LockLockedIcon } from '../../../lib/icons/LockLocked.js';
3
4
  import { LockUnlockedIcon } from '../../../lib/icons/LockUnlocked.js';
4
5
  export function LockStatus(props) {
6
+ if (!isLockDevice(props.device)) {
7
+ return null;
8
+ }
5
9
  const { device: { properties: { locked }, }, } = props;
6
10
  return (_jsx("div", { className: 'seam-lock-status', children: _jsx(Content, { isLocked: locked }) }));
7
11
  }
@@ -1 +1 @@
1
- {"version":3,"file":"LockStatus.js","sourceRoot":"","sources":["../../../src/lib/ui/device/LockStatus.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAM5D,MAAM,UAAU,UAAU,CAAC,KAAsB;IAC/C,MAAM,EACJ,MAAM,EAAE,EACN,UAAU,EAAE,EAAE,MAAM,EAAE,GACvB,GACF,GAAG,KAAK,CAAA;IAET,OAAO,CACL,cAAK,SAAS,EAAC,kBAAkB,YAC/B,KAAC,OAAO,IAAC,QAAQ,EAAE,MAAM,GAAI,GACzB,CACP,CAAA;AACH,CAAC;AAED,SAAS,OAAO,CAAC,KAA4B;IAC3C,MAAM,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAA;IAC1B,IAAI,QAAQ,EAAE;QACZ,OAAO,CACL,8BACE,KAAC,cAAc,IAAC,SAAS,EAAC,gBAAgB,GAAG,EAC7C,eAAM,SAAS,EAAC,kBAAkB,YAAE,CAAC,CAAC,MAAM,GAAQ,IACnD,CACJ,CAAA;KACF;IAED,OAAO,CACL,8BACE,KAAC,gBAAgB,IAAC,SAAS,EAAC,gBAAgB,GAAG,EAC/C,eAAM,SAAS,EAAC,kBAAkB,YAAE,CAAC,CAAC,QAAQ,GAAQ,IACrD,CACJ,CAAA;AACH,CAAC;AAED,MAAM,CAAC,GAAG;IACR,MAAM,EAAE,QAAQ;IAChB,QAAQ,EAAE,UAAU;CACrB,CAAA"}
1
+ {"version":3,"file":"LockStatus.js","sourceRoot":"","sources":["../../../src/lib/ui/device/LockStatus.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAqB,YAAY,EAAE,MAAM,SAAS,CAAA;AAEzD,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAM5D,MAAM,UAAU,UAAU,CAAC,KAAsB;IAC/C,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE;QAC/B,OAAO,IAAI,CAAA;KACZ;IAED,MAAM,EACJ,MAAM,EAAE,EACN,UAAU,EAAE,EAAE,MAAM,EAAE,GACvB,GACF,GAAG,KAAK,CAAA;IAET,OAAO,CACL,cAAK,SAAS,EAAC,kBAAkB,YAC/B,KAAC,OAAO,IAAC,QAAQ,EAAE,MAAM,GAAI,GACzB,CACP,CAAA;AACH,CAAC;AAED,SAAS,OAAO,CAAC,KAA4B;IAC3C,MAAM,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAA;IAC1B,IAAI,QAAQ,EAAE;QACZ,OAAO,CACL,8BACE,KAAC,cAAc,IAAC,SAAS,EAAC,gBAAgB,GAAG,EAC7C,eAAM,SAAS,EAAC,kBAAkB,YAAE,CAAC,CAAC,MAAM,GAAQ,IACnD,CACJ,CAAA;KACF;IAED,OAAO,CACL,8BACE,KAAC,gBAAgB,IAAC,SAAS,EAAC,gBAAgB,GAAG,EAC/C,eAAM,SAAS,EAAC,kBAAkB,YAAE,CAAC,CAAC,QAAQ,GAAQ,IACrD,CACJ,CAAA;AACH,CAAC;AAED,MAAM,CAAC,GAAG;IACR,MAAM,EAAE,QAAQ;IAChB,QAAQ,EAAE,UAAU;CACrB,CAAA"}
@@ -1,7 +1,7 @@
1
1
  /// <reference types="react" />
2
- import type { LockDevice } from 'seamapi';
2
+ import type { CommonDevice } from 'seamapi';
3
3
  interface OnlineStatusProps {
4
- device: LockDevice;
4
+ device: CommonDevice;
5
5
  }
6
6
  export declare function OnlineStatus(props: OnlineStatusProps): JSX.Element;
7
7
  export {};
package/lib/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- declare const seamapiReactVersion = "1.17.0";
1
+ declare const seamapiReactVersion = "1.18.1";
2
2
  export default seamapiReactVersion;
package/lib/version.js CHANGED
@@ -1,3 +1,3 @@
1
- const seamapiReactVersion = '1.17.0';
1
+ const seamapiReactVersion = '1.18.1';
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.17.0",
3
+ "version": "1.18.1",
4
4
  "description": "Seam Components.",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -110,7 +110,7 @@
110
110
  "@tanstack/react-query": "^4.28.0",
111
111
  "classnames": "^2.3.2",
112
112
  "luxon": "^3.3.0",
113
- "seamapi": "^6.3.0",
113
+ "seamapi": "^6.12.1",
114
114
  "uuid": "^9.0.0"
115
115
  },
116
116
  "devDependencies": {
@@ -121,7 +121,7 @@
121
121
  "@mui/icons-material": "^5.11.16",
122
122
  "@mui/material": "^5.12.2",
123
123
  "@r2wc/react-to-web-component": "^2.0.2",
124
- "@seamapi/fake-seam-connect": "^0.7.2",
124
+ "@seamapi/fake-seam-connect": "^0.8.0",
125
125
  "@storybook/addon-essentials": "^7.0.2",
126
126
  "@storybook/addon-interactions": "^7.0.2",
127
127
  "@storybook/addon-links": "^7.0.2",
@@ -1,7 +1,5 @@
1
- import type { LockDevice } from 'seamapi'
1
+ import { isLockDevice, type LockDevice } from 'seamapi'
2
2
 
3
- import { getDeviceModel } from 'lib/seam/components/DeviceDetails/DeviceModel.js'
4
- import { isLockDevice } from 'lib/seam/devices/types.js'
5
3
  import { useDevice } from 'lib/seam/devices/use-device.js'
6
4
  import { useToggleLock } from 'lib/seam/devices/use-toggle-lock.js'
7
5
  import { Button } from 'lib/ui/Button.js'
@@ -17,20 +15,27 @@ export function AccessCodeDevice({
17
15
  }): JSX.Element | null {
18
16
  const { isLoading, device } = useDevice({ device_id: deviceId })
19
17
 
20
- if (isLoading || device == null || !isLockDevice(device)) {
18
+ if (isLoading) {
21
19
  return null
22
20
  }
23
21
 
24
- return <LockDeviceDetails device={device} onSelectDevice={onSelectDevice} />
22
+ if (device == null) {
23
+ return null
24
+ }
25
+
26
+ if (!isLockDevice(device)) {
27
+ return null
28
+ }
29
+
30
+ return <Content device={device} onSelectDevice={onSelectDevice} />
25
31
  }
26
32
 
27
- function LockDeviceDetails(props: {
33
+ function Content(props: {
28
34
  device: LockDevice
29
35
  onSelectDevice: (deviceId: string) => void
30
36
  }): JSX.Element {
31
37
  const { device, onSelectDevice } = props
32
38
  const toggleLock = useToggleLock(device)
33
- const model = getDeviceModel(device)
34
39
 
35
40
  const toggleLockLabel = device.properties.locked ? t.unlock : t.lock
36
41
 
@@ -40,7 +45,7 @@ function LockDeviceDetails(props: {
40
45
  <DeviceImage device={device} />
41
46
  </div>
42
47
  <div className='seam-body'>
43
- <div className='seam-model'>{model}</div>
48
+ <div className='seam-model'>{device.properties.model.display_name}</div>
44
49
  <TextButton
45
50
  onClick={() => {
46
51
  onSelectDevice(device.device_id)
@@ -118,7 +118,7 @@ export function AccessCodeTable({
118
118
  />
119
119
  </TableHeader>
120
120
  <TableBody>
121
- <Body
121
+ <Content
122
122
  accessCodes={filteredAccessCodes}
123
123
  onAccessCodeClick={handleAccessCodeClick}
124
124
  />
@@ -127,7 +127,7 @@ export function AccessCodeTable({
127
127
  )
128
128
  }
129
129
 
130
- function Body(props: {
130
+ function Content(props: {
131
131
  accessCodes: Array<UseAccessCodesData[number]>
132
132
  onAccessCodeClick: (accessCodeId: string) => void
133
133
  }): JSX.Element {
@@ -1,20 +1,7 @@
1
- import classNames from 'classnames'
2
- import type { LockDevice } from 'seamapi'
1
+ import { isLockDevice } from 'seamapi'
3
2
 
4
- import { ChevronRightIcon } from 'lib/icons/ChevronRight.js'
5
- import { useAccessCodes } from 'lib/seam/access-codes/use-access-codes.js'
6
- import { AccessCodeTable } from 'lib/seam/components/AccessCodeTable/AccessCodeTable.js'
7
- import { DeviceModel } from 'lib/seam/components/DeviceDetails/DeviceModel.js'
8
- import { isLockDevice } from 'lib/seam/devices/types.js'
3
+ import { LockDeviceDetails } from 'lib/seam/components/DeviceDetails/LockDeviceDetails.js'
9
4
  import { useDevice } from 'lib/seam/devices/use-device.js'
10
- import { useToggleLock } from 'lib/seam/devices/use-toggle-lock.js'
11
- import { Alerts } from 'lib/ui/Alert/Alerts.js'
12
- import { Button } from 'lib/ui/Button.js'
13
- import { BatteryStatus } from 'lib/ui/device/BatteryStatus.js'
14
- import { DeviceImage } from 'lib/ui/device/DeviceImage.js'
15
- import { OnlineStatus } from 'lib/ui/device/OnlineStatus.js'
16
- import { ContentHeader } from 'lib/ui/layout/ContentHeader.js'
17
- import { useToggle } from 'lib/ui/use-toggle.js'
18
5
 
19
6
  export interface DeviceDetailsProps {
20
7
  deviceId: string
@@ -35,148 +22,15 @@ export function DeviceDetails({
35
22
  return null
36
23
  }
37
24
 
38
- if (!isLockDevice(device)) {
39
- return null
40
- }
41
-
42
- return (
43
- <LockDeviceDetails className={className} device={device} onBack={onBack} />
44
- )
45
- }
46
-
47
- function LockDeviceDetails(props: {
48
- device: LockDevice
49
- onBack?: () => void
50
- className?: string
51
- }): JSX.Element | null {
52
- const { device, onBack, className } = props
53
-
54
- const [accessCodesOpen, toggleAccessCodesOpen] = useToggle()
55
- const toggleLock = useToggleLock(device)
56
- const { accessCodes } = useAccessCodes({
57
- device_id: device.device_id,
58
- })
59
-
60
- const lockStatus = device.properties.locked ? t.locked : t.unlocked
61
- const toggleLockLabel = device.properties.locked ? t.unlock : t.lock
62
-
63
- const accessCodeCount = accessCodes?.length
64
-
65
- const accessCodeLength =
66
- device.properties?.schlage_metadata?.access_code_length
67
-
68
- if (accessCodes == null) {
69
- return null
70
- }
71
-
72
- if (accessCodesOpen) {
25
+ if (isLockDevice(device)) {
73
26
  return (
74
- <AccessCodeTable
27
+ <LockDeviceDetails
75
28
  className={className}
76
- deviceId={device.device_id}
77
- onBack={toggleAccessCodesOpen}
29
+ device={device}
30
+ onBack={onBack}
78
31
  />
79
32
  )
80
33
  }
81
34
 
82
- const alerts = [
83
- ...device.errors.map((error) => ({
84
- variant: 'error' as const,
85
- message: error.message,
86
- })),
87
- ...device.warnings.map((warning) => ({
88
- variant: 'warning' as const,
89
- message: warning.message,
90
- })),
91
- ]
92
-
93
- return (
94
- <div className={classNames('seam-device-details', className)}>
95
- <ContentHeader title='Device' onBack={onBack} />
96
- <div className='seam-body'>
97
- <div className='seam-summary'>
98
- <div className='seam-content'>
99
- <div className='seam-image'>
100
- <DeviceImage device={device} />
101
- </div>
102
- <div className='seam-info'>
103
- <span className='seam-label'>{t.device}</span>
104
- <h4 className='seam-device-name'>{device.properties.name}</h4>
105
- <div className='seam-properties'>
106
- <span className='seam-label'>{t.status}:</span>{' '}
107
- <OnlineStatus device={device} />
108
- <span className='seam-label'>{t.power}:</span>{' '}
109
- <BatteryStatus device={device} />
110
- <DeviceModel device={device} />
111
- </div>
112
- </div>
113
- </div>
114
- <Alerts alerts={alerts} className='seam-alerts-space-top' />
115
- </div>
116
- <div className='seam-box'>
117
- <div
118
- className='seam-content seam-access-codes'
119
- onClick={toggleAccessCodesOpen}
120
- >
121
- <span className='seam-value'>
122
- {accessCodeCount} {t.accessCodes}
123
- </span>
124
- <ChevronRightIcon />
125
- </div>
126
- </div>
127
-
128
- <div className='seam-box'>
129
- <div className='seam-content seam-lock-status'>
130
- <div>
131
- <span className='seam-label'>{t.lockStatus}</span>
132
- <span className='seam-value'>{lockStatus}</span>
133
- </div>
134
- <div className='seam-right'>
135
- <Button
136
- size='small'
137
- onClick={() => {
138
- toggleLock.mutate()
139
- }}
140
- >
141
- {toggleLockLabel}
142
- </Button>
143
- </div>
144
- </div>
145
- <AccessCodeLength accessCodeLength={accessCodeLength} />
146
- </div>
147
- </div>
148
- </div>
149
- )
150
- }
151
-
152
- function AccessCodeLength(props: {
153
- accessCodeLength: number | null | undefined
154
- }): JSX.Element | null {
155
- const { accessCodeLength } = props
156
- if (accessCodeLength == null) {
157
- return null
158
- }
159
-
160
- return (
161
- <div className='seam-content seam-access-code-length'>
162
- <span className='seam-label'>{t.codeLength}</span>
163
- <span className='seam-value'>
164
- {accessCodeLength} {t.digits}
165
- </span>
166
- </div>
167
- )
168
- }
169
-
170
- const t = {
171
- device: 'Device',
172
- unlock: 'Unlock',
173
- lock: 'Lock',
174
- locked: 'Locked',
175
- unlocked: 'Unlocked',
176
- accessCodes: 'access codes',
177
- codeLength: 'Code length',
178
- digits: 'digits',
179
- lockStatus: 'Lock status',
180
- status: 'Status',
181
- power: 'Power',
35
+ return null
182
36
  }
@@ -1,34 +1,20 @@
1
- import type { LockDevice } from 'seamapi'
1
+ import type { CommonDevice } from 'seamapi'
2
2
 
3
3
  interface DeviceModelProps {
4
- device: LockDevice
4
+ device: CommonDevice
5
5
  }
6
6
 
7
7
  export function DeviceModel({ device }: DeviceModelProps): JSX.Element | null {
8
- const model = getDeviceModel(device)
9
- if (model == null) {
10
- return null
11
- }
12
-
13
8
  return (
14
9
  <>
15
10
  <span className='seam-label'>{t.model}:</span>{' '}
16
- <div className='seam-device-model'>{model}</div>
11
+ <div className='seam-device-model'>
12
+ {device.properties.model.display_name}
13
+ </div>
17
14
  </>
18
15
  )
19
16
  }
20
17
 
21
- export const getDeviceModel = ({
22
- properties,
23
- }: LockDevice): string | undefined => {
24
- return (
25
- properties?.august_metadata?.model ??
26
- properties?.schlage_metadata?.model ??
27
- t.fallbackModel
28
- )
29
- }
30
-
31
18
  const t = {
32
19
  model: 'Model',
33
- fallbackModel: 'Unknown Lock',
34
20
  }
@@ -0,0 +1,158 @@
1
+ import classNames from 'classnames'
2
+ import type { LockDevice } from 'seamapi'
3
+
4
+ import { ChevronRightIcon } from 'lib/icons/ChevronRight.js'
5
+ import { useAccessCodes } from 'lib/seam/access-codes/use-access-codes.js'
6
+ import { AccessCodeTable } from 'lib/seam/components/AccessCodeTable/AccessCodeTable.js'
7
+ import { DeviceModel } from 'lib/seam/components/DeviceDetails/DeviceModel.js'
8
+ import { useToggleLock } from 'lib/seam/devices/use-toggle-lock.js'
9
+ import { Alerts } from 'lib/ui/Alert/Alerts.js'
10
+ import { Button } from 'lib/ui/Button.js'
11
+ import { BatteryStatus } from 'lib/ui/device/BatteryStatus.js'
12
+ import { DeviceImage } from 'lib/ui/device/DeviceImage.js'
13
+ import { OnlineStatus } from 'lib/ui/device/OnlineStatus.js'
14
+ import { ContentHeader } from 'lib/ui/layout/ContentHeader.js'
15
+ import { useToggle } from 'lib/ui/use-toggle.js'
16
+ export function LockDeviceDetails(props: {
17
+ device: LockDevice
18
+ onBack?: () => void
19
+ className?: string
20
+ }): JSX.Element | null {
21
+ const { device, onBack, className } = props
22
+
23
+ const [accessCodesOpen, toggleAccessCodesOpen] = useToggle()
24
+ const toggleLock = useToggleLock(device)
25
+ const { accessCodes } = useAccessCodes({
26
+ device_id: device.device_id,
27
+ })
28
+
29
+ const lockStatus = device.properties.locked ? t.locked : t.unlocked
30
+ const toggleLockLabel = device.properties.locked ? t.unlock : t.lock
31
+
32
+ const accessCodeCount = accessCodes?.length
33
+
34
+ if (accessCodes == null) {
35
+ return null
36
+ }
37
+
38
+ if (accessCodesOpen) {
39
+ return (
40
+ <AccessCodeTable
41
+ className={className}
42
+ deviceId={device.device_id}
43
+ onBack={toggleAccessCodesOpen}
44
+ />
45
+ )
46
+ }
47
+
48
+ const alerts = [
49
+ ...device.errors.map((error) => ({
50
+ variant: 'error' as const,
51
+ message: error.message,
52
+ })),
53
+ ...device.warnings.map((warning) => ({
54
+ variant: 'warning' as const,
55
+ message: warning.message,
56
+ })),
57
+ ]
58
+
59
+ return (
60
+ <div className={classNames('seam-device-details', className)}>
61
+ <ContentHeader title='Device' onBack={onBack} />
62
+ <div className='seam-body'>
63
+ <div className='seam-summary'>
64
+ <div className='seam-content'>
65
+ <div className='seam-image'>
66
+ <DeviceImage device={device} />
67
+ </div>
68
+ <div className='seam-info'>
69
+ <span className='seam-label'>{t.device}</span>
70
+ <h4 className='seam-device-name'>{device.properties.name}</h4>
71
+ <div className='seam-properties'>
72
+ <span className='seam-label'>{t.status}:</span>{' '}
73
+ <OnlineStatus device={device} />
74
+ <span className='seam-label'>{t.power}:</span>{' '}
75
+ <BatteryStatus device={device} />
76
+ <DeviceModel device={device} />
77
+ </div>
78
+ </div>
79
+ </div>
80
+ <Alerts alerts={alerts} className='seam-alerts-space-top' />
81
+ </div>
82
+ <div className='seam-box'>
83
+ <div
84
+ className='seam-content seam-access-codes'
85
+ onClick={toggleAccessCodesOpen}
86
+ >
87
+ <span className='seam-value'>
88
+ {accessCodeCount} {t.accessCodes}
89
+ </span>
90
+ <ChevronRightIcon />
91
+ </div>
92
+ </div>
93
+
94
+ <div className='seam-box'>
95
+ <div className='seam-content seam-lock-status'>
96
+ <div>
97
+ <span className='seam-label'>{t.lockStatus}</span>
98
+ <span className='seam-value'>{lockStatus}</span>
99
+ </div>
100
+ <div className='seam-right'>
101
+ <Button
102
+ size='small'
103
+ onClick={() => {
104
+ toggleLock.mutate()
105
+ }}
106
+ >
107
+ {toggleLockLabel}
108
+ </Button>
109
+ </div>
110
+ </div>
111
+ <AccessCodeLength
112
+ supportedCodeLengths={
113
+ device.properties?.supported_code_lengths ?? []
114
+ }
115
+ />
116
+ </div>
117
+ </div>
118
+ </div>
119
+ )
120
+ }
121
+
122
+ function AccessCodeLength(props: {
123
+ supportedCodeLengths: number[]
124
+ }): JSX.Element | null {
125
+ const { supportedCodeLengths } = props
126
+
127
+ if (supportedCodeLengths.length === 0) {
128
+ return null
129
+ }
130
+
131
+ const min = Math.min(...supportedCodeLengths)
132
+ const max = Math.max(...supportedCodeLengths)
133
+
134
+ const range = min === max ? max : `${min}–${max}`
135
+
136
+ return (
137
+ <div className='seam-content seam-access-code-length'>
138
+ <span className='seam-label'>{t.codeLength}</span>
139
+ <span className='seam-value'>
140
+ {range} {t.digits}
141
+ </span>
142
+ </div>
143
+ )
144
+ }
145
+
146
+ const t = {
147
+ device: 'Device',
148
+ unlock: 'Unlock',
149
+ lock: 'Lock',
150
+ locked: 'Locked',
151
+ unlocked: 'Unlocked',
152
+ accessCodes: 'access codes',
153
+ codeLength: 'Code length',
154
+ digits: 'digits',
155
+ lockStatus: 'Lock status',
156
+ status: 'Status',
157
+ power: 'Power',
158
+ }
@@ -1,5 +1,3 @@
1
- import { getDeviceModel } from 'lib/seam/components/DeviceDetails/DeviceModel.js'
2
- import { isLockDevice } from 'lib/seam/devices/types.js'
3
1
  import type {
4
2
  UseDevicesData,
5
3
  UseDevicesParams,
@@ -27,12 +25,6 @@ export function DeviceRow({
27
25
  device,
28
26
  onClick,
29
27
  }: DeviceRowProps): JSX.Element | null {
30
- if (!isLockDevice(device)) {
31
- return null
32
- }
33
-
34
- const deviceModel = getDeviceModel(device) ?? t.unknownLock
35
-
36
28
  return (
37
29
  <TableRow key={device.device_id} onClick={onClick}>
38
30
  <TableCell className='seam-image-cell'>
@@ -41,7 +33,9 @@ export function DeviceRow({
41
33
  <TableCell className='seam-body-cell'>
42
34
  <Title className='seam-truncated-text'>{device.properties.name}</Title>
43
35
  <div className='seam-bottom'>
44
- <span className='seam-device-model'>{deviceModel}</span>
36
+ <span className='seam-device-model'>
37
+ {device.properties.model.display_name}
38
+ </span>
45
39
  <div className='seam-device-statuses'>
46
40
  <OnlineStatus device={device} />
47
41
  <BatteryStatus device={device} />
@@ -52,9 +46,3 @@ export function DeviceRow({
52
46
  </TableRow>
53
47
  )
54
48
  }
55
-
56
- const t = {
57
- devices: 'Devices',
58
- unknownLock: 'Unknown Lock',
59
- noDevicesMessage: 'Sorry, no devices were found',
60
- }
@@ -1,5 +1,6 @@
1
1
  import classNames from 'classnames'
2
2
  import { useCallback, useMemo, useState } from 'react'
3
+ import { isLockDevice } from 'seamapi'
3
4
 
4
5
  import { compareByCreatedAtDesc } from 'lib/dates.js'
5
6
  import { DeviceDetails } from 'lib/seam/components/DeviceDetails/DeviceDetails.js'
@@ -60,6 +61,7 @@ export function DeviceTable({
60
61
  const filteredDevices = useMemo(
61
62
  () =>
62
63
  devices
64
+ ?.filter(isLockDevice)
63
65
  ?.filter((device) => deviceFilter(device, searchInputValue))
64
66
  ?.sort(deviceComparator) ?? [],
65
67
  [devices, searchInputValue, deviceFilter, deviceComparator]
@@ -108,13 +110,13 @@ export function DeviceTable({
108
110
  />
109
111
  </TableHeader>
110
112
  <TableBody>
111
- <Body devices={filteredDevices} onDeviceClick={handleDeviceClick} />
113
+ <Content devices={filteredDevices} onDeviceClick={handleDeviceClick} />
112
114
  </TableBody>
113
115
  </div>
114
116
  )
115
117
  }
116
118
 
117
- function Body(props: {
119
+ function Content(props: {
118
120
  devices: Array<UseDevicesData[number]>
119
121
  onDeviceClick: (deviceId: string) => void
120
122
  }): JSX.Element {
@@ -159,6 +161,5 @@ function Body(props: {
159
161
 
160
162
  const t = {
161
163
  devices: 'Devices',
162
- unknownLock: 'Unknown Lock',
163
164
  noDevicesMessage: 'Sorry, no devices were found',
164
165
  }
@@ -13,7 +13,10 @@ export type UseDeviceModelsParams = DeviceModelsListRequest
13
13
  export type UseDeviceModelsData = DeviceModel[]
14
14
 
15
15
  export function useDeviceModels(
16
- params?: UseDeviceModelsParams
16
+ params?: Omit<
17
+ UseDeviceModelsParams,
18
+ 'acknowledge_intentional_use_of_internal_api'
19
+ >
17
20
  ): UseSeamQueryResult<'deviceModels', UseDeviceModelsData> {
18
21
  const { client } = useSeamClient()
19
22
 
@@ -25,7 +28,10 @@ export function useDeviceModels(
25
28
  queryKey: ['device_models', 'list', params],
26
29
  queryFn: async () => {
27
30
  if (client == null) return []
28
- const deviceModels = await client?.deviceModels.list(params)
31
+ const deviceModels = await client?.deviceModels.list({
32
+ ...params,
33
+ acknowledge_intentional_use_of_internal_api: true,
34
+ })
29
35
  return deviceModels
30
36
  },
31
37
  })
@@ -1,7 +1,6 @@
1
1
  import { useQuery } from '@tanstack/react-query'
2
2
  import type {
3
- CommonDeviceProperties,
4
- Device,
3
+ CommonDevice,
5
4
  DeviceGetRequest,
6
5
  DeviceGetResponse,
7
6
  SeamError,
@@ -11,7 +10,7 @@ import { useSeamClient } from 'lib/seam/use-seam-client.js'
11
10
  import type { UseSeamQueryResult } from 'lib/seam/use-seam-query-result.js'
12
11
 
13
12
  export type UseDeviceParams = DeviceGetRequest | string
14
- export type UseDeviceData = Device<CommonDeviceProperties> | null
13
+ export type UseDeviceData = CommonDevice | null
15
14
 
16
15
  export function useDevice(
17
16
  params: DeviceGetRequest