@seamapi/react 1.6.0 → 1.8.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 (212) hide show
  1. package/README.md +18 -5
  2. package/dist/elements.js +25043 -0
  3. package/dist/elements.js.map +1 -0
  4. package/hooks.d.ts +1 -0
  5. package/hooks.js +2 -0
  6. package/hooks.js.map +1 -0
  7. package/index.css +6 -0
  8. package/index.css.map +1 -1
  9. package/index.min.css +1 -1
  10. package/index.min.css.map +1 -1
  11. package/lib/{sort-by.d.ts → dates.d.ts} +1 -1
  12. package/lib/{sort-by.js → dates.js} +2 -2
  13. package/lib/dates.js.map +1 -0
  14. package/lib/index.d.ts +2 -2
  15. package/lib/index.js +2 -2
  16. package/lib/index.js.map +1 -1
  17. package/lib/{SeamProvider.d.ts → seam/SeamProvider.d.ts} +9 -6
  18. package/lib/{SeamProvider.js → seam/SeamProvider.js} +29 -30
  19. package/lib/seam/SeamProvider.js.map +1 -0
  20. package/lib/seam/access-codes/use-access-codes.js +2 -2
  21. package/lib/seam/access-codes/use-access-codes.js.map +1 -1
  22. package/lib/{ui → seam/components}/AccessCodeDetails/AccessCodeDetails.d.ts +2 -1
  23. package/lib/{ui → seam/components}/AccessCodeDetails/AccessCodeDetails.js +9 -8
  24. package/lib/seam/components/AccessCodeDetails/AccessCodeDetails.js.map +1 -0
  25. package/lib/{ui → seam/components}/AccessCodeDetails/AccessCodeDevice.js +7 -7
  26. package/lib/seam/components/AccessCodeDetails/AccessCodeDevice.js.map +1 -0
  27. package/lib/seam/components/AccessCodeTable/AccessCodeTable.d.ts +7 -0
  28. package/lib/seam/components/AccessCodeTable/AccessCodeTable.js +77 -0
  29. package/lib/seam/components/AccessCodeTable/AccessCodeTable.js.map +1 -0
  30. package/lib/{ui → seam/components}/AccessCodeTable/CodeDetails.js +3 -3
  31. package/lib/seam/components/AccessCodeTable/CodeDetails.js.map +1 -0
  32. package/lib/seam/components/DeviceDetails/DeviceDetails.d.ts +7 -0
  33. package/lib/seam/components/DeviceDetails/DeviceDetails.js +80 -0
  34. package/lib/seam/components/DeviceDetails/DeviceDetails.js.map +1 -0
  35. package/lib/seam/components/DeviceDetails/DeviceModel.js.map +1 -0
  36. package/lib/{ui → seam/components}/DeviceTable/DeviceHealthBar.d.ts +3 -2
  37. package/lib/{ui → seam/components}/DeviceTable/DeviceHealthBar.js +4 -4
  38. package/lib/seam/components/DeviceTable/DeviceHealthBar.js.map +1 -0
  39. package/lib/{ui → seam/components}/DeviceTable/DeviceRow.d.ts +1 -1
  40. package/lib/{ui → seam/components}/DeviceTable/DeviceRow.js +9 -9
  41. package/lib/seam/components/DeviceTable/DeviceRow.js.map +1 -0
  42. package/lib/seam/components/DeviceTable/DeviceTable.d.ts +9 -0
  43. package/lib/seam/components/DeviceTable/DeviceTable.js +66 -0
  44. package/lib/seam/components/DeviceTable/DeviceTable.js.map +1 -0
  45. package/lib/seam/components/SupportedDeviceTable/FilterCategoryMenu.d.ts +20 -0
  46. package/lib/{ui → seam/components}/SupportedDeviceTable/FilterCategoryMenu.js +8 -5
  47. package/lib/seam/components/SupportedDeviceTable/FilterCategoryMenu.js.map +1 -0
  48. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceContent.d.ts +9 -0
  49. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceContent.js +39 -0
  50. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceContent.js.map +1 -0
  51. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceFilterArea.d.ts +9 -0
  52. package/lib/{ui → seam/components}/SupportedDeviceTable/SupportedDeviceFilterArea.js +33 -28
  53. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceFilterArea.js.map +1 -0
  54. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceHeader.d.ts +2 -0
  55. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceHeader.js +12 -0
  56. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceHeader.js.map +1 -0
  57. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceRow.d.ts +6 -0
  58. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceRow.js +19 -0
  59. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceRow.js.map +1 -0
  60. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceTable.d.ts +6 -0
  61. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceTable.js +17 -0
  62. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceTable.js.map +1 -0
  63. package/lib/seam/components/SupportedDeviceTable/use-filtered-device-models.d.ts +7 -0
  64. package/lib/seam/components/SupportedDeviceTable/use-filtered-device-models.js +18 -0
  65. package/lib/seam/components/SupportedDeviceTable/use-filtered-device-models.js.map +1 -0
  66. package/lib/seam/components/index.js.map +1 -0
  67. package/lib/seam/device-models/use-device-models.d.ts +5 -0
  68. package/lib/seam/device-models/use-device-models.js +17 -0
  69. package/lib/seam/device-models/use-device-models.js.map +1 -0
  70. package/lib/seam/devices/use-devices.js +3 -3
  71. package/lib/seam/devices/use-devices.js.map +1 -1
  72. package/lib/seam/devices/use-toggle-lock.js +1 -1
  73. package/lib/seam/devices/use-toggle-lock.js.map +1 -1
  74. package/lib/seam/index.d.ts +1 -0
  75. package/lib/seam/index.js +1 -0
  76. package/lib/seam/index.js.map +1 -1
  77. package/lib/seam/use-seam-client.js +1 -1
  78. package/lib/seam/use-seam-client.js.map +1 -1
  79. package/lib/seam/use-seam-font.d.ts +1 -1
  80. package/lib/seam/use-seam-font.js +1 -1
  81. package/lib/seam/use-seam-font.js.map +1 -1
  82. package/lib/seam/use-seam-styles.js.map +1 -1
  83. package/lib/{capitalize.js → strings.js} +1 -1
  84. package/lib/strings.js.map +1 -0
  85. package/lib/ui/Menu/Menu.d.ts +1 -1
  86. package/lib/ui/Menu/Menu.js.map +1 -1
  87. package/lib/ui/Menu/MenuItem.d.ts +1 -1
  88. package/lib/ui/Menu/MoreActionsMenu.d.ts +1 -1
  89. package/lib/ui/Table/TableFilterBar/TableFilterBar.d.ts +2 -1
  90. package/lib/ui/Table/TableFilterBar/TableFilterItem.d.ts +2 -1
  91. package/lib/ui/TextField/SearchTextField.js.map +1 -1
  92. package/lib/{copy-to-clipboard.js → ui/clipboard.js} +1 -1
  93. package/lib/ui/clipboard.js.map +1 -0
  94. package/lib/ui/use-interval.js.map +1 -0
  95. package/lib/{use-is-date-in-past.js → ui/use-is-date-in-past.js} +1 -1
  96. package/lib/ui/use-is-date-in-past.js.map +1 -0
  97. package/lib/ui/use-toggle.js.map +1 -0
  98. package/lib/version.d.ts +2 -2
  99. package/lib/version.js +3 -1
  100. package/lib/version.js.map +1 -1
  101. package/package.json +21 -8
  102. package/src/elements.ts +27 -0
  103. package/src/hooks.ts +1 -0
  104. package/src/lib/{sort-by.ts → dates.ts} +1 -1
  105. package/src/lib/element.tsx +86 -0
  106. package/src/lib/index.ts +2 -2
  107. package/src/lib/{SeamProvider.tsx → seam/SeamProvider.tsx} +53 -46
  108. package/src/lib/seam/access-codes/use-access-codes.ts +2 -2
  109. package/src/lib/seam/components/AccessCodeDetails/AccessCodeDetails.element.ts +12 -0
  110. package/src/lib/{ui → seam/components}/AccessCodeDetails/AccessCodeDetails.tsx +9 -6
  111. package/src/lib/{ui → seam/components}/AccessCodeDetails/AccessCodeDevice.tsx +2 -2
  112. package/src/lib/seam/components/AccessCodeTable/AccessCodeTable.element.ts +12 -0
  113. package/src/lib/{ui → seam/components}/AccessCodeTable/AccessCodeTable.tsx +30 -11
  114. package/src/lib/{ui → seam/components}/AccessCodeTable/CodeDetails.tsx +2 -3
  115. package/src/lib/seam/components/DeviceDetails/DeviceDetails.element.ts +12 -0
  116. package/src/lib/{ui → seam/components}/DeviceDetails/DeviceDetails.tsx +22 -12
  117. package/src/lib/{ui → seam/components}/DeviceTable/DeviceHealthBar.tsx +1 -1
  118. package/src/lib/{ui → seam/components}/DeviceTable/DeviceRow.tsx +1 -1
  119. package/src/lib/seam/components/DeviceTable/DeviceTable.element.ts +11 -0
  120. package/src/lib/{ui → seam/components}/DeviceTable/DeviceTable.tsx +15 -12
  121. package/src/lib/{ui → seam/components}/SupportedDeviceTable/FilterCategoryMenu.tsx +26 -13
  122. package/src/lib/seam/components/SupportedDeviceTable/SupportedDeviceContent.tsx +120 -0
  123. package/src/lib/{ui → seam/components}/SupportedDeviceTable/SupportedDeviceFilterArea.tsx +43 -39
  124. package/src/lib/seam/components/SupportedDeviceTable/SupportedDeviceHeader.tsx +22 -0
  125. package/src/lib/seam/components/SupportedDeviceTable/SupportedDeviceRow.tsx +48 -0
  126. package/src/lib/seam/components/SupportedDeviceTable/SupportedDeviceTable.element.ts +11 -0
  127. package/src/lib/seam/components/SupportedDeviceTable/SupportedDeviceTable.tsx +48 -0
  128. package/src/lib/seam/components/SupportedDeviceTable/use-filtered-device-models.ts +35 -0
  129. package/src/lib/seam/components/elements.ts +5 -0
  130. package/src/lib/seam/device-models/use-device-models.ts +34 -0
  131. package/src/lib/seam/devices/use-devices.ts +3 -3
  132. package/src/lib/seam/devices/use-toggle-lock.ts +1 -2
  133. package/src/lib/seam/index.ts +1 -0
  134. package/src/lib/seam/use-seam-client.ts +1 -1
  135. package/src/lib/seam/use-seam-font.ts +5 -1
  136. package/src/lib/seam/use-seam-styles.ts +1 -1
  137. package/src/lib/ui/Menu/Menu.tsx +4 -4
  138. package/src/lib/ui/Menu/MenuItem.tsx +1 -1
  139. package/src/lib/ui/Menu/MoreActionsMenu.tsx +1 -1
  140. package/src/lib/ui/Table/TableFilterBar/TableFilterBar.tsx +2 -2
  141. package/src/lib/ui/Table/TableFilterBar/TableFilterItem.tsx +1 -1
  142. package/src/lib/ui/TextField/SearchTextField.tsx +3 -3
  143. package/src/lib/ui/clipboard.ts +3 -0
  144. package/src/lib/{use-interval.ts → ui/use-interval.ts} +1 -1
  145. package/src/lib/{use-is-date-in-past.ts → ui/use-is-date-in-past.ts} +1 -1
  146. package/src/lib/version.ts +3 -1
  147. package/src/styles/_access-code-table.scss +7 -0
  148. package/lib/SeamProvider.js.map +0 -1
  149. package/lib/capitalize.js.map +0 -1
  150. package/lib/copy-to-clipboard.js.map +0 -1
  151. package/lib/sort-by.js.map +0 -1
  152. package/lib/ui/AccessCodeDetails/AccessCodeDetails.js.map +0 -1
  153. package/lib/ui/AccessCodeDetails/AccessCodeDevice.js.map +0 -1
  154. package/lib/ui/AccessCodeTable/AccessCodeTable.d.ts +0 -6
  155. package/lib/ui/AccessCodeTable/AccessCodeTable.js +0 -69
  156. package/lib/ui/AccessCodeTable/AccessCodeTable.js.map +0 -1
  157. package/lib/ui/AccessCodeTable/CodeDetails.js.map +0 -1
  158. package/lib/ui/DeviceDetails/DeviceDetails.d.ts +0 -6
  159. package/lib/ui/DeviceDetails/DeviceDetails.js +0 -80
  160. package/lib/ui/DeviceDetails/DeviceDetails.js.map +0 -1
  161. package/lib/ui/DeviceDetails/DeviceModel.js.map +0 -1
  162. package/lib/ui/DeviceTable/DeviceHealthBar.js.map +0 -1
  163. package/lib/ui/DeviceTable/DeviceRow.js.map +0 -1
  164. package/lib/ui/DeviceTable/DeviceTable.d.ts +0 -8
  165. package/lib/ui/DeviceTable/DeviceTable.js +0 -65
  166. package/lib/ui/DeviceTable/DeviceTable.js.map +0 -1
  167. package/lib/ui/SupportedDeviceTable/FilterCategoryMenu.d.ts +0 -15
  168. package/lib/ui/SupportedDeviceTable/FilterCategoryMenu.js.map +0 -1
  169. package/lib/ui/SupportedDeviceTable/SupportedDeviceContent.d.ts +0 -4
  170. package/lib/ui/SupportedDeviceTable/SupportedDeviceContent.js +0 -46
  171. package/lib/ui/SupportedDeviceTable/SupportedDeviceContent.js.map +0 -1
  172. package/lib/ui/SupportedDeviceTable/SupportedDeviceFilterArea.d.ts +0 -11
  173. package/lib/ui/SupportedDeviceTable/SupportedDeviceFilterArea.js.map +0 -1
  174. package/lib/ui/SupportedDeviceTable/SupportedDeviceHeader.d.ts +0 -1
  175. package/lib/ui/SupportedDeviceTable/SupportedDeviceHeader.js +0 -5
  176. package/lib/ui/SupportedDeviceTable/SupportedDeviceHeader.js.map +0 -1
  177. package/lib/ui/SupportedDeviceTable/SupportedDeviceRow.d.ts +0 -5
  178. package/lib/ui/SupportedDeviceTable/SupportedDeviceRow.js +0 -12
  179. package/lib/ui/SupportedDeviceTable/SupportedDeviceRow.js.map +0 -1
  180. package/lib/ui/SupportedDeviceTable/SupportedDeviceTable.d.ts +0 -3
  181. package/lib/ui/SupportedDeviceTable/SupportedDeviceTable.js +0 -8
  182. package/lib/ui/SupportedDeviceTable/SupportedDeviceTable.js.map +0 -1
  183. package/lib/ui/SupportedDeviceTable/types.d.ts +0 -15
  184. package/lib/ui/SupportedDeviceTable/types.js +0 -2
  185. package/lib/ui/SupportedDeviceTable/types.js.map +0 -1
  186. package/lib/ui/index.js.map +0 -1
  187. package/lib/use-interval.js.map +0 -1
  188. package/lib/use-is-date-in-past.js.map +0 -1
  189. package/lib/use-toggle.js.map +0 -1
  190. package/src/lib/copy-to-clipboard.ts +0 -3
  191. package/src/lib/ui/SupportedDeviceTable/SupportedDeviceContent.tsx +0 -135
  192. package/src/lib/ui/SupportedDeviceTable/SupportedDeviceHeader.tsx +0 -14
  193. package/src/lib/ui/SupportedDeviceTable/SupportedDeviceRow.tsx +0 -35
  194. package/src/lib/ui/SupportedDeviceTable/SupportedDeviceTable.tsx +0 -16
  195. package/src/lib/ui/SupportedDeviceTable/types.ts +0 -16
  196. /package/lib/{ui → seam/components}/AccessCodeDetails/AccessCodeDevice.d.ts +0 -0
  197. /package/lib/{ui → seam/components}/AccessCodeTable/CodeDetails.d.ts +0 -0
  198. /package/lib/{ui → seam/components}/DeviceDetails/DeviceModel.d.ts +0 -0
  199. /package/lib/{ui → seam/components}/DeviceDetails/DeviceModel.js +0 -0
  200. /package/lib/{ui → seam/components}/index.d.ts +0 -0
  201. /package/lib/{ui → seam/components}/index.js +0 -0
  202. /package/lib/{capitalize.d.ts → strings.d.ts} +0 -0
  203. /package/lib/{copy-to-clipboard.d.ts → ui/clipboard.d.ts} +0 -0
  204. /package/lib/{use-interval.d.ts → ui/use-interval.d.ts} +0 -0
  205. /package/lib/{use-interval.js → ui/use-interval.js} +0 -0
  206. /package/lib/{use-is-date-in-past.d.ts → ui/use-is-date-in-past.d.ts} +0 -0
  207. /package/lib/{use-toggle.d.ts → ui/use-toggle.d.ts} +0 -0
  208. /package/lib/{use-toggle.js → ui/use-toggle.js} +0 -0
  209. /package/src/lib/{ui → seam/components}/DeviceDetails/DeviceModel.tsx +0 -0
  210. /package/src/lib/{ui → seam/components}/index.ts +0 -0
  211. /package/src/lib/{capitalize.ts → strings.ts} +0 -0
  212. /package/src/lib/{use-toggle.ts → ui/use-toggle.ts} +0 -0
