@seamapi/react 2.1.0 → 2.1.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.
- package/README.md +3 -3
- package/dist/elements.js +633 -593
- package/dist/elements.js.map +1 -1
- package/dist/index.css +20 -0
- package/dist/index.css.map +1 -1
- package/dist/index.min.css +1 -1
- package/dist/index.min.css.map +1 -1
- package/lib/seam/access-codes/use-access-codes.js +11 -1
- package/lib/seam/access-codes/use-access-codes.js.map +1 -1
- package/lib/seam/components/SupportedDeviceTable/use-device-models.js +12 -1
- package/lib/seam/components/SupportedDeviceTable/use-device-models.js.map +1 -1
- package/lib/seam/components/SupportedDeviceTable/use-manufacturers.js +12 -1
- package/lib/seam/components/SupportedDeviceTable/use-manufacturers.js.map +1 -1
- package/lib/seam/devices/use-devices.js +0 -1
- package/lib/seam/devices/use-devices.js.map +1 -1
- package/lib/seam/thermostats/climate-setting-schedules/use-climate-setting-schedules.js +0 -1
- package/lib/seam/thermostats/climate-setting-schedules/use-climate-setting-schedules.js.map +1 -1
- package/lib/seam/thermostats/use-update-fan-mode.d.ts +6 -0
- package/lib/seam/thermostats/use-update-fan-mode.js +42 -0
- package/lib/seam/thermostats/use-update-fan-mode.js.map +1 -0
- package/lib/seam/thermostats/use-update-thermostat.d.ts +6 -0
- package/lib/seam/thermostats/use-update-thermostat.js +50 -0
- package/lib/seam/thermostats/use-update-thermostat.js.map +1 -0
- package/lib/ui/ClimateSettingForm/ClimateSettingScheduleForm.d.ts +3 -3
- package/lib/ui/ClimateSettingForm/ClimateSettingScheduleForm.js +30 -8
- package/lib/ui/ClimateSettingForm/ClimateSettingScheduleForm.js.map +1 -1
- package/lib/ui/ClimateSettingForm/ClimateSettingScheduleFormClimateSetting.d.ts +2 -4
- package/lib/ui/ClimateSettingForm/ClimateSettingScheduleFormClimateSetting.js +18 -23
- package/lib/ui/ClimateSettingForm/ClimateSettingScheduleFormClimateSetting.js.map +1 -1
- package/lib/ui/ClimateSettingForm/ClimateSettingScheduleFormDefaultClimateSetting.d.ts +10 -0
- package/lib/ui/ClimateSettingForm/ClimateSettingScheduleFormDefaultClimateSetting.js +24 -0
- package/lib/ui/ClimateSettingForm/ClimateSettingScheduleFormDefaultClimateSetting.js.map +1 -0
- package/lib/ui/ClimateSettingForm/ClimateSettingScheduleFormDeviceSelect.d.ts +1 -2
- package/lib/ui/ClimateSettingForm/ClimateSettingScheduleFormDeviceSelect.js +1 -2
- package/lib/ui/ClimateSettingForm/ClimateSettingScheduleFormDeviceSelect.js.map +1 -1
- package/lib/ui/thermostat/TemperatureControlGroup.d.ts +5 -5
- package/lib/ui/thermostat/TemperatureControlGroup.js +1 -1
- package/lib/ui/thermostat/TemperatureControlGroup.js.map +1 -1
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +2 -2
- package/src/lib/seam/access-codes/use-access-codes.ts +15 -1
- package/src/lib/seam/components/SupportedDeviceTable/use-device-models.ts +15 -1
- package/src/lib/seam/components/SupportedDeviceTable/use-manufacturers.ts +15 -1
- package/src/lib/seam/devices/use-devices.ts +0 -1
- package/src/lib/seam/thermostats/climate-setting-schedules/use-climate-setting-schedules.ts +0 -1
- package/src/lib/seam/thermostats/use-update-fan-mode.ts +81 -0
- package/src/lib/seam/thermostats/use-update-thermostat.ts +92 -0
- package/src/lib/ui/ClimateSettingForm/ClimateSettingScheduleForm.tsx +57 -23
- package/src/lib/ui/ClimateSettingForm/ClimateSettingScheduleFormClimateSetting.tsx +31 -77
- package/src/lib/ui/ClimateSettingForm/ClimateSettingScheduleFormDefaultClimateSetting.tsx +79 -0
- package/src/lib/ui/ClimateSettingForm/ClimateSettingScheduleFormDeviceSelect.tsx +0 -3
- package/src/lib/ui/thermostat/TemperatureControlGroup.tsx +10 -10
- package/src/lib/version.ts +1 -1
- package/src/styles/_climate-setting-schedule-form.scss +30 -0
|
@@ -33,7 +33,6 @@ export function useClimateSettingSchedules(
|
|
|
33
33
|
return await client.thermostats.climateSettingSchedules.list(params)
|
|
34
34
|
},
|
|
35
35
|
onSuccess: (schedules) => {
|
|
36
|
-
// Prime cache for each schedule.
|
|
37
36
|
for (const schedule of schedules) {
|
|
38
37
|
queryClient.setQueryData(
|
|
39
38
|
[
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useMutation,
|
|
3
|
+
type UseMutationResult,
|
|
4
|
+
useQueryClient,
|
|
5
|
+
} from '@tanstack/react-query'
|
|
6
|
+
import type {
|
|
7
|
+
SeamError,
|
|
8
|
+
ThermostatDevice,
|
|
9
|
+
ThermostatSetFanModeRequest,
|
|
10
|
+
ThermostatsListResponse,
|
|
11
|
+
} from 'seamapi'
|
|
12
|
+
|
|
13
|
+
import { NullSeamClientError, useSeamClient } from 'lib/seam/use-seam-client.js'
|
|
14
|
+
|
|
15
|
+
// UPSTREAM: Missing ThermostatSetFanModeResponse in seamapi.
|
|
16
|
+
type UseUpdateFanModeData = Record<string, unknown>
|
|
17
|
+
type UseUpdateFanModeMutationParams = ThermostatSetFanModeRequest
|
|
18
|
+
|
|
19
|
+
export function useUpdateFanMode(): UseMutationResult<
|
|
20
|
+
UseUpdateFanModeData,
|
|
21
|
+
SeamError,
|
|
22
|
+
UseUpdateFanModeMutationParams
|
|
23
|
+
> {
|
|
24
|
+
const { client } = useSeamClient()
|
|
25
|
+
const queryClient = useQueryClient()
|
|
26
|
+
|
|
27
|
+
return useMutation<
|
|
28
|
+
UseUpdateFanModeData,
|
|
29
|
+
SeamError,
|
|
30
|
+
UseUpdateFanModeMutationParams
|
|
31
|
+
>({
|
|
32
|
+
mutationFn: async (mutationParams: UseUpdateFanModeMutationParams) => {
|
|
33
|
+
if (client === null) throw new NullSeamClientError()
|
|
34
|
+
|
|
35
|
+
return await client.thermostats.setFanMode(mutationParams)
|
|
36
|
+
},
|
|
37
|
+
onSuccess: (_data, variables) => {
|
|
38
|
+
queryClient.setQueryData<ThermostatDevice | null>(
|
|
39
|
+
['thermostats', 'get', { device_id: variables.device_id }],
|
|
40
|
+
(thermostat) => {
|
|
41
|
+
if (thermostat == null) {
|
|
42
|
+
return
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return getUpdatedThermostat(thermostat, variables)
|
|
46
|
+
}
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
queryClient.setQueryData<ThermostatsListResponse['thermostats']>(
|
|
50
|
+
['thermostats', 'list', { device_id: variables.device_id }],
|
|
51
|
+
(thermostats): ThermostatDevice[] => {
|
|
52
|
+
if (thermostats == null) {
|
|
53
|
+
return []
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return thermostats.map((thermostat) => {
|
|
57
|
+
if (thermostat.device_id === variables.device_id) {
|
|
58
|
+
return getUpdatedThermostat(thermostat, variables)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return thermostat
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
)
|
|
65
|
+
},
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function getUpdatedThermostat(
|
|
70
|
+
thermostat: ThermostatDevice,
|
|
71
|
+
variables: UseUpdateFanModeMutationParams
|
|
72
|
+
): ThermostatDevice {
|
|
73
|
+
return {
|
|
74
|
+
...thermostat,
|
|
75
|
+
properties: {
|
|
76
|
+
...thermostat.properties,
|
|
77
|
+
fan_mode_setting:
|
|
78
|
+
variables.fan_mode_setting ?? thermostat.properties.fan_mode_setting,
|
|
79
|
+
},
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useMutation,
|
|
3
|
+
type UseMutationResult,
|
|
4
|
+
useQueryClient,
|
|
5
|
+
} from '@tanstack/react-query'
|
|
6
|
+
import type {
|
|
7
|
+
SeamError,
|
|
8
|
+
ThermostatDevice,
|
|
9
|
+
ThermostatsListResponse,
|
|
10
|
+
ThermostatUpdateRequest,
|
|
11
|
+
} from 'seamapi'
|
|
12
|
+
|
|
13
|
+
import { NullSeamClientError, useSeamClient } from 'lib/seam/use-seam-client.js'
|
|
14
|
+
|
|
15
|
+
// UPSTREAM: Missing ThermostatUpdateResponse in seamapi.
|
|
16
|
+
type UseUpdateThermostatData = Record<string, unknown>
|
|
17
|
+
type UseUpdateThermostatMutationParams = ThermostatUpdateRequest
|
|
18
|
+
|
|
19
|
+
export function useUpdateThermostat(): UseMutationResult<
|
|
20
|
+
UseUpdateThermostatData,
|
|
21
|
+
SeamError,
|
|
22
|
+
UseUpdateThermostatMutationParams
|
|
23
|
+
> {
|
|
24
|
+
const { client } = useSeamClient()
|
|
25
|
+
const queryClient = useQueryClient()
|
|
26
|
+
|
|
27
|
+
return useMutation<
|
|
28
|
+
UseUpdateThermostatData,
|
|
29
|
+
SeamError,
|
|
30
|
+
UseUpdateThermostatMutationParams
|
|
31
|
+
>({
|
|
32
|
+
mutationFn: async (mutationParams: UseUpdateThermostatMutationParams) => {
|
|
33
|
+
if (client === null) throw new NullSeamClientError()
|
|
34
|
+
|
|
35
|
+
return await client.thermostats.update(mutationParams)
|
|
36
|
+
},
|
|
37
|
+
onSuccess: (_data, variables) => {
|
|
38
|
+
queryClient.setQueryData<ThermostatDevice | null>(
|
|
39
|
+
['thermostats', 'get', { device_id: variables.device_id }],
|
|
40
|
+
(thermostat) => {
|
|
41
|
+
if (thermostat == null) {
|
|
42
|
+
return
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return getUpdatedThermostat(thermostat, variables)
|
|
46
|
+
}
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
queryClient.setQueryData<ThermostatsListResponse['thermostats']>(
|
|
50
|
+
['thermostats', 'list', { device_id: variables.device_id }],
|
|
51
|
+
(thermostats): ThermostatDevice[] => {
|
|
52
|
+
if (thermostats == null) {
|
|
53
|
+
return []
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return thermostats.map((thermostat) => {
|
|
57
|
+
if (thermostat.device_id === variables.device_id) {
|
|
58
|
+
return getUpdatedThermostat(thermostat, variables)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return thermostat
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
)
|
|
65
|
+
},
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function getUpdatedThermostat(
|
|
70
|
+
thermostat: ThermostatDevice,
|
|
71
|
+
variables: UseUpdateThermostatMutationParams
|
|
72
|
+
): ThermostatDevice {
|
|
73
|
+
return {
|
|
74
|
+
...thermostat,
|
|
75
|
+
|
|
76
|
+
properties: {
|
|
77
|
+
...thermostat.properties,
|
|
78
|
+
|
|
79
|
+
default_climate_setting: {
|
|
80
|
+
...thermostat.properties.default_climate_setting,
|
|
81
|
+
manual_override_allowed:
|
|
82
|
+
thermostat.properties?.default_climate_setting
|
|
83
|
+
?.manual_override_allowed != null
|
|
84
|
+
? thermostat.properties.default_climate_setting
|
|
85
|
+
.manual_override_allowed
|
|
86
|
+
: true,
|
|
87
|
+
|
|
88
|
+
...variables.default_climate_setting,
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import classNames from 'classnames'
|
|
2
|
-
import { useState } from 'react'
|
|
2
|
+
import { useEffect, useState } from 'react'
|
|
3
3
|
import { useForm } from 'react-hook-form'
|
|
4
|
-
import
|
|
4
|
+
import {
|
|
5
|
+
type ClimateSetting,
|
|
6
|
+
type HvacModeSetting,
|
|
7
|
+
isThermostatDevice,
|
|
8
|
+
} from 'seamapi'
|
|
9
|
+
|
|
10
|
+
import { useDevice } from 'lib/index.js'
|
|
5
11
|
|
|
6
12
|
import { getSystemTimeZone } from 'lib/dates.js'
|
|
7
13
|
import { ClimateSettingScheduleFormClimateSetting } from 'lib/ui/ClimateSettingForm/ClimateSettingScheduleFormClimateSetting.js'
|
|
14
|
+
import { ClimateSettingScheduleFormDefaultClimateSetting } from 'lib/ui/ClimateSettingForm/ClimateSettingScheduleFormDefaultClimateSetting.js'
|
|
8
15
|
import { ClimateSettingScheduleFormDeviceSelect } from 'lib/ui/ClimateSettingForm/ClimateSettingScheduleFormDeviceSelect.js'
|
|
9
16
|
import { ClimateSettingScheduleFormNameAndSchedule } from 'lib/ui/ClimateSettingForm/ClimateSettingScheduleFormNameAndSchedule.js'
|
|
10
17
|
import { ClimateSettingScheduleFormTimeZonePicker } from 'lib/ui/ClimateSettingForm/ClimateSettingScheduleFormTimeZonePicker.js'
|
|
@@ -31,8 +38,9 @@ export interface ClimateSettingScheduleFormFields {
|
|
|
31
38
|
startDate: string
|
|
32
39
|
endDate: string
|
|
33
40
|
timeZone: string
|
|
34
|
-
|
|
35
|
-
|
|
41
|
+
climateSetting: {
|
|
42
|
+
hvacModeSetting: HvacModeSetting
|
|
43
|
+
// may have to ignore one or the other fields here on submit
|
|
36
44
|
heatingSetPoint: number
|
|
37
45
|
coolingSetPoint: number
|
|
38
46
|
}
|
|
@@ -54,24 +62,29 @@ export function ClimateSettingScheduleForm({
|
|
|
54
62
|
function Content({
|
|
55
63
|
onBack,
|
|
56
64
|
}: Omit<ClimateSettingScheduleFormProps, 'className'>): JSX.Element {
|
|
57
|
-
const { control, watch, resetField } =
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
const { control, watch, resetField } =
|
|
66
|
+
useForm<ClimateSettingScheduleFormFields>({
|
|
67
|
+
defaultValues: {
|
|
68
|
+
deviceId: '',
|
|
69
|
+
name: '',
|
|
70
|
+
startDate: '',
|
|
71
|
+
endDate: '',
|
|
72
|
+
timeZone: getSystemTimeZone(),
|
|
73
|
+
climateSetting: {
|
|
74
|
+
hvacModeSetting: 'heat_cool',
|
|
75
|
+
heatingSetPoint: 70,
|
|
76
|
+
coolingSetPoint: 75,
|
|
77
|
+
},
|
|
68
78
|
},
|
|
69
|
-
}
|
|
70
|
-
})
|
|
79
|
+
})
|
|
71
80
|
|
|
72
81
|
const deviceId = watch('deviceId')
|
|
73
82
|
const timeZone = watch('timeZone')
|
|
74
83
|
|
|
84
|
+
const { device } = useDevice({
|
|
85
|
+
device_id: deviceId,
|
|
86
|
+
})
|
|
87
|
+
|
|
75
88
|
const [page, setPage] = useState<
|
|
76
89
|
| 'device_select'
|
|
77
90
|
| 'default_setting'
|
|
@@ -80,13 +93,38 @@ function Content({
|
|
|
80
93
|
| 'climate_setting'
|
|
81
94
|
>('device_select')
|
|
82
95
|
|
|
96
|
+
const returnToDeviceSelect = (): void => {
|
|
97
|
+
resetField('deviceId')
|
|
98
|
+
setPage('device_select')
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
useEffect(() => {
|
|
102
|
+
if (page === 'device_select' && device != null) {
|
|
103
|
+
if (!isThermostatDevice(device)) return
|
|
104
|
+
const defaultSetting = device.properties.default_climate_setting
|
|
105
|
+
if (defaultSetting != null) setPage('name_and_schedule')
|
|
106
|
+
else setPage('default_setting')
|
|
107
|
+
}
|
|
108
|
+
}, [device, page, setPage])
|
|
109
|
+
|
|
83
110
|
if (page === 'device_select') {
|
|
84
111
|
return (
|
|
85
112
|
<ClimateSettingScheduleFormDeviceSelect
|
|
86
113
|
title={t.addNewClimateSettingSchedule}
|
|
87
114
|
control={control}
|
|
88
115
|
onBack={onBack}
|
|
89
|
-
|
|
116
|
+
/>
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (page === 'default_setting') {
|
|
121
|
+
return (
|
|
122
|
+
<ClimateSettingScheduleFormDefaultClimateSetting
|
|
123
|
+
title={t.addNewClimateSettingSchedule}
|
|
124
|
+
deviceId={deviceId}
|
|
125
|
+
onBack={returnToDeviceSelect}
|
|
126
|
+
onCancel={onBack}
|
|
127
|
+
onSave={() => {
|
|
90
128
|
setPage('name_and_schedule')
|
|
91
129
|
}}
|
|
92
130
|
/>
|
|
@@ -99,9 +137,7 @@ function Content({
|
|
|
99
137
|
title={t.addNewClimateSettingSchedule}
|
|
100
138
|
control={control}
|
|
101
139
|
deviceId={deviceId}
|
|
102
|
-
onBack={
|
|
103
|
-
setPage('device_select')
|
|
104
|
-
}}
|
|
140
|
+
onBack={returnToDeviceSelect}
|
|
105
141
|
onCancel={onBack}
|
|
106
142
|
onNext={() => {
|
|
107
143
|
setPage('climate_setting')
|
|
@@ -130,8 +166,6 @@ function Content({
|
|
|
130
166
|
<ClimateSettingScheduleFormClimateSetting
|
|
131
167
|
title={t.addNewClimateSettingSchedule}
|
|
132
168
|
control={control}
|
|
133
|
-
watch={watch}
|
|
134
|
-
resetField={resetField}
|
|
135
169
|
deviceId={deviceId}
|
|
136
170
|
onBack={() => {
|
|
137
171
|
setPage('name_and_schedule')
|
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type Control,
|
|
3
|
-
Controller,
|
|
4
|
-
type UseFormResetField,
|
|
5
|
-
type UseFormWatch,
|
|
6
|
-
} from 'react-hook-form'
|
|
7
|
-
import type { HvacModeSetting } from 'seamapi'
|
|
1
|
+
import { type Control, Controller } from 'react-hook-form'
|
|
8
2
|
|
|
9
3
|
import { useDevice } from 'lib/seam/devices/use-device.js'
|
|
10
4
|
import { Button } from 'lib/ui/Button.js'
|
|
@@ -12,14 +6,11 @@ import type { ClimateSettingScheduleFormFields } from 'lib/ui/ClimateSettingForm
|
|
|
12
6
|
import { FormField } from 'lib/ui/FormField.js'
|
|
13
7
|
import { InputLabel } from 'lib/ui/InputLabel.js'
|
|
14
8
|
import { ContentHeader } from 'lib/ui/layout/ContentHeader.js'
|
|
15
|
-
import {
|
|
16
|
-
import { TemperatureControlGroup } from 'lib/ui/thermostat/TemperatureControlGroup.js'
|
|
9
|
+
import { ClimateSettingControlGroup } from 'lib/ui/thermostat/ClimateSettingControlGroup.js'
|
|
17
10
|
|
|
18
11
|
interface ClimateSettingScheduleFormClimateSettingProps {
|
|
19
12
|
title: string
|
|
20
13
|
control: Control<ClimateSettingScheduleFormFields>
|
|
21
|
-
watch: UseFormWatch<ClimateSettingScheduleFormFields>
|
|
22
|
-
resetField: UseFormResetField<ClimateSettingScheduleFormFields>
|
|
23
14
|
deviceId: string
|
|
24
15
|
onBack: () => void
|
|
25
16
|
onCancel: (() => void) | undefined
|
|
@@ -29,8 +20,6 @@ interface ClimateSettingScheduleFormClimateSettingProps {
|
|
|
29
20
|
export function ClimateSettingScheduleFormClimateSetting({
|
|
30
21
|
title,
|
|
31
22
|
control,
|
|
32
|
-
watch,
|
|
33
|
-
resetField,
|
|
34
23
|
deviceId,
|
|
35
24
|
onBack,
|
|
36
25
|
onCancel,
|
|
@@ -40,8 +29,6 @@ export function ClimateSettingScheduleFormClimateSetting({
|
|
|
40
29
|
device_id: deviceId,
|
|
41
30
|
})
|
|
42
31
|
|
|
43
|
-
const hvacModeSetting = watch('hvacModeSetting')
|
|
44
|
-
|
|
45
32
|
return (
|
|
46
33
|
<>
|
|
47
34
|
<ContentHeader
|
|
@@ -56,11 +43,7 @@ export function ClimateSettingScheduleFormClimateSetting({
|
|
|
56
43
|
<InputLabel>{t.climateSetting}</InputLabel>
|
|
57
44
|
<span className='seam-label'>{t.climateSettingSubHeading}</span>
|
|
58
45
|
</div>
|
|
59
|
-
<FormContent
|
|
60
|
-
control={control}
|
|
61
|
-
resetField={resetField}
|
|
62
|
-
hvacModeSetting={hvacModeSetting}
|
|
63
|
-
/>
|
|
46
|
+
<FormContent control={control} />
|
|
64
47
|
</div>
|
|
65
48
|
</div>
|
|
66
49
|
<div className='seam-actions'>
|
|
@@ -76,67 +59,38 @@ export function ClimateSettingScheduleFormClimateSetting({
|
|
|
76
59
|
|
|
77
60
|
interface FormContentProps {
|
|
78
61
|
control: Control<ClimateSettingScheduleFormFields>
|
|
79
|
-
resetField: UseFormResetField<ClimateSettingScheduleFormFields>
|
|
80
|
-
hvacModeSetting: HvacModeSetting
|
|
81
62
|
}
|
|
82
63
|
|
|
83
|
-
function FormContent({
|
|
84
|
-
control,
|
|
85
|
-
resetField,
|
|
86
|
-
hvacModeSetting,
|
|
87
|
-
}: FormContentProps): JSX.Element {
|
|
64
|
+
function FormContent({ control }: FormContentProps): JSX.Element {
|
|
88
65
|
return (
|
|
89
|
-
|
|
90
|
-
<
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
<TemperatureControlGroup
|
|
114
|
-
coolValue={value.coolingSetPoint}
|
|
115
|
-
heatValue={value.heatingSetPoint}
|
|
116
|
-
delta={5}
|
|
117
|
-
maxCool={90}
|
|
118
|
-
maxHeat={100}
|
|
119
|
-
minCool={50}
|
|
120
|
-
minHeat={70}
|
|
121
|
-
mode={hvacModeSetting}
|
|
122
|
-
onCoolValueChange={(coolingSetPoint) => {
|
|
123
|
-
onChange({
|
|
124
|
-
...value,
|
|
125
|
-
coolingSetPoint,
|
|
126
|
-
})
|
|
127
|
-
}}
|
|
128
|
-
onHeatValueChange={(heatingSetPoint) => {
|
|
129
|
-
onChange({
|
|
130
|
-
...value,
|
|
131
|
-
heatingSetPoint,
|
|
132
|
-
})
|
|
133
|
-
}}
|
|
134
|
-
/>
|
|
135
|
-
)}
|
|
66
|
+
<FormField>
|
|
67
|
+
<Controller
|
|
68
|
+
name='climateSetting'
|
|
69
|
+
control={control}
|
|
70
|
+
render={({ field: { value, onChange } }) => (
|
|
71
|
+
<ClimateSettingControlGroup
|
|
72
|
+
mode={value.hvacModeSetting}
|
|
73
|
+
onModeChange={(mode) => {
|
|
74
|
+
onChange({ ...value, hvacModeSetting: mode })
|
|
75
|
+
}}
|
|
76
|
+
coolValue={value.coolingSetPoint}
|
|
77
|
+
heatValue={value.heatingSetPoint}
|
|
78
|
+
onCoolValueChange={(coolingSetPoint) => {
|
|
79
|
+
onChange({
|
|
80
|
+
...value,
|
|
81
|
+
coolingSetPoint,
|
|
82
|
+
})
|
|
83
|
+
}}
|
|
84
|
+
onHeatValueChange={(heatingSetPoint) => {
|
|
85
|
+
onChange({
|
|
86
|
+
...value,
|
|
87
|
+
heatingSetPoint,
|
|
88
|
+
})
|
|
89
|
+
}}
|
|
136
90
|
/>
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
91
|
+
)}
|
|
92
|
+
/>
|
|
93
|
+
</FormField>
|
|
140
94
|
)
|
|
141
95
|
}
|
|
142
96
|
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { useState } from 'react'
|
|
2
|
+
import type { HvacModeSetting } from 'seamapi'
|
|
3
|
+
|
|
4
|
+
import { useDevice } from 'lib/seam/devices/use-device.js'
|
|
5
|
+
import { Button } from 'lib/ui/Button.js'
|
|
6
|
+
import { InputLabel } from 'lib/ui/InputLabel.js'
|
|
7
|
+
import { ContentHeader } from 'lib/ui/layout/ContentHeader.js'
|
|
8
|
+
import { ClimateSettingControlGroup } from 'lib/ui/thermostat/ClimateSettingControlGroup.js'
|
|
9
|
+
|
|
10
|
+
interface ClimateSettingScheduleFormDefaultClimateSettingProps {
|
|
11
|
+
title: string
|
|
12
|
+
deviceId: string
|
|
13
|
+
onBack: () => void
|
|
14
|
+
onCancel: (() => void) | undefined
|
|
15
|
+
onSave: () => void
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function ClimateSettingScheduleFormDefaultClimateSetting({
|
|
19
|
+
title,
|
|
20
|
+
deviceId,
|
|
21
|
+
onBack,
|
|
22
|
+
onCancel,
|
|
23
|
+
onSave,
|
|
24
|
+
}: ClimateSettingScheduleFormDefaultClimateSettingProps): JSX.Element {
|
|
25
|
+
const { device } = useDevice({
|
|
26
|
+
device_id: deviceId,
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
const [mode, setMode] = useState<HvacModeSetting>('heat_cool')
|
|
30
|
+
const [heatValue, setHeatValue] = useState(70)
|
|
31
|
+
const [coolValue, setCoolValue] = useState(75)
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<>
|
|
35
|
+
<ContentHeader
|
|
36
|
+
title={title}
|
|
37
|
+
onBack={onBack}
|
|
38
|
+
subheading={device?.properties.name}
|
|
39
|
+
/>
|
|
40
|
+
<div className='seam-main'>
|
|
41
|
+
<div className='seam-climate-setting-schedule-form-default-climate-setting'>
|
|
42
|
+
<div className='seam-content'>
|
|
43
|
+
<div className='seam-default-climate-setting-message'>
|
|
44
|
+
<p>{t.defaultClimateMessage}</p>
|
|
45
|
+
</div>
|
|
46
|
+
<div className='seam-control-group-title'>
|
|
47
|
+
<InputLabel>{t.defaultClimate}</InputLabel>
|
|
48
|
+
<span className='seam-label'>{t.defautClimateSubHeading}</span>
|
|
49
|
+
</div>
|
|
50
|
+
<ClimateSettingControlGroup
|
|
51
|
+
mode={mode}
|
|
52
|
+
onModeChange={setMode}
|
|
53
|
+
heatValue={heatValue}
|
|
54
|
+
onHeatValueChange={setHeatValue}
|
|
55
|
+
coolValue={coolValue}
|
|
56
|
+
onCoolValueChange={setCoolValue}
|
|
57
|
+
/>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
<div className='seam-actions'>
|
|
61
|
+
<Button onClick={onCancel}>{t.cancel}</Button>
|
|
62
|
+
<Button variant='solid' onClick={onSave}>
|
|
63
|
+
{t.save}
|
|
64
|
+
</Button>
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
</>
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const t = {
|
|
72
|
+
defaultClimate: 'Default Climate',
|
|
73
|
+
defautClimateSubHeading:
|
|
74
|
+
'Choose the default mode and climate for this device',
|
|
75
|
+
defaultClimateMessage:
|
|
76
|
+
'This device doesn’t have a default climate set up yet. Choose the climate you’d like the device to fall back to after scheduled climates reach their ends.',
|
|
77
|
+
cancel: 'Cancel',
|
|
78
|
+
save: 'Save',
|
|
79
|
+
}
|
|
@@ -7,7 +7,6 @@ import { ThermostatSelect } from 'lib/ui/thermostat/ThermostatSelect.js'
|
|
|
7
7
|
interface ClimateSettingScheduleFormDeviceSelectProps {
|
|
8
8
|
title: string
|
|
9
9
|
control: Control<ClimateSettingScheduleFormFields>
|
|
10
|
-
onSelect: () => void
|
|
11
10
|
onBack: (() => void) | undefined
|
|
12
11
|
}
|
|
13
12
|
|
|
@@ -15,7 +14,6 @@ export function ClimateSettingScheduleFormDeviceSelect({
|
|
|
15
14
|
title,
|
|
16
15
|
control,
|
|
17
16
|
onBack,
|
|
18
|
-
onSelect,
|
|
19
17
|
}: ClimateSettingScheduleFormDeviceSelectProps): JSX.Element {
|
|
20
18
|
return (
|
|
21
19
|
<>
|
|
@@ -28,7 +26,6 @@ export function ClimateSettingScheduleFormDeviceSelect({
|
|
|
28
26
|
<ThermostatSelect
|
|
29
27
|
onSelect={(deviceId) => {
|
|
30
28
|
onChange(deviceId)
|
|
31
|
-
onSelect()
|
|
32
29
|
}}
|
|
33
30
|
/>
|
|
34
31
|
)}
|
|
@@ -16,11 +16,11 @@ export interface TemperatureControlGroupProps {
|
|
|
16
16
|
onHeatValueChange: (temperature: number) => void
|
|
17
17
|
coolValue: number
|
|
18
18
|
onCoolValueChange: (temperature: number) => void
|
|
19
|
-
delta
|
|
20
|
-
minHeat
|
|
21
|
-
maxHeat
|
|
22
|
-
minCool
|
|
23
|
-
maxCool
|
|
19
|
+
delta?: number
|
|
20
|
+
minHeat?: number
|
|
21
|
+
maxHeat?: number
|
|
22
|
+
minCool?: number
|
|
23
|
+
maxCool?: number
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
export function TemperatureControlGroup({
|
|
@@ -29,11 +29,11 @@ export function TemperatureControlGroup({
|
|
|
29
29
|
onHeatValueChange,
|
|
30
30
|
coolValue,
|
|
31
31
|
onCoolValueChange,
|
|
32
|
-
delta,
|
|
33
|
-
minHeat,
|
|
34
|
-
maxHeat,
|
|
35
|
-
minCool,
|
|
36
|
-
maxCool,
|
|
32
|
+
delta = 5,
|
|
33
|
+
minHeat = 60,
|
|
34
|
+
maxHeat = 90,
|
|
35
|
+
minCool = 60,
|
|
36
|
+
maxCool = 90,
|
|
37
37
|
}: TemperatureControlGroupProps): JSX.Element {
|
|
38
38
|
const showHeat = mode === 'heat' || mode === 'heat_cool'
|
|
39
39
|
const showCool = mode === 'cool' || mode === 'heat_cool'
|
package/src/lib/version.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
.seam-climate-setting-schedule-form {
|
|
5
5
|
@include main;
|
|
6
6
|
@include name-and-schedule;
|
|
7
|
+
@include default-climate-setting;
|
|
7
8
|
@include climate-setting;
|
|
8
9
|
}
|
|
9
10
|
}
|
|
@@ -57,6 +58,35 @@
|
|
|
57
58
|
}
|
|
58
59
|
}
|
|
59
60
|
|
|
61
|
+
@mixin default-climate-setting {
|
|
62
|
+
.seam-climate-setting-schedule-form-default-climate-setting {
|
|
63
|
+
.seam-control-group-title {
|
|
64
|
+
margin-top: 16px;
|
|
65
|
+
margin-bottom: 16px;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.seam-label {
|
|
69
|
+
color: colors.$text-gray-1;
|
|
70
|
+
font-size: 14px;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.seam-default-climate-setting-message {
|
|
74
|
+
> p {
|
|
75
|
+
color: colors.$text-gray-1;
|
|
76
|
+
font-size: 14px;
|
|
77
|
+
margin-bottom: 16px;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
margin-top: 4px;
|
|
81
|
+
border-bottom: 1px solid colors.$divider-stroke-light;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.seam-climate-setting-control-group {
|
|
85
|
+
margin-bottom: 32px;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
60
90
|
@mixin climate-setting {
|
|
61
91
|
.seam-climate-setting-schedule-form-climate-setting {
|
|
62
92
|
.seam-content {
|