@seamapi/react 0.9.1 → 0.11.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 (224) hide show
  1. package/index.css +243 -105
  2. package/index.css.map +1 -1
  3. package/index.min.css +1 -1
  4. package/index.min.css.map +1 -1
  5. package/lib/{provider.d.ts → SeamProvider.d.ts} +3 -3
  6. package/lib/{provider.js → SeamProvider.js} +9 -2
  7. package/lib/SeamProvider.js.map +1 -0
  8. package/lib/icons/AccessCodeKey.d.ts +2 -0
  9. package/lib/icons/AccessCodeKey.js +3 -0
  10. package/lib/icons/AccessCodeKey.js.map +1 -0
  11. package/lib/icons/ArrowBack.d.ts +2 -0
  12. package/lib/icons/ArrowBack.js +5 -0
  13. package/lib/icons/ArrowBack.js.map +1 -0
  14. package/lib/icons/BatteryLevelCritical.d.ts +2 -0
  15. package/lib/icons/BatteryLevelCritical.js +3 -0
  16. package/lib/icons/BatteryLevelCritical.js.map +1 -0
  17. package/lib/icons/BatteryLevelFull.d.ts +2 -0
  18. package/lib/icons/BatteryLevelFull.js +3 -0
  19. package/lib/icons/BatteryLevelFull.js.map +1 -0
  20. package/lib/icons/BatteryLevelHigh.d.ts +2 -0
  21. package/lib/icons/BatteryLevelHigh.js +3 -0
  22. package/lib/icons/BatteryLevelHigh.js.map +1 -0
  23. package/lib/icons/BatteryLevelLow.d.ts +2 -0
  24. package/lib/icons/BatteryLevelLow.js +3 -0
  25. package/lib/icons/BatteryLevelLow.js.map +1 -0
  26. package/lib/icons/BatteryLevelWired.d.ts +2 -0
  27. package/lib/icons/BatteryLevelWired.js +5 -0
  28. package/lib/icons/BatteryLevelWired.js.map +1 -0
  29. package/lib/icons/ChevronRight.d.ts +2 -0
  30. package/lib/icons/ChevronRight.js +5 -0
  31. package/lib/icons/ChevronRight.js.map +1 -0
  32. package/lib/icons/DotsEllipsisMore.d.ts +2 -0
  33. package/lib/icons/DotsEllipsisMore.js +5 -0
  34. package/lib/icons/DotsEllipsisMore.js.map +1 -0
  35. package/lib/icons/OnlineStatusAccountOffline.d.ts +2 -0
  36. package/lib/icons/OnlineStatusAccountOffline.js +5 -0
  37. package/lib/icons/OnlineStatusAccountOffline.js.map +1 -0
  38. package/lib/icons/OnlineStatusDeviceOffline.d.ts +2 -0
  39. package/lib/icons/OnlineStatusDeviceOffline.js +3 -0
  40. package/lib/icons/OnlineStatusDeviceOffline.js.map +1 -0
  41. package/lib/icons/OnlineStatusOnline.d.ts +2 -0
  42. package/lib/icons/OnlineStatusOnline.js +3 -0
  43. package/lib/icons/OnlineStatusOnline.js.map +1 -0
  44. package/lib/icons/index.d.ts +12 -0
  45. package/lib/icons/index.js +12 -0
  46. package/lib/icons/index.js.map +1 -1
  47. package/lib/index.d.ts +3 -3
  48. package/lib/index.js +3 -3
  49. package/lib/index.js.map +1 -1
  50. package/lib/seam/devices/index.d.ts +1 -0
  51. package/lib/seam/devices/index.js +2 -0
  52. package/lib/seam/devices/index.js.map +1 -0
  53. package/lib/{hooks → seam/devices}/use-devices.js +3 -3
  54. package/lib/seam/devices/use-devices.js.map +1 -0
  55. package/lib/seam/index.d.ts +2 -0
  56. package/lib/seam/index.js +3 -0
  57. package/lib/seam/index.js.map +1 -0
  58. package/lib/{hooks/use-seam.d.ts → seam/use-seam-client.d.ts} +1 -1
  59. package/lib/{hooks/use-seam.js → seam/use-seam-client.js} +4 -5
  60. package/lib/seam/use-seam-client.js.map +1 -0
  61. package/lib/ui/AccessCodeTable/AccessCodeTable.d.ts +5 -0
  62. package/lib/ui/AccessCodeTable/AccessCodeTable.js +15 -0
  63. package/lib/ui/AccessCodeTable/AccessCodeTable.js.map +1 -0
  64. package/lib/ui/AccessCodeTable/CodeDetails.d.ts +4 -0
  65. package/lib/ui/AccessCodeTable/CodeDetails.js +28 -0
  66. package/lib/ui/AccessCodeTable/CodeDetails.js.map +1 -0
  67. package/lib/ui/AccessCodeTable/index.d.ts +2 -0
  68. package/lib/ui/AccessCodeTable/index.js +3 -0
  69. package/lib/ui/AccessCodeTable/index.js.map +1 -0
  70. package/lib/ui/DeviceDetails/BatteryStatus.d.ts +4 -0
  71. package/lib/ui/DeviceDetails/BatteryStatus.js +41 -0
  72. package/lib/ui/DeviceDetails/BatteryStatus.js.map +1 -0
  73. package/lib/ui/DeviceDetails/DeviceDetails.d.ts +4 -0
  74. package/lib/ui/DeviceDetails/DeviceDetails.js +38 -0
  75. package/lib/ui/DeviceDetails/DeviceDetails.js.map +1 -0
  76. package/lib/ui/DeviceDetails/DeviceImage.d.ts +4 -0
  77. package/lib/ui/DeviceDetails/DeviceImage.js +8 -0
  78. package/lib/ui/DeviceDetails/DeviceImage.js.map +1 -0
  79. package/lib/ui/DeviceDetails/ModelStatus.d.ts +4 -0
  80. package/lib/ui/DeviceDetails/ModelStatus.js +15 -0
  81. package/lib/ui/DeviceDetails/ModelStatus.js.map +1 -0
  82. package/lib/ui/DeviceDetails/OnlineStatus.d.ts +4 -0
  83. package/lib/ui/DeviceDetails/OnlineStatus.js +21 -0
  84. package/lib/ui/DeviceDetails/OnlineStatus.js.map +1 -0
  85. package/lib/ui/DeviceDetails/index.d.ts +5 -0
  86. package/lib/ui/DeviceDetails/index.js +6 -0
  87. package/lib/ui/DeviceDetails/index.js.map +1 -0
  88. package/lib/{components → ui}/DeviceManager/DeviceManager.d.ts +2 -3
  89. package/lib/{components → ui}/DeviceManager/DeviceManager.js +1 -1
  90. package/lib/ui/DeviceManager/DeviceManager.js.map +1 -0
  91. package/lib/ui/DeviceManager/index.d.ts +1 -0
  92. package/lib/ui/DeviceManager/index.js +2 -0
  93. package/lib/ui/DeviceManager/index.js.map +1 -0
  94. package/lib/ui/IconButton.d.ts +2 -0
  95. package/lib/ui/IconButton.js +5 -0
  96. package/lib/ui/IconButton.js.map +1 -0
  97. package/lib/ui/Table/TableBody.d.ts +4 -0
  98. package/lib/ui/Table/TableBody.js +5 -0
  99. package/lib/ui/Table/TableBody.js.map +1 -0
  100. package/lib/ui/Table/TableCell.d.ts +2 -0
  101. package/lib/ui/Table/TableCell.js +6 -0
  102. package/lib/ui/Table/TableCell.js.map +1 -0
  103. package/lib/ui/Table/TableHeader.d.ts +4 -0
  104. package/lib/ui/Table/TableHeader.js +5 -0
  105. package/lib/ui/Table/TableHeader.js.map +1 -0
  106. package/lib/ui/Table/TableRow.d.ts +2 -0
  107. package/lib/ui/Table/TableRow.js +5 -0
  108. package/lib/ui/Table/TableRow.js.map +1 -0
  109. package/lib/ui/Table/TableTitle.d.ts +4 -0
  110. package/lib/ui/Table/TableTitle.js +5 -0
  111. package/lib/ui/Table/TableTitle.js.map +1 -0
  112. package/lib/ui/Table/index.d.ts +5 -0
  113. package/lib/ui/Table/index.js +6 -0
  114. package/lib/ui/Table/index.js.map +1 -0
  115. package/lib/ui/TextField/SearchTextField.d.ts +2 -0
  116. package/lib/ui/TextField/SearchTextField.js +7 -0
  117. package/lib/ui/TextField/SearchTextField.js.map +1 -0
  118. package/lib/ui/TextField/TextField.d.ts +7 -0
  119. package/lib/ui/TextField/TextField.js +10 -0
  120. package/lib/ui/TextField/TextField.js.map +1 -0
  121. package/lib/ui/TextField/index.d.ts +2 -0
  122. package/lib/ui/TextField/index.js +3 -0
  123. package/lib/ui/TextField/index.js.map +1 -0
  124. package/lib/ui/index.js.map +1 -0
  125. package/lib/ui/layout/ContentHeader.d.ts +4 -0
  126. package/lib/ui/layout/ContentHeader.js +12 -0
  127. package/lib/ui/layout/ContentHeader.js.map +1 -0
  128. package/lib/ui/layout/DotDivider.d.ts +1 -0
  129. package/lib/ui/layout/DotDivider.js +5 -0
  130. package/lib/ui/layout/DotDivider.js.map +1 -0
  131. package/lib/ui/types.d.ts +3 -0
  132. package/lib/ui/types.js +2 -0
  133. package/lib/ui/types.js.map +1 -0
  134. package/lib/ui/typography/Caption.d.ts +4 -0
  135. package/lib/ui/typography/Caption.js +5 -0
  136. package/lib/ui/typography/Caption.js.map +1 -0
  137. package/lib/ui/typography/Title.d.ts +4 -0
  138. package/lib/ui/typography/Title.js +5 -0
  139. package/lib/ui/typography/Title.js.map +1 -0
  140. package/lib/use-toggle.d.ts +5 -0
  141. package/lib/use-toggle.js +14 -0
  142. package/lib/use-toggle.js.map +1 -0
  143. package/package.json +8 -1
  144. package/src/icons/access-code-key.svg +3 -0
  145. package/src/icons/arrow-back.svg +8 -0
  146. package/src/icons/battery-level-critical.svg +4 -0
  147. package/src/icons/battery-level-full.svg +4 -0
  148. package/src/icons/battery-level-high.svg +4 -0
  149. package/src/icons/battery-level-low.svg +4 -0
  150. package/src/icons/battery-level-wired.svg +8 -0
  151. package/src/icons/chevron-right.svg +8 -0
  152. package/src/icons/dots-ellipsis-more.svg +8 -0
  153. package/src/icons/online-status-account-offline.svg +8 -0
  154. package/src/icons/online-status-device-offline.svg +4 -0
  155. package/src/icons/online-status-online.svg +4 -0
  156. package/src/index.scss +1 -2
  157. package/src/lib/{provider.tsx → SeamProvider.tsx} +17 -3
  158. package/src/lib/icons/AccessCodeKey.tsx +19 -0
  159. package/src/lib/icons/ArrowBack.tsx +30 -0
  160. package/src/lib/icons/BatteryLevelCritical.tsx +27 -0
  161. package/src/lib/icons/BatteryLevelFull.tsx +20 -0
  162. package/src/lib/icons/BatteryLevelHigh.tsx +27 -0
  163. package/src/lib/icons/BatteryLevelLow.tsx +27 -0
  164. package/src/lib/icons/BatteryLevelWired.tsx +34 -0
  165. package/src/lib/icons/ChevronRight.tsx +32 -0
  166. package/src/lib/icons/DotsEllipsisMore.tsx +32 -0
  167. package/src/lib/icons/OnlineStatusAccountOffline.tsx +32 -0
  168. package/src/lib/icons/OnlineStatusDeviceOffline.tsx +23 -0
  169. package/src/lib/icons/OnlineStatusOnline.tsx +21 -0
  170. package/src/lib/icons/index.ts +12 -0
  171. package/src/lib/index.ts +3 -3
  172. package/src/lib/seam/devices/index.ts +1 -0
  173. package/src/lib/{hooks → seam/devices}/use-devices.ts +3 -3
  174. package/src/lib/seam/index.ts +2 -0
  175. package/src/lib/{hooks/use-seam.ts → seam/use-seam-client.ts} +3 -5
  176. package/src/lib/ui/AccessCodeTable/AccessCodeTable.tsx +57 -0
  177. package/src/lib/ui/AccessCodeTable/CodeDetails.tsx +51 -0
  178. package/src/lib/ui/AccessCodeTable/index.ts +2 -0
  179. package/src/lib/ui/DeviceDetails/BatteryStatus.tsx +81 -0
  180. package/src/lib/ui/DeviceDetails/DeviceDetails.tsx +99 -0
  181. package/src/lib/ui/DeviceDetails/DeviceImage.tsx +12 -0
  182. package/src/lib/ui/DeviceDetails/ModelStatus.tsx +27 -0
  183. package/src/lib/ui/DeviceDetails/OnlineStatus.tsx +44 -0
  184. package/src/lib/ui/DeviceDetails/index.ts +5 -0
  185. package/src/lib/{components → ui}/DeviceManager/DeviceManager.tsx +6 -4
  186. package/src/lib/ui/DeviceManager/index.ts +1 -0
  187. package/src/lib/ui/IconButton.tsx +5 -0
  188. package/src/lib/ui/Table/TableBody.tsx +5 -0
  189. package/src/lib/ui/Table/TableCell.tsx +9 -0
  190. package/src/lib/ui/Table/TableHeader.tsx +5 -0
  191. package/src/lib/ui/Table/TableRow.tsx +5 -0
  192. package/src/lib/ui/Table/TableTitle.tsx +5 -0
  193. package/src/lib/ui/Table/index.ts +5 -0
  194. package/src/lib/ui/TextField/SearchTextField.tsx +12 -0
  195. package/src/lib/ui/TextField/TextField.tsx +26 -0
  196. package/src/lib/ui/TextField/index.ts +2 -0
  197. package/src/lib/ui/layout/ContentHeader.tsx +21 -0
  198. package/src/lib/ui/layout/DotDivider.tsx +3 -0
  199. package/src/lib/ui/types.ts +4 -0
  200. package/src/lib/ui/typography/Caption.tsx +5 -0
  201. package/src/lib/ui/typography/Title.tsx +5 -0
  202. package/src/lib/use-toggle.ts +18 -0
  203. package/src/styles/access-code-table.scss +52 -0
  204. package/src/styles/buttons.scss +15 -0
  205. package/src/styles/content-header.scss +21 -0
  206. package/src/styles/device-details.scss +134 -0
  207. package/src/styles/inputs.scss +6 -0
  208. package/src/styles/main.scss +28 -0
  209. package/src/styles/tables.scss +36 -0
  210. package/src/styles/typography.scss +16 -0
  211. package/lib/components/DeviceManager/DeviceManager.js.map +0 -1
  212. package/lib/components/index.js.map +0 -1
  213. package/lib/hooks/index.d.ts +0 -1
  214. package/lib/hooks/index.js +0 -2
  215. package/lib/hooks/index.js.map +0 -1
  216. package/lib/hooks/use-devices.js.map +0 -1
  217. package/lib/hooks/use-seam.js.map +0 -1
  218. package/lib/provider.js.map +0 -1
  219. package/src/lib/hooks/index.ts +0 -1
  220. package/src/styles/_main.scss +0 -10
  221. /package/lib/{hooks → seam/devices}/use-devices.d.ts +0 -0
  222. /package/lib/{components → ui}/index.d.ts +0 -0
  223. /package/lib/{components → ui}/index.js +0 -0
  224. /package/src/lib/{components → ui}/index.ts +0 -0