@@ -1,20 +1,20 @@
1
- 'use client'
2
-
3
1
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
4
2
  import {
5
3
  createContext,
6
4
  type PropsWithChildren,
7
5
  useContext,
8
- useRef,
6
+ useMemo,
9
7
  } from 'react'
10
8
  import type { Seam, SeamClientOptions } from 'seamapi'
11
9
 
12
- import { useSeamFont } from './seam/use-seam-font.js'
13
- import { useSeamStyles } from './seam/use-seam-styles.js'
10
+ import { useSeamFont } from 'lib/seam/use-seam-font.js'
11
+ import { useSeamStyles } from 'lib/seam/use-seam-styles.js'
14
12
 
15
13
  declare global {
16
14
  // eslint-disable-next-line no-var
17
15
  var seam: SeamProviderProps | undefined
16
+ // eslint-disable-next-line no-var
17
+ var seamQueryClient: QueryClient | undefined
18
18
  }
19
19
 
20
20
  export interface SeamContext {
@@ -25,82 +25,90 @@ export interface SeamContext {
25
25
  clientSessionToken?: string | undefined
26
26
  }
27
27
 
28
- type SeamProviderProps = SeamProviderBaseProps &
29
- (
30
- | SeamProviderPropsWithClient
31
- | (SeamProviderPropsWithPublishableKey & AllowedSeamClientOptions)
32
- | (SeamProviderPropsWithClientSessionToken & AllowedSeamClientOptions)
33
- )
28
+ export type SeamProviderProps =
29
+ | SeamProviderPropsWithClient
30
+ | SeamProviderPropsWithPublishableKey
31
+ | SeamProviderPropsWithClientSessionToken
34
32
 
35
- interface SeamProviderPropsWithClient {
33
+ export interface SeamProviderPropsWithClient extends SeamProviderBaseProps {
36
34
  client: Seam
37
35
  }
38
36
 
39
- interface SeamProviderPropsWithPublishableKey {
37
+ export interface SeamProviderPropsWithPublishableKey
38
+ extends SeamProviderBaseProps,
39
+ AllowedSeamClientOptions {
40
40
  publishableKey: string
41
41
  userIdentifierKey?: string
42
42
  }
43
43
 
44
- interface SeamProviderPropsWithClientSessionToken {
44
+ export interface SeamProviderPropsWithClientSessionToken
45
+ extends SeamProviderBaseProps,
46
+ AllowedSeamClientOptions {
45
47
  clientSessionToken: string
46
48
  }
47
49
 
48
50
  interface SeamProviderBaseProps {
49
51
  disableCssInjection?: boolean | undefined
50
52
  disableFontInjection?: boolean | undefined
51
- useUnminifiedCss?: boolean | undefined
53
+ unminifiyCss?: boolean | undefined
54
+ queryClient?: QueryClient | undefined
52
55
  }
53
56
 
54
57
  type AllowedSeamClientOptions = Pick<SeamClientOptions, 'endpoint'>
55
58
 
59
+ const defaultQueryClient = new QueryClient()
60
+
56
61
  export function SeamProvider({
57
62
  children,
58
63
  disableCssInjection = false,
59
64
  disableFontInjection = false,
60
- useUnminifiedCss = false,
65
+ unminifiyCss = false,
66
+ queryClient,
61
67
  ...props
62
68
  }: PropsWithChildren<SeamProviderProps>): JSX.Element {
63
- const { Provider } = seamContext
64
-
65
- const queryClientRef = useRef(new QueryClient())
69
+ useSeamStyles({ disabled: disableCssInjection, unminified: unminifiyCss })
70
+ useSeamFont({ disabled: disableFontInjection })
66
71
 
67
- const contextRef = useRef(createSeamContextValue(props))
68
- if (
69
- contextRef.current.client == null &&
70
- contextRef.current.publishableKey == null &&
71
- contextRef.current.clientSessionToken == null
72
- ) {
73
- contextRef.current = defaultSeamContextValue
74
- }
72
+ const value = useMemo(() => {
73
+ const context = createSeamContextValue(props)
74
+ if (
75
+ context.client == null &&
76
+ context.publishableKey == null &&
77
+ context.clientSessionToken == null
78
+ ) {
79
+ return defaultSeamContextValue
80
+ }
81
+ return context
82
+ }, [props])
75
83
 
76
84
  if (
77
- contextRef.current.client == null &&
78
- contextRef.current.publishableKey == null &&
79
- contextRef.current.clientSessionToken == null
85
+ value.client == null &&
86
+ value.publishableKey == null &&
87
+ value.clientSessionToken == null
80
88
  ) {
81
89
  throw new Error(
82
- `Must provide either a Seam client, clientSessionToken or a publishableKey.`
90
+ `Must provide either a Seam client, clientSessionToken, or a publishableKey.`
83
91
  )
84
92
  }
85
93
 
86
- useSeamStyles({ disabled: disableCssInjection, unminified: useUnminifiedCss })
87
- useSeamFont({ disabled: disableFontInjection })
94
+ const { Provider } = seamContext
88
95
 
89
96
  return (
90
97
  <div className='seam-components'>
91
- <QueryClientProvider client={queryClientRef.current}>
92
- <Provider value={{ ...contextRef.current }}>{children}</Provider>
98
+ <QueryClientProvider
99
+ client={queryClient ?? globalThis.seamQueryClient ?? defaultQueryClient}
100
+ >
101
+ <Provider value={value}>{children}</Provider>
93
102
  </QueryClientProvider>
94
103
  </div>
95
104
  )
96
105
  }
97
106
 
98
107
  const createDefaultSeamContextValue = (): SeamContext => {
99
- if (globalThis.seam == null) {
100
- return { client: null }
101
- }
102
-
103
108
  try {
109
+ if (globalThis.seam == null) {
110
+ return { client: null }
111
+ }
104
112
  return createSeamContextValue(globalThis.seam)
105
113
  } catch (err) {
106
114
  // eslint-disable-next-line no-console
@@ -133,7 +141,7 @@ const createSeamContextValue = (options: SeamProviderProps): SeamContext => {
133
141
  }
134
142
  }
135
143
 
136
- throw new Error('Invalid SeamProvider options')
144
+ return { client: null }
137
145
  }
138
146
 
139
147
  const defaultSeamContextValue = createDefaultSeamContextValue()
@@ -199,12 +207,11 @@ const isSeamProviderPropsWithClientSessionToken = (
199
207
  throw new Error('Cannot provide a Seam client along with other options.')
200
208
  }
201
209
 
202
- // No reason to ban this behavior, but it's unnecessary.
203
- // if ('publishableKey' in props && props.publishableKey != null) {
204
- // throw new Error(
205
- // 'Cannot provide both a clientSessionToken and a publishableKey .'
206
- // )
207
- // }
210
+ if ('publishableKey' in props && props.publishableKey != null) {
211
+ throw new Error(
212
+ 'Cannot provide both a clientSessionToken and a publishableKey.'
213
+ )
214
+ }
208
215
 
209
216
  if ('userIdentifierKey' in props && props.userIdentifierKey != null) {
210
217
  throw new Error('Cannot use a userIdentifierKey with a clientSessionToken.')
@@ -6,9 +6,9 @@ import type {
6
6
  SeamError,
7
7
  } from 'seamapi'
8
8
 
9
+ import { compareByCreatedAtDesc } from 'lib/dates.js'
9
10
  import { useSeamClient } from 'lib/seam/use-seam-client.js'
10
11
  import type { UseSeamQueryResult } from 'lib/seam/use-seam-query-result.js'
11
- import { byCreatedAt } from 'lib/sort-by.js'
12
12
 
13
13
  export type UseAccessCodesParams = AccessCodesListRequest | string
14
14
  export type UseAccessCodesData = AccessCode[]
@@ -29,7 +29,7 @@ export function useAccessCodes(
29
29
  queryFn: async () => {
30
30
  if (client == null) return []
31
31
  const accessCodes = await client?.accessCodes.list(normalizedParams)
32
- return accessCodes.sort(byCreatedAt)
32
+ return accessCodes.sort(compareByCreatedAtDesc)
33
33
  },
34
34
  })
35
35
 
@@ -0,0 +1,12 @@
1
+ import type { ElementProps } from 'lib/element.js'
2
+
3
+ import type { AccessCodeDetailsProps } from './AccessCodeDetails.js'
4
+
5
+ export const name = 'seam-access-code-details'
6
+
7
+ export const props: ElementProps<AccessCodeDetailsProps> = {
8
+ accessCodeId: 'string',
9
+ onBack: 'function',
10
+ }
11
+
12
+ export { AccessCodeDetails as Component } from './AccessCodeDetails.js'
@@ -1,22 +1,24 @@
1
+ import classNames from 'classnames'
1
2
  import { DateTime } from 'luxon'
2
3
  import { useState } from 'react'
3
4
  import type { AccessCode } from 'seamapi'
4
5
 
5
- import { useAccessCode } from 'lib/index.js'
6
-
7
- import { AccessCodeDevice } from 'lib/ui/AccessCodeDetails/AccessCodeDevice.js'
8
- import { DeviceDetails } from 'lib/ui/DeviceDetails/DeviceDetails.js'
6
+ import { useAccessCode } from 'lib/seam/access-codes/use-access-code.js'
7
+ import { AccessCodeDevice } from 'lib/seam/components/AccessCodeDetails/AccessCodeDevice.js'
8
+ import { DeviceDetails } from 'lib/seam/components/DeviceDetails/DeviceDetails.js'
9
9
  import { ContentHeader } from 'lib/ui/layout/ContentHeader.js'
10
- import { useIsDateInPast } from 'lib/use-is-date-in-past.js'
10
+ import { useIsDateInPast } from 'lib/ui/use-is-date-in-past.js'
11
11
 
12
12
  export interface AccessCodeDetailsProps {
13
13
  accessCodeId: string
14
14
  onBack?: () => void
15
+ className?: string
15
16
  }
16
17
 
17
18
  export function AccessCodeDetails({
18
19
  accessCodeId,
19
20
  onBack,
21
+ className,
20
22
  }: AccessCodeDetailsProps): JSX.Element | null {
21
23
  const { accessCode } = useAccessCode(accessCodeId)
22
24
  const [selectedDeviceId, selectDevice] = useState<string | null>(null)
@@ -30,6 +32,7 @@ export function AccessCodeDetails({
30
32
  if (selectedDeviceId != null) {
31
33
  return (
32
34
  <DeviceDetails
35
+ className={className}
33
36
  deviceId={selectedDeviceId}
34
37
  onBack={() => {
35
38
  selectDevice(null)
@@ -39,7 +42,7 @@ export function AccessCodeDetails({
39
42
  }
40
43
 
41
44
  return (
42
- <div className='seam-access-code-details'>
45
+ <div className={classNames('seam-access-code-details', className)}>
43
46
  <ContentHeader title='Access code' onBack={onBack} />
44
47
  <div className='seam-summary'>
45
48
  <div className='seam-top'>
@@ -1,11 +1,11 @@
1
1
  import type { LockDevice } from 'seamapi'
2
2
 
3
+ import { getDeviceModel } from 'lib/seam/components/DeviceDetails/DeviceModel.js'
3
4
  import { isLockDevice } from 'lib/seam/devices/types.js'
4
5
  import { useDevice } from 'lib/seam/devices/use-device.js'
5
6
  import { useToggleLock } from 'lib/seam/devices/use-toggle-lock.js'
6
7
  import { Button } from 'lib/ui/Button.js'
7
8
  import { DeviceImage } from 'lib/ui/device/DeviceImage.js'
8
- import { getDeviceModel } from 'lib/ui/DeviceDetails/DeviceModel.js'
9
9
  import { TextButton } from 'lib/ui/TextButton.js'
10
10
 
11
11
  export function AccessCodeDevice({
@@ -27,7 +27,7 @@ export function AccessCodeDevice({
27
27
  function LockDeviceDetails(props: {
28
28
  device: LockDevice
29
29
  onSelectDevice: (deviceId: string) => void
30
- }) {
30
+ }): JSX.Element {
31
31
  const { device, onSelectDevice } = props
32
32
  const toggleLock = useToggleLock(device)
33
33
  const model = getDeviceModel(device)
@@ -0,0 +1,12 @@
1
+ import type { ElementProps } from 'lib/element.js'
2
+
3
+ import type { AccessCodeTableProps } from './AccessCodeTable.js'
4
+
5
+ export const name = 'seam-access-code-table'
6
+
7
+ export const props: ElementProps<AccessCodeTableProps> = {
8
+ deviceId: 'string',
9
+ onBack: 'function',
10
+ }
11
+
12
+ export { AccessCodeTable as Component } from './AccessCodeTable.js'
@@ -1,15 +1,17 @@
1
+ import classNames from 'classnames'
1
2
  import { useState } from 'react'
2
3
  import type { AccessCode } from 'seamapi'
3
4
 
4
- import { copyToClipboard } from 'lib/copy-to-clipboard.js'
5
5
  import { AccessCodeKeyIcon } from 'lib/icons/AccessCodeKey.js'
6
6
  import { CopyIcon } from 'lib/icons/Copy.js'
7
+ import { ExclamationCircleOutlineIcon } from 'lib/icons/ExclamationCircleOutline.js'
7
8
  import {
8
9
  useAccessCodes,
9
10
  type UseAccessCodesData,
10
11
  } from 'lib/seam/access-codes/use-access-codes.js'
11
- import { AccessCodeDetails } from 'lib/ui/AccessCodeDetails/AccessCodeDetails.js'
12
- import { CodeDetails } from 'lib/ui/AccessCodeTable/CodeDetails.js'
12
+ import { AccessCodeDetails } from 'lib/seam/components/AccessCodeDetails/AccessCodeDetails.js'
13
+ import { CodeDetails } from 'lib/seam/components/AccessCodeTable/CodeDetails.js'
14
+ import { copyToClipboard } from 'lib/ui/clipboard.js'
13
15
  import { ContentHeader } from 'lib/ui/layout/ContentHeader.js'
14
16
  import { MenuItem } from 'lib/ui/Menu/MenuItem.js'
15
17
  import { MoreActionsMenu } from 'lib/ui/Menu/MoreActionsMenu.js'
@@ -26,15 +28,17 @@ import { Title } from 'lib/ui/typography/Title.js'
26
28
  export interface AccessCodeTableProps {
27
29
  deviceId: string
28
30
  onBack?: () => void
31
+ className?: string
29
32
  }
30
33
 
31
- export function AccessCodeTable(
32
- props: AccessCodeTableProps
33
- ): JSX.Element | null {
34
+ export function AccessCodeTable({
35
+ deviceId,
36
+ onBack,
37
+ className,
38
+ }: AccessCodeTableProps): JSX.Element | null {
34
39
  const { accessCodes } = useAccessCodes({
35
- device_id: props.deviceId,
40
+ device_id: deviceId,
36
41
  })
37
- const { onBack } = props
38
42
 
39
43
  const [selectedAccessCode, selectAccessCode] = useState<AccessCode | null>(
40
44
  null
@@ -44,6 +48,7 @@ export function AccessCodeTable(
44
48
  if (selectedAccessCode != null) {
45
49
  return (
46
50
  <AccessCodeDetails
51
+ className={className}
47
52
  accessCodeId={selectedAccessCode.access_code_id}
48
53
  onBack={() => {
49
54
  selectAccessCode(null)
@@ -67,7 +72,7 @@ export function AccessCodeTable(
67
72
  const accessCodeCount = accessCodes.length
68
73
 
69
74
  return (
70
- <div className='seam-access-code-table'>
75
+ <div className={classNames('seam-access-code-table', className)}>
71
76
  <ContentHeader onBack={onBack} />
72
77
  <TableHeader>
73
78
  <TableTitle>
@@ -89,7 +94,7 @@ export function AccessCodeTable(
89
94
  function Body(props: {
90
95
  accessCodes: Array<UseAccessCodesData[number]>
91
96
  selectAccessCode: (accessCode: AccessCode) => void
92
- }) {
97
+ }): JSX.Element {
93
98
  const { accessCodes, selectAccessCode } = props
94
99
 
95
100
  if (accessCodes.length === 0) {
@@ -114,8 +119,15 @@ function Body(props: {
114
119
  function AccessCodeRow(props: {
115
120
  accessCode: UseAccessCodesData[number]
116
121
  onClick: () => void
117
- }) {
122
+ }): JSX.Element {
118
123
  const { onClick, accessCode } = props
124
+
125
+ const errorCount = accessCode.errors?.length ?? 0
126
+ const isPlural = errorCount === 0 || errorCount > 1
127
+ const issueIconTitle = isPlural
128
+ ? `${errorCount} ${t.codeIssues}`
129
+ : `${errorCount} ${t.codeIssue}`
130
+
119
131
  return (
120
132
  <TableRow key={accessCode.access_code_id} onClick={onClick}>
121
133
  <TableCell className='seam-icon-cell'>
@@ -128,6 +140,11 @@ function AccessCodeRow(props: {
128
140
  <CodeDetails accessCode={accessCode} />
129
141
  </TableCell>
130
142
  <TableCell className='seam-action-cell'>
143
+ {errorCount > 0 && (
144
+ <div className='seam-code-issue-icon-wrap' title={issueIconTitle}>
145
+ <ExclamationCircleOutlineIcon />
146
+ </div>
147
+ )}
131
148
  <MoreActionsMenu
132
149
  menuProps={{
133
150
  backgroundProps: {
@@ -157,4 +174,6 @@ const t = {
157
174
  accessCodes: 'Access Codes',
158
175
  copyCode: 'Copy code',
159
176
  noAccessCodesMessage: 'Sorry, no access codes were found',
177
+ codeIssue: 'code issue',
178
+ codeIssues: 'code issues',
160
179
  }
@@ -1,10 +1,9 @@
1
1
  import { DateTime } from 'luxon'
2
2
  import type { AccessCode } from 'seamapi'
3
3
 
4
- import { useDevice } from 'lib/index.js'
5
-
4
+ import { useDevice } from 'lib/seam/devices/use-device.js'
6
5
  import { DotDivider } from 'lib/ui/layout/DotDivider.js'
7
- import { useIsDateInPast } from 'lib/use-is-date-in-past.js'
6
+ import { useIsDateInPast } from 'lib/ui/use-is-date-in-past.js'
8
7
 
9
8
  export function CodeDetails(props: { accessCode: AccessCode }): JSX.Element {
10
9
  const { accessCode } = props
@@ -0,0 +1,12 @@
1
+ import type { ElementProps } from 'lib/element.js'
2
+
3
+ import type { DeviceDetailsProps } from './DeviceDetails.js'
4
+
5
+ export const name = 'seam-device-details'
6
+
7
+ export const props: ElementProps<DeviceDetailsProps> = {
8
+ deviceId: 'string',
9
+ onBack: 'function',
10
+ }
11
+
12
+ export { DeviceDetails as Component } from './DeviceDetails.js'
@@ -1,29 +1,32 @@
1
+ import classNames from 'classnames'
1
2
  import type { LockDevice } from 'seamapi'
2
3
 
3
- import { useDevice } from 'lib/index.js'
4
-
5
4
  import { ChevronRightIcon } from 'lib/icons/ChevronRight.js'
6
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'
7
8
  import { isLockDevice } from 'lib/seam/devices/types.js'
9
+ import { useDevice } from 'lib/seam/devices/use-device.js'
8
10
  import { useToggleLock } from 'lib/seam/devices/use-toggle-lock.js'
9
- import { AccessCodeTable } from 'lib/ui/AccessCodeTable/AccessCodeTable.js'
10
11
  import { Alerts } from 'lib/ui/Alert/Alerts.js'
11
12
  import { Button } from 'lib/ui/Button.js'
12
13
  import { BatteryStatus } from 'lib/ui/device/BatteryStatus.js'
13
14
  import { DeviceImage } from 'lib/ui/device/DeviceImage.js'
14
15
  import { OnlineStatus } from 'lib/ui/device/OnlineStatus.js'
15
- import { DeviceModel } from 'lib/ui/DeviceDetails/DeviceModel.js'
16
16
  import { ContentHeader } from 'lib/ui/layout/ContentHeader.js'
17
- import { useToggle } from 'lib/use-toggle.js'
17
+ import { useToggle } from 'lib/ui/use-toggle.js'
18
18
 
19
19
  export interface DeviceDetailsProps {
20
20
  deviceId: string
21
21
  onBack?: () => void
22
+ className?: string
22
23
  }
23
24
 
24
- export function DeviceDetails(props: DeviceDetailsProps): JSX.Element | null {
25
- const { deviceId, onBack } = props
26
-
25
+ export function DeviceDetails({
26
+ deviceId,
27
+ onBack,
28
+ className,
29
+ }: DeviceDetailsProps): JSX.Element | null {
27
30
  const { device } = useDevice({
28
31
  device_id: deviceId,
29
32
  })
@@ -36,11 +39,17 @@ export function DeviceDetails(props: DeviceDetailsProps): JSX.Element | null {
36
39
  return null
37
40
  }
38
41
 
39
- return <LockDeviceDetails device={device} onBack={onBack} />
42
+ return (
43
+ <LockDeviceDetails className={className} device={device} onBack={onBack} />
44
+ )
40
45
  }
41
46
 
42
- function LockDeviceDetails(props: { device: LockDevice; onBack?: () => void }) {
43
- const { device, onBack } = props
47
+ function LockDeviceDetails(props: {
48
+ device: LockDevice
49
+ onBack?: () => void
50
+ className?: string
51
+ }): JSX.Element | null {
52
+ const { device, onBack, className } = props
44
53
 
45
54
  const [accessCodesOpen, toggleAccessCodesOpen] = useToggle()
46
55
  const toggleLock = useToggleLock(device)
@@ -63,6 +72,7 @@ function LockDeviceDetails(props: { device: LockDevice; onBack?: () => void }) {
63
72
  if (accessCodesOpen) {
64
73
  return (
65
74
  <AccessCodeTable
75
+ className={className}
66
76
  deviceId={device.device_id}
67
77
  onBack={toggleAccessCodesOpen}
68
78
  />
@@ -81,7 +91,7 @@ function LockDeviceDetails(props: { device: LockDevice; onBack?: () => void }) {
81
91
  ]
82
92
 
83
93
  return (
84
- <div className='seam-device-details'>
94
+ <div className={classNames('seam-device-details', className)}>
85
95
  <ContentHeader title='Device' onBack={onBack} />
86
96
  <div className='seam-body'>
87
97
  <div className='seam-summary'>
@@ -16,7 +16,7 @@ export function DeviceHealthBar({
16
16
  devices,
17
17
  filter,
18
18
  onFilterSelect,
19
- }: DeviceHealthBarProps) {
19
+ }: DeviceHealthBarProps): JSX.Element {
20
20
  const erroredDevices = devices.filter((device) => device.errors.length > 0)
21
21
  const issueCount = erroredDevices.length
22
22
 
@@ -1,3 +1,4 @@
1
+ import { getDeviceModel } from 'lib/seam/components/DeviceDetails/DeviceModel.js'
1
2
  import { isLockDevice } from 'lib/seam/devices/types.js'
2
3
  import type {
3
4
  UseDevicesData,
@@ -7,7 +8,6 @@ import { BatteryStatus } from 'lib/ui/device/BatteryStatus.js'
7
8
  import { DeviceImage } from 'lib/ui/device/DeviceImage.js'
8
9
  import { LockStatus } from 'lib/ui/device/LockStatus.js'
9
10
  import { OnlineStatus } from 'lib/ui/device/OnlineStatus.js'
10
- import { getDeviceModel } from 'lib/ui/DeviceDetails/DeviceModel.js'
11
11
  import { TableCell } from 'lib/ui/Table/TableCell.js'
12
12
  import { TableRow } from 'lib/ui/Table/TableRow.js'
13
13
  import { Title } from 'lib/ui/typography/Title.js'
@@ -0,0 +1,11 @@
1
+ import type { ElementProps } from 'lib/element.js'
2
+
3
+ import type { DeviceTableProps } from './DeviceTable.js'
4
+
5
+ export const name = 'seam-device-table'
6
+
7
+ export const props: ElementProps<DeviceTableProps> = {
8
+ onBack: 'function',
9
+ }
10
+
11
+ export { DeviceTable as Component } from './DeviceTable.js'
@@ -1,16 +1,17 @@
1
+ import classNames from 'classnames'
1
2
  import { useState } from 'react'
2
3
 
4
+ import { DeviceDetails } from 'lib/seam/components/DeviceDetails/DeviceDetails.js'
5
+ import {
6
+ type DeviceFilter,
7
+ DeviceHealthBar,
8
+ } from 'lib/seam/components/DeviceTable/DeviceHealthBar.js'
9
+ import { DeviceRow } from 'lib/seam/components/DeviceTable/DeviceRow.js'
3
10
  import {
4
11
  useDevices,
5
12
  type UseDevicesData,
6
13
  type UseDevicesParams,
7
14
  } from 'lib/seam/devices/use-devices.js'
8
- import { DeviceDetails } from 'lib/ui/DeviceDetails/DeviceDetails.js'
9
- import {
10
- type DeviceFilter,
11
- DeviceHealthBar,
12
- } from 'lib/ui/DeviceTable/DeviceHealthBar.js'
13
- import { DeviceRow } from 'lib/ui/DeviceTable/DeviceRow.js'
14
15
  import { ContentHeader } from 'lib/ui/layout/ContentHeader.js'
15
16
  import { EmptyPlaceholder } from 'lib/ui/Table/EmptyPlaceholder.js'
16
17
  import { TableBody } from 'lib/ui/Table/TableBody.js'
@@ -23,13 +24,14 @@ export type DeviceTableProps = Props & UseDevicesParams
23
24
 
24
25
  interface Props {
25
26
  onBack?: () => void
27
+ className?: string
26
28
  }
27
29
 
28
30
  export function DeviceTable({
29
31
  onBack,
30
- ...props
32
+ className,
31
33
  }: DeviceTableProps): JSX.Element | null {
32
- const { devices, isLoading, isError, error } = useDevices(props)
34
+ const { devices, isLoading, isError, error } = useDevices()
33
35
 
34
36
  const [selectedDeviceId, selectDevice] = useState<string | null>(null)
35
37
  const [searchTerm, setSearchTerm] = useState('')
@@ -37,6 +39,7 @@ export function DeviceTable({
37
39
  if (selectedDeviceId != null) {
38
40
  return (
39
41
  <DeviceDetails
42
+ className={className}
40
43
  deviceId={selectedDeviceId}
41
44
  onBack={() => {
42
45
  selectDevice(null)
@@ -46,11 +49,11 @@ export function DeviceTable({
46
49
  }
47
50
 
48
51
  if (isLoading) {
49
- return <p>...</p>
52
+ return <p className={className}>...</p>
50
53
  }
51
54
 
52
55
  if (isError) {
53
- return <p>{error?.message}</p>
56
+ return <p className={className}>{error?.message}</p>
54
57
  }
55
58
 
56
59
  if (devices == null) {
@@ -68,7 +71,7 @@ export function DeviceTable({
68
71
  })
69
72
 
70
73
  return (
71
- <div className='seam-device-table'>
74
+ <div className={classNames('seam-device-table', className)}>
72
75
  <ContentHeader onBack={onBack} />
73
76
  <TableHeader>
74
77
  <TableTitle>
@@ -90,7 +93,7 @@ export function DeviceTable({
90
93
  function Body(props: {
91
94
  devices: Array<UseDevicesData[number]>
92
95
  selectDevice: (id: string) => void
93
- }) {
96
+ }): JSX.Element {
94
97
  const { devices, selectDevice } = props
95
98
  const [filter, setFilter] = useState<DeviceFilter | null>(null)
96
99