@seamapi/react 1.44.0 → 1.45.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 +1 -1
- package/dist/elements.js +79 -75
- package/dist/elements.js.map +1 -1
- package/dist/index.css +16 -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/components/SupportedDeviceTable/SupportedDeviceContent.d.ts +2 -1
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceContent.js +2 -1
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceContent.js.map +1 -1
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceFilterArea.d.ts +2 -1
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceFilterArea.js +12 -11
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceFilterArea.js.map +1 -1
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceTable.d.ts +2 -1
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceTable.js +3 -3
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceTable.js.map +1 -1
- package/lib/seam/components/SupportedDeviceTable/use-filtered-device-models.d.ts +2 -1
- package/lib/seam/components/SupportedDeviceTable/use-filtered-device-models.js +11 -6
- package/lib/seam/components/SupportedDeviceTable/use-filtered-device-models.js.map +1 -1
- package/lib/ui/thermostat/ClimateSettingStatus.d.ts +9 -0
- package/lib/ui/thermostat/ClimateSettingStatus.js +33 -0
- package/lib/ui/thermostat/ClimateSettingStatus.js.map +1 -0
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +1 -1
- package/src/lib/seam/components/SupportedDeviceTable/SupportedDeviceContent.tsx +3 -0
- package/src/lib/seam/components/SupportedDeviceTable/SupportedDeviceFilterArea.tsx +18 -13
- package/src/lib/seam/components/SupportedDeviceTable/SupportedDeviceTable.element.ts +1 -0
- package/src/lib/seam/components/SupportedDeviceTable/SupportedDeviceTable.tsx +4 -0
- package/src/lib/seam/components/SupportedDeviceTable/use-filtered-device-models.ts +11 -8
- package/src/lib/ui/thermostat/ClimateSettingStatus.tsx +88 -0
- package/src/lib/version.ts +1 -1
- package/src/styles/_main.scss +2 -0
- package/src/styles/_thermostat.scss +21 -0
|
@@ -14,6 +14,7 @@ interface SupportedDeviceFilterAreaProps {
|
|
|
14
14
|
filters: DeviceModelFilters
|
|
15
15
|
setFilters: Dispatch<SetStateAction<DeviceModelFilters>>
|
|
16
16
|
brands: string[] | null
|
|
17
|
+
excludedBrands: string[]
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
export function SupportedDeviceFilterArea({
|
|
@@ -22,10 +23,11 @@ export function SupportedDeviceFilterArea({
|
|
|
22
23
|
filters,
|
|
23
24
|
setFilters,
|
|
24
25
|
brands,
|
|
26
|
+
excludedBrands,
|
|
25
27
|
}: SupportedDeviceFilterAreaProps): JSX.Element {
|
|
26
28
|
const appliedFiltersCount = getAppliedFilterCount(filters)
|
|
27
29
|
|
|
28
|
-
const availableBrands = useAvailableBrands(brands)
|
|
30
|
+
const availableBrands = useAvailableBrands(brands, excludedBrands)
|
|
29
31
|
|
|
30
32
|
const resetFilter = (filterType: keyof DeviceModelFilters): void => {
|
|
31
33
|
setFilters((filters) => ({
|
|
@@ -121,27 +123,30 @@ const getAppliedFilterCount = (filters: DeviceModelFilters): number => {
|
|
|
121
123
|
return count
|
|
122
124
|
}
|
|
123
125
|
|
|
124
|
-
const useAvailableBrands = (
|
|
126
|
+
const useAvailableBrands = (
|
|
127
|
+
brands: string[] | null,
|
|
128
|
+
excludedBrands: string[]
|
|
129
|
+
): string[] => {
|
|
125
130
|
const { deviceModels } = useDeviceModels()
|
|
126
131
|
|
|
127
132
|
if (deviceModels == null) return []
|
|
128
133
|
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
uniqueBrands.add(deviceModel.brand)
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
return Array.from(uniqueBrands)
|
|
134
|
+
const availableBrands = deviceModels
|
|
135
|
+
.map(({ brand }) => brand.trim())
|
|
136
|
+
.filter((brand) => {
|
|
137
|
+
// UPSTREAM: API can return an empty value for brand.
|
|
138
|
+
return brand !== ''
|
|
139
|
+
})
|
|
140
140
|
.filter((brand) => {
|
|
141
141
|
if (brands === null) return true
|
|
142
142
|
return brands.includes(brand)
|
|
143
143
|
})
|
|
144
|
+
.filter((brand) => {
|
|
145
|
+
return !excludedBrands.includes(brand)
|
|
146
|
+
})
|
|
144
147
|
.map((brand) => capitalize(brand))
|
|
148
|
+
|
|
149
|
+
return Array.from(new Set(availableBrands))
|
|
145
150
|
}
|
|
146
151
|
|
|
147
152
|
const t = {
|
|
@@ -12,6 +12,7 @@ export interface SupportedDeviceTableProps {
|
|
|
12
12
|
*/
|
|
13
13
|
cannotFilter?: boolean
|
|
14
14
|
brands?: string[] | null
|
|
15
|
+
excludedBrands?: string[]
|
|
15
16
|
className?: string
|
|
16
17
|
}
|
|
17
18
|
|
|
@@ -19,6 +20,7 @@ export function SupportedDeviceTable({
|
|
|
19
20
|
disableFilter = false,
|
|
20
21
|
cannotFilter,
|
|
21
22
|
brands = null,
|
|
23
|
+
excludedBrands = [],
|
|
22
24
|
className,
|
|
23
25
|
}: SupportedDeviceTableProps = {}): JSX.Element {
|
|
24
26
|
const [filterValue, setFilterValue] = useState('')
|
|
@@ -43,6 +45,7 @@ export function SupportedDeviceTable({
|
|
|
43
45
|
filters={filters}
|
|
44
46
|
setFilters={setFilters}
|
|
45
47
|
brands={brands}
|
|
48
|
+
excludedBrands={excludedBrands}
|
|
46
49
|
/>
|
|
47
50
|
)}
|
|
48
51
|
<SupportedDeviceContent
|
|
@@ -52,6 +55,7 @@ export function SupportedDeviceTable({
|
|
|
52
55
|
filterValue={filterValue}
|
|
53
56
|
filters={filters}
|
|
54
57
|
brands={brands}
|
|
58
|
+
excludedBrands={excludedBrands}
|
|
55
59
|
/>
|
|
56
60
|
</div>
|
|
57
61
|
)
|
|
@@ -12,10 +12,12 @@ export const useFilteredDeviceModels = ({
|
|
|
12
12
|
filterValue,
|
|
13
13
|
filters,
|
|
14
14
|
brands,
|
|
15
|
+
excludedBrands,
|
|
15
16
|
}: {
|
|
16
17
|
filterValue: string
|
|
17
18
|
filters: DeviceModelFilters
|
|
18
19
|
brands: string[] | null
|
|
20
|
+
excludedBrands: string[]
|
|
19
21
|
}): ReturnType<typeof useDeviceModels> => {
|
|
20
22
|
const params: UseDeviceModelsParams = {}
|
|
21
23
|
|
|
@@ -33,16 +35,17 @@ export const useFilteredDeviceModels = ({
|
|
|
33
35
|
|
|
34
36
|
const query = useDeviceModels(params)
|
|
35
37
|
|
|
36
|
-
|
|
37
|
-
return query
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// UPSTREAM: The API does not have a brands query parameter,
|
|
38
|
+
// UPSTREAM: The API does not have a brands or excludedBrands query parameter,
|
|
41
39
|
// so selected brands are filtered here.
|
|
42
40
|
return {
|
|
43
41
|
...query,
|
|
44
|
-
deviceModels: query.deviceModels
|
|
45
|
-
|
|
46
|
-
|
|
42
|
+
deviceModels: query.deviceModels
|
|
43
|
+
?.filter(({ brand }) => {
|
|
44
|
+
if (brands === null) return true
|
|
45
|
+
return brands.includes(brand)
|
|
46
|
+
})
|
|
47
|
+
.filter(({ brand }) => {
|
|
48
|
+
return !excludedBrands.includes(brand)
|
|
49
|
+
}),
|
|
47
50
|
}
|
|
48
51
|
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { ClimateSetting } from 'seamapi'
|
|
2
|
+
|
|
3
|
+
import { ThermostatCoolIcon } from 'lib/icons/ThermostatCool.js'
|
|
4
|
+
import { ThermostatHeatIcon } from 'lib/icons/ThermostatHeat.js'
|
|
5
|
+
import { ThermostatHeatCoolIcon } from 'lib/icons/ThermostatHeatCool.js'
|
|
6
|
+
import { ThermostatOffIcon } from 'lib/icons/ThermostatOff.js'
|
|
7
|
+
|
|
8
|
+
interface ClimateSettingStatusProps {
|
|
9
|
+
climateSetting: ClimateSetting
|
|
10
|
+
temperatureUnit?: 'fahrenheit' | 'celsius'
|
|
11
|
+
iconPlacement?: 'left' | 'right'
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function ClimateSettingStatus({
|
|
15
|
+
climateSetting,
|
|
16
|
+
temperatureUnit = 'fahrenheit',
|
|
17
|
+
iconPlacement = 'left',
|
|
18
|
+
}: ClimateSettingStatusProps): JSX.Element {
|
|
19
|
+
return (
|
|
20
|
+
<div className='seam-climate-setting-status'>
|
|
21
|
+
{iconPlacement === 'left' && (
|
|
22
|
+
<ClimateSettingIcon mode={climateSetting.hvac_mode_setting} />
|
|
23
|
+
)}
|
|
24
|
+
<Content
|
|
25
|
+
mode={climateSetting.hvac_mode_setting}
|
|
26
|
+
coolingSetPoint={climateSetting.cooling_set_point_fahrenheit}
|
|
27
|
+
heatingSetPoint={climateSetting.heating_set_point_fahrenheit}
|
|
28
|
+
temperatureUnit={temperatureUnit}
|
|
29
|
+
/>
|
|
30
|
+
{iconPlacement === 'right' && (
|
|
31
|
+
<ClimateSettingIcon mode={climateSetting.hvac_mode_setting} />
|
|
32
|
+
)}
|
|
33
|
+
</div>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function ClimateSettingIcon(props: {
|
|
38
|
+
mode: ClimateSetting['hvac_mode_setting']
|
|
39
|
+
}): JSX.Element | null {
|
|
40
|
+
const { mode } = props
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<div className='seam-climate-setting-status-icon'>
|
|
44
|
+
{mode === 'cool' && <ThermostatCoolIcon />}
|
|
45
|
+
{mode === 'heat' && <ThermostatHeatIcon />}
|
|
46
|
+
{mode === 'heatcool' && <ThermostatHeatCoolIcon />}
|
|
47
|
+
{mode === 'off' && <ThermostatOffIcon />}
|
|
48
|
+
</div>
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function Content(props: {
|
|
53
|
+
mode: ClimateSetting['hvac_mode_setting']
|
|
54
|
+
coolingSetPoint:
|
|
55
|
+
| ClimateSetting['cooling_set_point_fahrenheit']
|
|
56
|
+
| ClimateSetting['cooling_set_point_celsius']
|
|
57
|
+
heatingSetPoint:
|
|
58
|
+
| ClimateSetting['heating_set_point_fahrenheit']
|
|
59
|
+
| ClimateSetting['heating_set_point_celsius']
|
|
60
|
+
temperatureUnit: 'fahrenheit' | 'celsius'
|
|
61
|
+
}): JSX.Element | null {
|
|
62
|
+
const { mode, coolingSetPoint, heatingSetPoint, temperatureUnit } = props
|
|
63
|
+
const hasCoolingSetPoint = coolingSetPoint !== undefined
|
|
64
|
+
const hasHeatingSetPoint = heatingSetPoint !== undefined
|
|
65
|
+
const unit =
|
|
66
|
+
temperatureUnit === 'fahrenheit' ? t.degreeFahrenheit : t.degreeCelsius
|
|
67
|
+
|
|
68
|
+
if (mode === 'cool' && hasCoolingSetPoint)
|
|
69
|
+
return <span>{`${coolingSetPoint}${unit}`}</span>
|
|
70
|
+
|
|
71
|
+
if (mode === 'heat' && hasHeatingSetPoint)
|
|
72
|
+
return <span>{`${heatingSetPoint}${unit}`}</span>
|
|
73
|
+
|
|
74
|
+
if (mode === 'heatcool' && hasHeatingSetPoint && hasCoolingSetPoint)
|
|
75
|
+
return (
|
|
76
|
+
<span>{`${heatingSetPoint}${unit} - ${coolingSetPoint}${unit}`}</span>
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
if (mode === 'off') return <span>{t.off}</span>
|
|
80
|
+
|
|
81
|
+
return null
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const t = {
|
|
85
|
+
degreeFahrenheit: '°F',
|
|
86
|
+
degreeCelsius: '°C',
|
|
87
|
+
off: 'Off',
|
|
88
|
+
}
|
package/src/lib/version.ts
CHANGED
package/src/styles/_main.scss
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
@use './form-field';
|
|
19
19
|
@use './radio-field';
|
|
20
20
|
@use './checkbox';
|
|
21
|
+
@use './thermostat';
|
|
21
22
|
|
|
22
23
|
.seam-components {
|
|
23
24
|
// Reset
|
|
@@ -44,4 +45,5 @@
|
|
|
44
45
|
@include access-code-form.all;
|
|
45
46
|
@include alert.all;
|
|
46
47
|
@include supported-device-table.all;
|
|
48
|
+
@include thermostat.all;
|
|
47
49
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
@use './colors';
|
|
2
|
+
|
|
3
|
+
@mixin all {
|
|
4
|
+
.seam-climate-setting-status {
|
|
5
|
+
display: flex;
|
|
6
|
+
align-items: center;
|
|
7
|
+
gap: 4px;
|
|
8
|
+
color: colors.$text-gray-1;
|
|
9
|
+
font-size: 14px;
|
|
10
|
+
line-height: 118%;
|
|
11
|
+
white-space: nowrap;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.seam-climate-setting-status-icon {
|
|
15
|
+
width: 20px;
|
|
16
|
+
height: 20px;
|
|
17
|
+
display: flex;
|
|
18
|
+
justify-content: center;
|
|
19
|
+
align-items: center;
|
|
20
|
+
}
|
|
21
|
+
}
|