@@ -0,0 +1,32 @@
1
+ import type { SVGProps } from 'react'
2
+ export const DotsEllipsisMoreIcon = (
3
+ props: SVGProps<SVGSVGElement>
4
+ ): JSX.Element => (
5
+ <svg
6
+ xmlns='http://www.w3.org/2000/svg'
7
+ width={18}
8
+ height={18}
9
+ fill='none'
10
+ {...props}
11
+ >
12
+ <mask
13
+ id='dots-ellipsis-more_svg__a'
14
+ width={18}
15
+ height={18}
16
+ x={0}
17
+ y={0}
18
+ maskUnits='userSpaceOnUse'
19
+ style={{
20
+ maskType: 'alpha',
21
+ }}
22
+ >
23
+ <path fill='#2196F3' d='M0 0h18v18H0z' />
24
+ </mask>
25
+ <g mask='url(#dots-ellipsis-more_svg__a)'>
26
+ <path
27
+ fill='#007AFC'
28
+ d='M4.5 10.5c-.412 0-.766-.147-1.06-.44A1.445 1.445 0 0 1 3 9c0-.412.147-.766.44-1.06.294-.293.648-.44 1.06-.44.412 0 .766.147 1.06.44.293.294.44.647.44 1.06 0 .412-.147.766-.44 1.06-.294.293-.647.44-1.06.44Zm4.5 0c-.412 0-.766-.147-1.06-.44A1.444 1.444 0 0 1 7.5 9c0-.412.147-.766.44-1.06.294-.293.647-.44 1.06-.44.412 0 .766.147 1.06.44.293.294.44.647.44 1.06 0 .412-.147.766-.44 1.06-.294.293-.648.44-1.06.44Zm4.5 0c-.412 0-.766-.147-1.06-.44A1.445 1.445 0 0 1 12 9c0-.412.147-.766.44-1.06.294-.293.648-.44 1.06-.44.412 0 .766.147 1.06.44.293.294.44.647.44 1.06 0 .412-.147.766-.44 1.06-.294.293-.648.44-1.06.44Z'
29
+ />
30
+ </g>
31
+ </svg>
32
+ )
@@ -0,0 +1,32 @@
1
+ import type { SVGProps } from 'react'
2
+ export const OnlineStatusAccountOfflineIcon = (
3
+ props: SVGProps<SVGSVGElement>
4
+ ): JSX.Element => (
5
+ <svg
6
+ xmlns='http://www.w3.org/2000/svg'
7
+ width={24}
8
+ height={25}
9
+ fill='none'
10
+ {...props}
11
+ >
12
+ <mask
13
+ id='online-status-account-offline_svg__a'
14
+ width={24}
15
+ height={25}
16
+ x={0}
17
+ y={0}
18
+ maskUnits='userSpaceOnUse'
19
+ style={{
20
+ maskType: 'alpha',
21
+ }}
22
+ >
23
+ <path fill='#D9D9D9' d='M0 .733h24v24H0z' />
24
+ </mask>
25
+ <g mask='url(#online-status-account-offline_svg__a)'>
26
+ <path
27
+ fill='#E36857'
28
+ d='m19.8 23.333-2.65-2.6H6.5c-1.533 0-2.833-.534-3.9-1.6-1.067-1.067-1.6-2.367-1.6-3.9 0-1.284.396-2.425 1.188-3.425A5.286 5.286 0 0 1 5.25 9.883c.05-.134.1-.263.15-.388.05-.125.1-.262.15-.412L1.4 4.933l1.4-1.4 18.4 18.4-1.4 1.4Zm-13.3-4.6h8.65l-8.05-8.05a6.626 6.626 0 0 0-.075.525 5.28 5.28 0 0 0-.025.525h-.5c-.967 0-1.792.341-2.475 1.025A3.372 3.372 0 0 0 3 15.233c0 .966.342 1.791 1.025 2.475A3.372 3.372 0 0 0 6.5 18.733Zm15.1.75-1.45-1.4c.283-.234.496-.505.638-.813.141-.308.212-.654.212-1.037 0-.7-.242-1.292-.725-1.775-.483-.484-1.075-.725-1.775-.725H17v-2c0-1.384-.488-2.563-1.463-3.538-.975-.975-2.154-1.462-3.537-1.462-.45 0-.883.054-1.3.162-.417.109-.817.28-1.2.513l-1.45-1.45a7.028 7.028 0 0 1 1.862-.913A6.878 6.878 0 0 1 12 4.733c1.95 0 3.604.679 4.962 2.037C18.322 8.13 19 9.783 19 11.733c1.15.133 2.104.629 2.863 1.487A4.407 4.407 0 0 1 23 16.233a4.384 4.384 0 0 1-1.4 3.25Z'
29
+ />
30
+ </g>
31
+ </svg>
32
+ )
@@ -0,0 +1,23 @@
1
+ import type { SVGProps } from 'react'
2
+ export const OnlineStatusDeviceOfflineIcon = (
3
+ props: SVGProps<SVGSVGElement>
4
+ ): JSX.Element => (
5
+ <svg
6
+ xmlns='http://www.w3.org/2000/svg'
7
+ width={24}
8
+ height={25}
9
+ fill='none'
10
+ {...props}
11
+ >
12
+ <path
13
+ fill='#E36857'
14
+ d='m1.411 4.931 1.373-1.373 18.432 18.431-1.373 1.373z'
15
+ />
16
+ <path
17
+ fill='#E36857'
18
+ fillRule='evenodd'
19
+ d='M12 23.362c-1.95 0-3.604-.679-4.963-2.037C5.68 19.967 5 18.312 5 16.362v-8c0-.799.114-1.548.342-2.248L7.028 7.8c-.019.184-.028.371-.028.562v8c0 1.384.487 2.563 1.463 3.538.975.975 2.154 1.462 3.537 1.462s2.563-.487 3.537-1.462c.664-.664 1.102-1.423 1.314-2.276l1.58 1.58a6.913 6.913 0 0 1-1.469 2.12c-1.358 1.36-3.012 2.038-4.962 2.038Zm6.975-6.36c.017-.21.025-.423.025-.64v-8c0-1.95-.68-3.604-2.038-4.962C15.604 2.04 13.95 1.362 12 1.362c-1.95 0-3.604.68-4.963 2.038a7.413 7.413 0 0 0-.767.897l1.452 1.451c.204-.325.45-.633.74-.923.976-.975 2.155-1.463 3.538-1.463s2.563.488 3.537 1.463C16.512 5.8 17 6.979 17 8.362v6.664l1.975 1.975ZM15 12.361c.283 0 .52-.095.713-.287a.968.968 0 0 0 .287-.713.968.968 0 0 0-.287-.712.968.968 0 0 0-.713-.288.968.968 0 0 0-.713.288.968.968 0 0 0-.287.712c0 .284.096.521.287.713.192.192.43.287.713.287Zm-6 3c.283 0 .52-.095.713-.287a.968.968 0 0 0 .287-.713.968.968 0 0 0-.287-.712.967.967 0 0 0-.713-.288.967.967 0 0 0-.713.288.968.968 0 0 0-.287.712c0 .284.096.521.287.713.192.192.43.287.713.287Zm0 3c.283 0 .52-.095.713-.287a.968.968 0 0 0 .287-.713.968.968 0 0 0-.287-.712.967.967 0 0 0-.713-.288.967.967 0 0 0-.713.288.968.968 0 0 0-.287.712c0 .284.096.521.287.713.192.192.43.287.713.287Zm3 0c.283 0 .52-.095.713-.287a.968.968 0 0 0 .287-.713.968.968 0 0 0-.287-.712.968.968 0 0 0-.713-.288.968.968 0 0 0-.713.288.968.968 0 0 0-.287.712c0 .284.096.521.287.713.192.192.43.287.713.287Zm3.713-9.287a.968.968 0 0 1-.713.287.968.968 0 0 1-.713-.287.967.967 0 0 1-.287-.713c0-.283.096-.52.287-.712A.968.968 0 0 1 15 7.362c.283 0 .52.096.713.288.191.191.287.429.287.712 0 .284-.096.521-.287.713Zm-3.749.287c.283 0 .52-.096.713-.287a.967.967 0 0 0 .287-.713.967.967 0 0 0-.287-.712.968.968 0 0 0-.713-.288.968.968 0 0 0-.712.288.967.967 0 0 0-.288.712c0 .284.096.521.288.713.191.191.429.287.712.287Z'
20
+ clipRule='evenodd'
21
+ />
22
+ </svg>
23
+ )
@@ -0,0 +1,21 @@
1
+ import type { SVGProps } from 'react'
2
+ export const OnlineStatusOnlineIcon = (
3
+ props: SVGProps<SVGSVGElement>
4
+ ): JSX.Element => (
5
+ <svg
6
+ xmlns='http://www.w3.org/2000/svg'
7
+ width={24}
8
+ height={24}
9
+ fill='none'
10
+ {...props}
11
+ >
12
+ <path
13
+ fill='#9DA1A9'
14
+ d='M6.5 20c-1.517 0-2.813-.525-3.888-1.575C1.537 17.375 1 16.092 1 14.575c0-1.3.392-2.458 1.175-3.475S3.983 9.433 5.25 9.15c.417-1.533 1.25-2.775 2.5-3.725C9 4.475 10.417 4 12 4c1.95 0 3.604.68 4.962 2.037C18.322 7.396 19 9.05 19 11c1.15.133 2.104.63 2.863 1.488A4.407 4.407 0 0 1 23 15.5c0 1.25-.438 2.313-1.313 3.188S19.75 20 18.5 20h-12Zm0-2h12c.7 0 1.292-.242 1.775-.725.483-.483.725-1.075.725-1.775s-.242-1.292-.725-1.775C19.792 13.242 19.2 13 18.5 13H17v-2c0-1.383-.488-2.563-1.463-3.537C14.563 6.487 13.383 6 12 6s-2.563.487-3.537 1.463C7.488 8.437 7 9.617 7 11h-.5c-.967 0-1.792.342-2.475 1.025A3.372 3.372 0 0 0 3 14.5c0 .967.342 1.792 1.025 2.475A3.372 3.372 0 0 0 6.5 18Z'
15
+ />
16
+ <path
17
+ fill='#27AE60'
18
+ d='M16 11.35 10.35 17 6.8 13.45l1.425-1.425 2.1 2.1L14.55 9.9 16 11.35Z'
19
+ />
20
+ </svg>
21
+ )
@@ -1 +1,13 @@
1
+ export { AccessCodeKeyIcon } from './AccessCodeKey.js'
2
+ export { ArrowBackIcon } from './ArrowBack.js'
3
+ export { BatteryLevelCriticalIcon } from './BatteryLevelCritical.js'
4
+ export { BatteryLevelFullIcon } from './BatteryLevelFull.js'
5
+ export { BatteryLevelHighIcon } from './BatteryLevelHigh.js'
6
+ export { BatteryLevelLowIcon } from './BatteryLevelLow.js'
7
+ export { BatteryLevelWiredIcon } from './BatteryLevelWired.js'
8
+ export { ChevronRightIcon } from './ChevronRight.js'
9
+ export { DotsEllipsisMoreIcon } from './DotsEllipsisMore.js'
10
+ export { OnlineStatusAccountOfflineIcon } from './OnlineStatusAccountOffline.js'
11
+ export { OnlineStatusDeviceOfflineIcon } from './OnlineStatusDeviceOffline.js'
12
+ export { OnlineStatusOnlineIcon } from './OnlineStatusOnline.js'
1
13
  export { SeamIcon } from './Seam.js'
