import classNames from 'classnames' import { useEffect, useState } from 'react' import { debounce } from 'lib/debounce.js' import { CheckBlackIcon } from 'lib/icons/CheckBlack.js' import type { NestedSpecificDeviceDetailsProps } from 'lib/seam/components/DeviceDetails/DeviceDetails.js' import { DeviceInfo } from 'lib/seam/components/DeviceDetails/DeviceInfo.js' import type { HvacModeSetting, ThermostatDevice, } from 'lib/seam/thermostats/thermostat-device.js' import { useCoolThermostat } from 'lib/seam/thermostats/use-cool-thermostat.js' import { useHeatCoolThermostat } from 'lib/seam/thermostats/use-heat-cool-thermostat.js' import { useHeatThermostat } from 'lib/seam/thermostats/use-heat-thermostat.js' import { useSetThermostatFanMode } from 'lib/seam/thermostats/use-set-thermostat-fan-mode.js' import { useSetThermostatOff } from 'lib/seam/thermostats/use-set-thermostat-off.js' import { Button } from 'lib/ui/Button.js' import { AccordionRow } from 'lib/ui/layout/AccordionRow.js' import { ContentHeader } from 'lib/ui/layout/ContentHeader.js' import { DetailRow } from 'lib/ui/layout/DetailRow.js' import { DetailSection } from 'lib/ui/layout/DetailSection.js' import { DetailSectionGroup } from 'lib/ui/layout/DetailSectionGroup.js' import { Snackbar } from 'lib/ui/Snackbar/Snackbar.js' import { ClimateModeMenu } from 'lib/ui/thermostat/ClimateModeMenu.js' import { ClimatePresets } from 'lib/ui/thermostat/ClimatePresets.js' import { ClimateSettingStatus } from 'lib/ui/thermostat/ClimateSettingStatus.js' import { FanModeMenu } from 'lib/ui/thermostat/FanModeMenu.js' import { TemperatureControlGroup } from 'lib/ui/thermostat/TemperatureControlGroup.js' import { ThermostatCard } from 'lib/ui/thermostat/ThermostatCard.js' interface ThermostatDeviceDetailsProps extends NestedSpecificDeviceDetailsProps { device: ThermostatDevice onEditName?: (newName: string) => void | Promise } export function ThermostatDeviceDetails({ device, disableResourceIds, disableConnectedAccountInformation, onBack, className, onEditName, }: ThermostatDeviceDetailsProps): JSX.Element | null { const [temperatureUnit, setTemperatureUnit] = useState< 'fahrenheit' | 'celsius' >('fahrenheit') const [climateSettingsVisible, setClimateSettingsVisible] = useState(false) if (device == null) { return null } if (climateSettingsVisible) { return ( { setClimateSettingsVisible(false) }} /> ) } return (
{ setClimateSettingsVisible(true) }} device={device} />
) } function FanModeRow({ device }: { device: ThermostatDevice }): JSX.Element { const { mutate, isSuccess, isError } = useSetThermostatFanMode() return ( <>
{ mutate({ device_id: device.device_id, fan_mode_setting: fanMode, }) }} />
) } function ClimateSettingRow({ device, }: { device: ThermostatDevice }): JSX.Element { const deviceHeatValue = device.properties.current_climate_setting.heating_set_point_fahrenheit const deviceCoolValue = device.properties.current_climate_setting.cooling_set_point_fahrenheit const availableHvacModes = device.properties.available_hvac_mode_settings const [showSuccess, setShowSuccess] = useState(false) const [mode, setMode] = useState( (availableHvacModes.includes('heat_cool') ? 'heat_cool' : availableHvacModes[0]) ?? 'off' ) const [heatValue, setHeatValue] = useState( device.properties.current_climate_setting.heating_set_point_fahrenheit ?? 0 ) const [coolValue, setCoolValue] = useState( device.properties.current_climate_setting.cooling_set_point_fahrenheit ?? 0 ) const { mutate: heatCoolThermostat, isSuccess: isHeatCoolSuccess, isError: isHeatCoolError, } = useHeatCoolThermostat() const { mutate: heatThermostat, isSuccess: isHeatSuccess, isError: isHeatError, } = useHeatThermostat() const { mutate: coolThermostat, isSuccess: isCoolSuccess, isError: isCoolError, } = useCoolThermostat() const { mutate: setThermostatOff, isSuccess: isSetOffSuccess, isError: isSetOffError, } = useSetThermostatOff() useEffect(() => { const handler = debounce(() => { switch (mode) { case 'heat_cool': heatCoolThermostat({ device_id: device.device_id, heating_set_point_fahrenheit: heatValue, cooling_set_point_fahrenheit: coolValue, }) break case 'heat': heatThermostat({ device_id: device.device_id, heating_set_point_fahrenheit: heatValue, }) break case 'cool': coolThermostat({ device_id: device.device_id, cooling_set_point_fahrenheit: coolValue, }) break case 'off': setThermostatOff({ device_id: device.device_id, }) break } }, 2000) if ( heatValue !== deviceHeatValue || coolValue !== deviceCoolValue || mode === 'off' ) { handler() } return () => { handler.cancel() } }, [ heatValue, coolValue, mode, deviceHeatValue, deviceCoolValue, device, heatThermostat, coolThermostat, heatCoolThermostat, setThermostatOff, ]) useEffect(() => { if ( isHeatCoolSuccess || isHeatSuccess || isCoolSuccess || isSetOffSuccess ) { setShowSuccess(true) const timeout = globalThis.setTimeout(() => { setShowSuccess(false) }, 3000) return () => { globalThis.clearTimeout(timeout) } } return () => {} }, [isHeatCoolSuccess, isHeatSuccess, isCoolSuccess, isSetOffSuccess]) return ( <>
{t.saved}
} rightCollapsedContent={ } >
{mode !== 'off' && ( )}
) } interface ClimatePresetRowProps { device: ThermostatDevice onClickManage: () => void } function ClimatePresetRow({ device, onClickManage, }: ClimatePresetRowProps): JSX.Element { return ( ) } const t = { thermostat: 'Thermostat', currentSettings: 'Current settings', currentSettingsTooltip: 'These are the settings currently on the device. If you change them here, they change on the device.', climate: 'Climate', climatePresets: 'Climate presets', fanMode: 'Fan mode', none: 'None', fanModeSuccess: 'Successfully updated fan mode!', fanModeError: 'Error updating fan mode. Please try again.', climateSettingError: 'Error updating climate setting. Please try again.', saved: 'Saved', manageNPresets: (n: number) => `Manage (${n} Preset${n <= 1 ? '' : 's'})`, }