@seamapi/react 1.35.0 → 1.37.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.
- package/README.md +1 -1
- package/dist/elements.js +4501 -4476
- package/dist/elements.js.map +1 -1
- package/lib/seam/SeamProvider.js +16 -12
- package/lib/seam/SeamProvider.js.map +1 -1
- package/lib/seam/access-codes/use-create-access-code.js +3 -4
- package/lib/seam/access-codes/use-create-access-code.js.map +1 -1
- package/lib/seam/components/AccessCodeTable/AccessCodeTable.d.ts +2 -1
- package/lib/seam/components/AccessCodeTable/AccessCodeTable.js +2 -2
- package/lib/seam/components/AccessCodeTable/AccessCodeTable.js.map +1 -1
- package/lib/seam/components/DeviceTable/DeviceTable.d.ts +2 -1
- package/lib/seam/components/DeviceTable/DeviceTable.js +2 -2
- package/lib/seam/components/DeviceTable/DeviceTable.js.map +1 -1
- package/lib/seam/connect-webviews/use-create-connect-webview.js +3 -4
- package/lib/seam/connect-webviews/use-create-connect-webview.js.map +1 -1
- package/lib/seam/devices/use-toggle-lock.js +3 -4
- package/lib/seam/devices/use-toggle-lock.js.map +1 -1
- package/lib/seam/thermostats/climate-setting-schedules/use-climate-setting-schedules.d.ts +5 -0
- package/lib/seam/thermostats/climate-setting-schedules/use-climate-setting-schedules.js +29 -0
- package/lib/seam/thermostats/climate-setting-schedules/use-climate-setting-schedules.js.map +1 -0
- package/lib/seam/use-seam-client.d.ts +3 -0
- package/lib/seam/use-seam-client.js +12 -0
- package/lib/seam/use-seam-client.js.map +1 -1
- package/lib/ui/RadioField/RadioField.d.ts +1 -1
- package/lib/ui/RadioField/RadioField.js +2 -2
- package/lib/ui/RadioField/RadioField.js.map +1 -1
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +2 -2
- package/src/elements.ts +1 -1
- package/src/lib/seam/SeamProvider.tsx +27 -16
- package/src/lib/seam/access-codes/use-create-access-code.ts +2 -5
- package/src/lib/seam/components/AccessCodeTable/AccessCodeTable.tsx +10 -3
- package/src/lib/seam/components/DeviceTable/DeviceTable.tsx +9 -3
- package/src/lib/seam/connect-webviews/use-create-connect-webview.ts +2 -5
- package/src/lib/seam/devices/use-toggle-lock.ts +2 -5
- package/src/lib/seam/thermostats/climate-setting-schedules/use-climate-setting-schedules.ts +53 -0
- package/src/lib/seam/use-seam-client.ts +15 -0
- package/src/lib/ui/RadioField/RadioField.tsx +6 -5
- package/src/lib/version.ts +1 -1
|
@@ -34,6 +34,7 @@ export interface DeviceTableProps {
|
|
|
34
34
|
onDeviceClick?: (deviceId: string) => void
|
|
35
35
|
preventDefaultOnDeviceClick?: boolean
|
|
36
36
|
onBack?: () => void
|
|
37
|
+
title?: string | null
|
|
37
38
|
className?: string
|
|
38
39
|
}
|
|
39
40
|
|
|
@@ -56,6 +57,7 @@ export function DeviceTable({
|
|
|
56
57
|
onBack,
|
|
57
58
|
deviceFilter = defaultDeviceFilter,
|
|
58
59
|
deviceComparator = compareByCreatedAtDesc,
|
|
60
|
+
title = t.devices,
|
|
59
61
|
className,
|
|
60
62
|
}: DeviceTableProps = {}): JSX.Element {
|
|
61
63
|
const { devices, isLoading, isError, error } = useDevices({
|
|
@@ -109,9 +111,13 @@ export function DeviceTable({
|
|
|
109
111
|
<div className={classNames('seam-device-table', className)}>
|
|
110
112
|
<ContentHeader onBack={onBack} />
|
|
111
113
|
<TableHeader>
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
114
|
+
{title != null ? (
|
|
115
|
+
<TableTitle>
|
|
116
|
+
{title ?? t.devices} <Caption>({filteredDevices.length})</Caption>
|
|
117
|
+
</TableTitle>
|
|
118
|
+
) : (
|
|
119
|
+
<div className='seam-fragment' />
|
|
120
|
+
)}
|
|
115
121
|
{!disableSearch && (
|
|
116
122
|
<SearchTextField
|
|
117
123
|
value={searchInputValue}
|
|
@@ -6,7 +6,7 @@ import type {
|
|
|
6
6
|
SeamError,
|
|
7
7
|
} from 'seamapi'
|
|
8
8
|
|
|
9
|
-
import { useSeamClient } from 'lib/seam/use-seam-client.js'
|
|
9
|
+
import { NullSeamClientError, useSeamClient } from 'lib/seam/use-seam-client.js'
|
|
10
10
|
|
|
11
11
|
export interface UseCreateConnectWebviewParams {
|
|
12
12
|
willNavigateToWebview?: boolean
|
|
@@ -32,10 +32,7 @@ export function useCreateConnectWebview({
|
|
|
32
32
|
mutationFn: async (
|
|
33
33
|
mutationParams: UseCreateConnectWebviewMutationParams
|
|
34
34
|
) => {
|
|
35
|
-
if (client
|
|
36
|
-
throw new Error('Missing seam client')
|
|
37
|
-
}
|
|
38
|
-
|
|
35
|
+
if (client === null) throw new NullSeamClientError()
|
|
39
36
|
return await client.connectWebviews.create(mutationParams)
|
|
40
37
|
},
|
|
41
38
|
onSuccess: ({ url }) => {
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
type SeamError,
|
|
12
12
|
} from 'seamapi'
|
|
13
13
|
|
|
14
|
-
import { useSeamClient } from 'lib/seam/use-seam-client.js'
|
|
14
|
+
import { NullSeamClientError, useSeamClient } from 'lib/seam/use-seam-client.js'
|
|
15
15
|
|
|
16
16
|
export function useToggleLock({
|
|
17
17
|
device_id: deviceId,
|
|
@@ -26,10 +26,7 @@ export function useToggleLock({
|
|
|
26
26
|
|
|
27
27
|
return useMutation<{ actionAttempt: ActionAttempt }, SeamError>({
|
|
28
28
|
mutationFn: async () => {
|
|
29
|
-
if (client
|
|
30
|
-
throw new Error('Missing seam client')
|
|
31
|
-
}
|
|
32
|
-
|
|
29
|
+
if (client === null) throw new NullSeamClientError()
|
|
33
30
|
const toggle = locked ? client.locks.unlockDoor : client.locks.lockDoor
|
|
34
31
|
return await toggle(deviceId)
|
|
35
32
|
},
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
|
2
|
+
import type {
|
|
3
|
+
ClimateSettingSchedule,
|
|
4
|
+
ClimateSettingSchedulesListRequest,
|
|
5
|
+
ClimateSettingSchedulesListResponse,
|
|
6
|
+
SeamError,
|
|
7
|
+
} from 'seamapi'
|
|
8
|
+
|
|
9
|
+
import { useSeamClient } from 'lib/seam/use-seam-client.js'
|
|
10
|
+
import type { UseSeamQueryResult } from 'lib/seam/use-seam-query-result.js'
|
|
11
|
+
|
|
12
|
+
export type UseClimateSettingSchedulesParams =
|
|
13
|
+
ClimateSettingSchedulesListRequest
|
|
14
|
+
export type UseClimateSettingSchedulesData = ClimateSettingSchedule[]
|
|
15
|
+
|
|
16
|
+
export function useClimateSettingSchedules(
|
|
17
|
+
params: UseClimateSettingSchedulesParams
|
|
18
|
+
): UseSeamQueryResult<
|
|
19
|
+
'climateSettingSchedules',
|
|
20
|
+
UseClimateSettingSchedulesData
|
|
21
|
+
> {
|
|
22
|
+
const { client } = useSeamClient()
|
|
23
|
+
const queryClient = useQueryClient()
|
|
24
|
+
|
|
25
|
+
const { data, ...rest } = useQuery<
|
|
26
|
+
ClimateSettingSchedulesListResponse['climate_setting_schedules'],
|
|
27
|
+
SeamError
|
|
28
|
+
>({
|
|
29
|
+
enabled: client != null,
|
|
30
|
+
queryKey: ['thermostats', 'climate_setting_schedules', 'list', params],
|
|
31
|
+
queryFn: async () => {
|
|
32
|
+
if (client == null) return []
|
|
33
|
+
return await client.thermostats.climateSettingSchedules.list(params)
|
|
34
|
+
},
|
|
35
|
+
onSuccess: (schedules) => {
|
|
36
|
+
// Prime cache for each schedule.
|
|
37
|
+
for (const schedule of schedules) {
|
|
38
|
+
queryClient.setQueryData(
|
|
39
|
+
[
|
|
40
|
+
'climate_setting_schedules',
|
|
41
|
+
'get',
|
|
42
|
+
{
|
|
43
|
+
climate_setting_schedule_id: schedule.climate_setting_schedule_id,
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
schedule
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
return { ...rest, climateSettingSchedules: data }
|
|
53
|
+
}
|
|
@@ -71,6 +71,21 @@ export function useSeamClient(): {
|
|
|
71
71
|
return { client: data ?? null, isLoading, isError, error }
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
export class NullSeamClientError extends Error {
|
|
75
|
+
constructor() {
|
|
76
|
+
super(
|
|
77
|
+
[
|
|
78
|
+
'Attempted to use a null Seam client.',
|
|
79
|
+
'Either a hook using useSeamClient was called outside of a SeamProvider,',
|
|
80
|
+
'or there was an error when creating the Seam client in useSeamClient,',
|
|
81
|
+
'or useSeamClient is still loading the client.',
|
|
82
|
+
].join(' ')
|
|
83
|
+
)
|
|
84
|
+
this.name = this.constructor.name
|
|
85
|
+
Error.captureStackTrace(this, this.constructor)
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
74
89
|
function useUserIdentifierKeyOrFingerprint(
|
|
75
90
|
userIdentifierKey: string | undefined
|
|
76
91
|
): string {
|
|
@@ -14,11 +14,12 @@ interface RadioOption<Value> {
|
|
|
14
14
|
value: Value
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
type RadioFieldContext<Value extends string> =
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
type RadioFieldContext<Value extends string> = Omit<
|
|
18
|
+
RadioFieldProps<Value>,
|
|
19
|
+
'options'
|
|
20
|
+
> | null
|
|
20
21
|
|
|
21
|
-
const radioFieldContext = createContext<RadioFieldContext<any>>(
|
|
22
|
+
const radioFieldContext = createContext<RadioFieldContext<any>>(null)
|
|
22
23
|
|
|
23
24
|
export function RadioField<Value extends string>({
|
|
24
25
|
value,
|
|
@@ -48,7 +49,7 @@ export function useRadioField<Value extends string>(): NonNullable<
|
|
|
48
49
|
RadioFieldContext<Value>
|
|
49
50
|
> {
|
|
50
51
|
const context = useContext<RadioFieldContext<Value>>(radioFieldContext)
|
|
51
|
-
if (context ===
|
|
52
|
+
if (context === null) {
|
|
52
53
|
throw new Error('useRadioField must be used within a <RadioField/>')
|
|
53
54
|
}
|
|
54
55
|
return context
|
package/src/lib/version.ts
CHANGED