package/src/lib/index.ts CHANGED
@@ -1,3 +1,3 @@
1
- export * from './components/index.js'
2
- export * from './hooks/index.js'
3
- export * from './provider.js'
1
+ export * from './seam/index.js'
2
+ export * from './SeamProvider.js'
3
+ export * from './ui/index.js'
@@ -0,0 +1 @@
1
+ export * from './use-devices.js'
@@ -5,7 +5,7 @@ import type {
5
5
  SeamError,
6
6
  } from 'seamapi'
7
7
 
8
- import { useSeam } from './use-seam.js'
8
+ import { useSeamClient } from 'lib/seam/use-seam-client.js'
9
9
 
10
10
  export type UseDevicesParams = DevicesListRequest
11
11
  export type UseDevicesData = DevicesListResponse['devices']
@@ -15,11 +15,11 @@ type Result = UseQueryResult<UseDevicesData, SeamError>
15
15
  type UseDevicesResult = Omit<Result, 'data'> & { devices: Result['data'] }
16
16
 
17
17
  export function useDevices(params: DevicesListRequest): UseDevicesResult {
18
- const { client } = useSeam()
18
+ const { client } = useSeamClient()
19
19
  const { data, ...rest } = useQuery<DevicesListResponse['devices'], SeamError>(
20
20
  {
21
21
  enabled: client != null,
22
- queryKey: ['list', 'devices', params],
22
+ queryKey: ['devices', 'list', params],
23
23
  queryFn: async () => {
24
24
  if (client == null) return []
25
25
  return await client?.devices.list(params)
@@ -0,0 +1,2 @@
1
+ export * from './devices/index.js'
2
+ export * from './use-seam-client.js'
@@ -1,18 +1,16 @@
1
1
  import { useQuery } from '@tanstack/react-query'
2
- import { useContext } from 'react'
3
2
  import { type ClientSession, Seam } from 'seamapi'
4
3
  import { v4 as uuidv4 } from 'uuid'
5
4
 
6
- import { seamContext } from 'lib/provider.js'
5
+ import { useSeamContext } from 'lib/SeamProvider.js'
7
6
 
8
- export function useSeam(): {
7
+ export function useSeamClient(): {
9
8
  client: Seam | null
10
9
  isLoading: boolean
11
10
  isError: boolean
12
11
  error: unknown
13
12
  } {
14
- const { client, clientOptions, publishableKey, ...context } =
15
- useContext(seamContext)
13
+ const { client, clientOptions, publishableKey, ...context } = useSeamContext()
16
14
  const [clientSession, setClientSession] = useClientSession()
17
15
  const userIdentifierKey = useUserIdentifierKey(context.userIdentifierKey)
18
16
 
@@ -0,0 +1,57 @@
1
+ import type { AccessCode } from 'seamapi'
2
+
3
+ import {
4
+ TableBody,
5
+ TableCell,
6
+ TableHeader,
7
+ TableRow,
8
+ TableTitle,
9
+ } from 'lib/ui/Table/index.js'
10
+
11
+ import { AccessCodeKeyIcon } from 'lib/icons/AccessCodeKey.js'
12
+ import { CodeDetails } from 'lib/ui/AccessCodeTable/CodeDetails.js'
13
+ import { ContentHeader } from 'lib/ui/layout/ContentHeader.js'
14
+ import { Caption } from 'lib/ui/typography/Caption.js'
15
+ import { Title } from 'lib/ui/typography/Title.js'
16
+
17
+ export function AccessCodeTable(props: {
18
+ accessCodes: AccessCode[]
19
+ onClickBack?: () => void
20
+ }) {
21
+ const { accessCodes, onClickBack } = props
22
+
23
+ return (
24
+ <div className='seam-access-code-table'>
25
+ <ContentHeader onClickBack={onClickBack} />
26
+ <TableHeader>
27
+ <TableTitle>
28
+ {t.accessCodes} <Caption>({accessCodes.length})</Caption>
29
+ </TableTitle>
30
+ </TableHeader>
31
+ <TableBody>
32
+ {accessCodes.map((code) => (
33
+ <TableRow key={code.access_code_id}>
34
+ <TableCell className='seam-icon-cell'>
35
+ <div>
36
+ <AccessCodeKeyIcon />
37
+ </div>
38
+ </TableCell>
39
+ <TableCell className='seam-name-cell'>
40
+ <Title>{code.name}</Title>
41
+ <CodeDetails accessCode={code} />
42
+ </TableCell>
43
+ <TableCell className='seam-action-cell'>
44
+ {/* <IconButton>
45
+ <DotsEllipsisMoreIcon />
46
+ </IconButton> */}
47
+ </TableCell>
48
+ </TableRow>
49
+ ))}
50
+ </TableBody>
51
+ </div>
52
+ )
53
+ }
54
+
55
+ const t = {
56
+ accessCodes: 'Access Codes',
57
+ }
@@ -0,0 +1,51 @@
1
+ import dayjs from 'dayjs'
2
+ import type { AccessCode } from 'seamapi'
3
+
4
+ import { DotDivider } from 'lib/ui/layout/DotDivider.js'
5
+
6
+ export function CodeDetails(props: { accessCode: AccessCode }) {
7
+ const { accessCode } = props
8
+
9
+ return (
10
+ <div className='seam-access-code-details'>
11
+ Unit 110
12
+ <DotDivider />
13
+ <Duration accessCode={accessCode} />
14
+ <DotDivider />
15
+ {t.code}: {accessCode.code}
16
+ </div>
17
+ )
18
+ }
19
+
20
+ function Duration(props: { accessCode: AccessCode }) {
21
+ const { accessCode } = props
22
+ if (accessCode.type === 'ongoing') {
23
+ return <span>{t.ends}: Never</span>
24
+ }
25
+
26
+ const hasStarted = new Date(accessCode.starts_at).valueOf() < Date.now()
27
+ if (hasStarted) {
28
+ return (
29
+ <span>
30
+ {t.ends}: {formatDate(accessCode.ends_at)}{' '}
31
+ </span>
32
+ )
33
+ }
34
+
35
+ // is in future
36
+ return (
37
+ <span>
38
+ {t.starts}: {formatDate(accessCode.starts_at)}
39
+ </span>
40
+ )
41
+ }
42
+
43
+ function formatDate(date: string) {
44
+ return dayjs(date).format('MMM D')
45
+ }
46
+
47
+ const t = {
48
+ code: 'Code',
49
+ starts: 'Starts',
50
+ ends: 'Ends',
51
+ }
@@ -0,0 +1,2 @@
1
+ export * from './AccessCodeTable.js'
2
+ export * from './CodeDetails.js'
@@ -0,0 +1,81 @@
1
+ import type { LockDevice } from 'seamapi'
2
+
3
+ import { BatteryLevelCriticalIcon } from 'lib/icons/BatteryLevelCritical.js'
4
+ import { BatteryLevelFullIcon } from 'lib/icons/BatteryLevelFull.js'
5
+ import { BatteryLevelHighIcon } from 'lib/icons/BatteryLevelHigh.js'
6
+ import { BatteryLevelLowIcon } from 'lib/icons/BatteryLevelLow.js'
7
+
8
+ /**
9
+ * Thresholds to determine the battery status
10
+ */
11
+ const BATTERY_LEVEL = {
12
+ FULL: 0.85,
13
+ HIGH: 0.6,
14
+ LOW: 0.3,
15
+ }
16
+ export function BatteryStatus(props: { device: LockDevice }) {
17
+ const {
18
+ device: {
19
+ properties: { battery_level: batteryLevel },
20
+ },
21
+ } = props
22
+
23
+ if (batteryLevel === undefined) {
24
+ return null
25
+ }
26
+
27
+ return (
28
+ <>
29
+ <span className='seam-label'>{t.power}:</span>{' '}
30
+ <div className='seam-battery-status'>
31
+ <Status batteryLevel={batteryLevel} />
32
+ </div>
33
+ </>
34
+ )
35
+ }
36
+
37
+ function Status(props: { batteryLevel: number }) {
38
+ const { batteryLevel } = props
39
+
40
+ if (batteryLevel > BATTERY_LEVEL.FULL) {
41
+ return (
42
+ <>
43
+ <BatteryLevelFullIcon />
44
+ <span className='seam-status-text'>{t.full}</span>
45
+ </>
46
+ )
47
+ }
48
+
49
+ if (batteryLevel > BATTERY_LEVEL.HIGH) {
50
+ return (
51
+ <>
52
+ <BatteryLevelHighIcon />
53
+ <span className='seam-status-text'>{t.high}</span>
54
+ </>
55
+ )
56
+ }
57
+
58
+ if (batteryLevel > BATTERY_LEVEL.LOW) {
59
+ return (
60
+ <>
61
+ <BatteryLevelLowIcon />
62
+ <span className='seam-status-text'>{t.low}</span>
63
+ </>
64
+ )
65
+ }
66
+
67
+ return (
68
+ <>
69
+ <BatteryLevelCriticalIcon />
70
+ <span className='seam-text-danger'>{t.critical}</span>
71
+ </>
72
+ )
73
+ }
74
+
75
+ const t = {
76
+ power: 'Power',
77
+ full: 'Good',
78
+ high: 'Good',
79
+ low: 'Low',
80
+ critical: 'Low!',
81
+ }
@@ -0,0 +1,99 @@
1
+ import { type AccessCode, type LockDevice } from 'seamapi'
2
+
3
+ import { ChevronRightIcon } from 'lib/icons/ChevronRight.js'
4
+ import { AccessCodeTable } from 'lib/ui/AccessCodeTable/AccessCodeTable.js'
5
+ import { BatteryStatus } from 'lib/ui/DeviceDetails/BatteryStatus.js'
6
+ import { DeviceImage } from 'lib/ui/DeviceDetails/DeviceImage.js'
7
+ import { ModelStatus } from 'lib/ui/DeviceDetails/ModelStatus.js'
8
+ import { OnlineStatus } from 'lib/ui/DeviceDetails/OnlineStatus.js'
9
+ import { ContentHeader } from 'lib/ui/layout/ContentHeader.js'
10
+ import useToggle from 'lib/use-toggle.js'
11
+
12
+ export function DeviceDetails(props: { device: LockDevice }) {
13
+ const { device } = props
14
+
15
+ const lockStatus = device.properties.locked ? t.locked : t.unlocked
16
+
17
+ const accessCodeLength =
18
+ device.properties?.schlage_metadata?.access_code_length ?? null
19
+
20
+ // TODO : Fetch access codes
21
+ const accessCodes: AccessCode[] = []
22
+
23
+ const [showingAccessCodes, toggleAccessCodes] = useToggle()
24
+
25
+ if (showingAccessCodes) {
26
+ return (
27
+ <AccessCodeTable
28
+ accessCodes={accessCodes}
29
+ onClickBack={toggleAccessCodes}
30
+ />
31
+ )
32
+ }
33
+
34
+ return (
35
+ <div className='seam-device-details'>
36
+ <ContentHeader title='Device' />
37
+ <div className='seam-body'>
38
+ <div className='seam-summary'>
39
+ <div className='seam-content'>
40
+ <div className='seam-image'>
41
+ <DeviceImage device={device} />
42
+ </div>
43
+
44
+ <div className='seam-info'>
45
+ <h4 className='seam-device-name'>{device.properties.name}</h4>
46
+ <div className='seam-properties'>
47
+ <OnlineStatus device={device} />
48
+ <BatteryStatus device={device} />
49
+ <ModelStatus device={device} />
50
+ </div>
51
+ </div>
52
+ </div>
53
+ </div>
54
+ <div className='seam-box'>
55
+ <div
56
+ className='seam-content seam-access-codes'
57
+ onClick={toggleAccessCodes}
58
+ >
59
+ <span className='seam-value'>49 {t.accessCodes}</span>
60
+ <ChevronRightIcon />
61
+ </div>
62
+ </div>
63
+
64
+ <div className='seam-box'>
65
+ <div className='seam-content'>
66
+ <span className='seam-label'>{t.lockStatus}</span>
67
+ <span className='seam-value'>{lockStatus}</span>
68
+ </div>
69
+ <AccessCodeLength accessCodeLength={accessCodeLength} />
70
+ </div>
71
+ </div>
72
+ </div>
73
+ )
74
+ }
75
+
76
+ function AccessCodeLength(props: { accessCodeLength: number | null }) {
77
+ const { accessCodeLength } = props
78
+ if (accessCodeLength === null) {
79
+ return null
80
+ }
81
+
82
+ return (
83
+ <div className='seam-content seam-access-code-length'>
84
+ <span className='seam-label'>{t.codeLength}</span>
85
+ <span className='seam-value'>
86
+ {accessCodeLength} {t.digits}
87
+ </span>
88
+ </div>
89
+ )
90
+ }
91
+
92
+ const t = {
93
+ locked: 'Locked',
94
+ unlocked: 'Unlocked',
95
+ accessCodes: 'access codes',
96
+ codeLength: 'Code length',
97
+ digits: 'digits',
98
+ lockStatus: 'lockStatus',
99
+ }
@@ -0,0 +1,12 @@
1
+ import type { LockDevice } from 'seamapi'
2
+
3
+ const FALLBACK_IMAGE_URL =
4
+ 'https://connect.getseam.com/assets/images/devices/unknown-lock.png'
5
+
6
+ export function DeviceImage(props: { device: LockDevice }) {
7
+ const { device } = props
8
+
9
+ const url = device.properties.image_url ?? FALLBACK_IMAGE_URL
10
+
11
+ return <img src={url} alt={device.properties.name} />
12
+ }
@@ -0,0 +1,27 @@
1
+ import type { LockDevice } from 'seamapi'
2
+
3
+ export function ModelStatus(props: { device: LockDevice }) {
4
+ const {
5
+ device: { properties },
6
+ } = props
7
+
8
+ const model =
9
+ properties?.august_metadata?.model ??
10
+ properties?.schlage_metadata?.model ??
11
+ null
12
+
13
+ if (model === null) {
14
+ return null
15
+ }
16
+
17
+ return (
18
+ <>
19
+ <span className='seam-label'>{t.model}:</span>{' '}
20
+ <div className='seam-device-model'>{model}</div>
21
+ </>
22
+ )
23
+ }
24
+
25
+ const t = {
26
+ model: 'Model',
27
+ }
@@ -0,0 +1,44 @@
1
+ import type { LockDevice } from 'seamapi'
2
+
3
+ import { OnlineStatusDeviceOfflineIcon } from 'lib/icons/OnlineStatusDeviceOffline.js'
4
+ import { OnlineStatusOnlineIcon } from 'lib/icons/OnlineStatusOnline.js'
5
+
6
+ export function OnlineStatus(props: { device: LockDevice }) {
7
+ const { device } = props
8
+ return (
9
+ <>
10
+ <span className='seam-label'>{t.status}:</span>{' '}
11
+ <div className='seam-online-status'>
12
+ <Status isOnline={device.properties.online} />
13
+ </div>
14
+ </>
15
+ )
16
+ }
17
+
18
+ function Status(props: { isOnline: boolean }) {
19
+ const { isOnline } = props
20
+
21
+ if (isOnline) {
22
+ return (
23
+ <>
24
+ <OnlineStatusOnlineIcon />
25
+ <span className='seam-status-text'>{t.online}</span>
26
+ </>
27
+ )
28
+ }
29
+
30
+ // TODO: Check for Account Offline status
31
+
32
+ return (
33
+ <>
34
+ <OnlineStatusDeviceOfflineIcon />
35
+ <span className='seam-text-danger'>{t.deviceOffline}</span>
36
+ </>
37
+ )
38
+ }
39
+
40
+ const t = {
41
+ status: 'Status',
42
+ online: 'Online',
43
+ deviceOffline: 'Device Offline',
44
+ }
@@ -0,0 +1,5 @@
1
+ export * from './BatteryStatus.js'
2
+ export * from './DeviceDetails.js'
3
+ export * from './DeviceImage.js'
4
+ export * from './ModelStatus.js'
5
+ export * from './OnlineStatus.js'
@@ -1,14 +1,16 @@
1
- import type { ReactElement } from 'react'
2
1
  import type { CommonDeviceProperties, Device } from 'seamapi'
3
2
 
4
- import { useDevices, type UseDevicesParams } from 'lib/hooks/use-devices.js'
3
+ import {
4
+ useDevices,
5
+ type UseDevicesParams,
6
+ } from 'lib/seam/devices/use-devices.js'
5
7
 
6
8
  export type DeviceManagerProps = UseDevicesParams
7
9
 
8
10
  /**
9
11
  * Fetch, list, and manage devices.
10
12
  */
11
- export const DeviceManager = (props: DeviceManagerProps): ReactElement => {
13
+ export const DeviceManager = (props: DeviceManagerProps): JSX.Element => {
12
14
  const { devices, isLoading, isError, error } = useDevices(props)
13
15
 
14
16
  if (isLoading) return <p role='loading'>{t.loading}</p>
@@ -30,7 +32,7 @@ export const DeviceManager = (props: DeviceManagerProps): ReactElement => {
30
32
 
31
33
  const DeviceManagerItem = (
32
34
  props: Device<CommonDeviceProperties>
33
- ): ReactElement => {
35
+ ): JSX.Element => {
34
36
  return (
35
37
  <li>
36
38
  <p>
@@ -0,0 +1 @@
1
+ export * from './DeviceManager.js'
@@ -0,0 +1,5 @@
1
+ import type { ButtonProps } from 'lib/ui/types.js'
2
+
3
+ export function IconButton(props: ButtonProps) {
4
+ return <button {...props} className='seam-button seam-icon-button' />
5
+ }
@@ -0,0 +1,5 @@
1
+ import type { ReactNode } from 'react'
2
+
3
+ export function TableBody(props: { children: ReactNode }) {
4
+ return <div className='seam-table-body'>{props.children}</div>
5
+ }
@@ -0,0 +1,9 @@
1
+ import classNames from 'classnames'
2
+
3
+ import type { DivProps } from 'lib/ui/types.js'
4
+
5
+ export function TableCell({ className, ...otherProps }: DivProps) {
6
+ return (
7
+ <div className={classNames('seam-table-cell', className)} {...otherProps} />
8
+ )
9
+ }
@@ -0,0 +1,5 @@
1
+ import type { ReactNode } from 'react'
2
+
3
+ export function TableHeader(props: { children: ReactNode }) {
4
+ return <div className='seam-table-header'>{props.children}</div>
5
+ }
@@ -0,0 +1,5 @@
1
+ import type { DivProps } from 'lib/ui/types.js'
2
+
3
+ export function TableRow(props: DivProps) {
4
+ return <div className='seam-table-row'>{props.children}</div>
5
+ }
@@ -0,0 +1,5 @@
1
+ import type { ReactNode } from 'react'
2
+
3
+ export function TableTitle(props: { children: ReactNode }) {
4
+ return <h5 className='seam-table-title'>{props.children}</h5>
5
+ }
@@ -0,0 +1,5 @@
1
+ export * from './TableBody.js'
2
+ export * from './TableCell.js'
3
+ export * from './TableHeader.js'
4
+ export * from './TableRow.js'
5
+ export * from './TableTitle.js'