diff --git a/src/lib/seam/components/DeviceDetails/ThermostatDeviceDetails.tsx b/src/lib/seam/components/DeviceDetails/ThermostatDeviceDetails.tsx index fc3eff6a1..4aac71a91 100644 --- a/src/lib/seam/components/DeviceDetails/ThermostatDeviceDetails.tsx +++ b/src/lib/seam/components/DeviceDetails/ThermostatDeviceDetails.tsx @@ -14,7 +14,7 @@ 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 { useSetThermostatOff } from 'lib/seam/thermostats/use-set-thermostat-off.js' -import { useUpdateFanMode } from 'lib/seam/thermostats/use-update-fan-mode.js' +import { useSetThermostatFanMode } from 'lib/seam/thermostats/use-set-thermostat-fan-mode.js' import { useUpdateThermostat } from 'lib/seam/thermostats/use-update-thermostat.js' import { AccordionRow } from 'lib/ui/layout/AccordionRow.js' import { ContentHeader } from 'lib/ui/layout/ContentHeader.js' @@ -203,7 +203,7 @@ function ManualOverrideRow({ } function FanModeRow({ device }: { device: ThermostatDevice }): JSX.Element { - const { mutate, isSuccess, isError } = useUpdateFanMode() + const { mutate, isSuccess, isError } = useSetThermostatFanMode() return ( <> diff --git a/src/lib/seam/thermostats/use-set-thermostat-fan-mode.ts b/src/lib/seam/thermostats/use-set-thermostat-fan-mode.ts new file mode 100644 index 000000000..bdf62b9d1 --- /dev/null +++ b/src/lib/seam/thermostats/use-set-thermostat-fan-mode.ts @@ -0,0 +1,95 @@ +import type { + SeamActionAttemptFailedError, + SeamActionAttemptTimeoutError, + SeamHttpApiError, + ThermostatsSetFanModeBody, +} from '@seamapi/http/connect' +import type { ActionAttempt, Device } from '@seamapi/types/connect' +import { + useMutation, + type UseMutationResult, + useQueryClient, +} from '@tanstack/react-query' + +import { NullSeamClientError, useSeamClient } from 'lib/seam/use-seam-client.js' + +export type UseSetThermostatFanModeParams = never + +export type UseSetThermostatFanModeData = undefined + +export type UseSetThermostatFanModeMutationVariables = ThermostatsSetFanModeBody + +type SetThermostatFanModeActionAttempt = Extract< + ActionAttempt, + { action_type: 'SET_FAN_MODE' } +> + +type MutationError = + | SeamHttpApiError + | SeamActionAttemptFailedError + | SeamActionAttemptTimeoutError + +export function useSetThermostatFanMode(): UseMutationResult< + UseSetThermostatFanModeData, + MutationError, + UseSetThermostatFanModeMutationVariables +> { + const { client } = useSeamClient() + const queryClient = useQueryClient() + + return useMutation< + UseSetThermostatFanModeData, + MutationError, + UseSetThermostatFanModeMutationVariables + >({ + mutationFn: async (variables) => { + if (client === null) throw new NullSeamClientError() + await client.thermostats.setFanMode(variables) + }, + onSuccess: (_data, variables) => { + queryClient.setQueryData( + ['devices', 'get', { device_id: variables.device_id }], + (device) => { + if (device == null) { + return + } + return getUpdatedDevice(device, variables) + } + ) + + queryClient.setQueryData( + ['devices', 'list', { device_id: variables.device_id }], + (devices): Device[] => { + if (devices == null) { + return [] + } + + return devices.map((device) => { + if (device.device_id === variables.device_id) { + return getUpdatedDevice(device, variables) + } + + return device + }) + } + ) + }, + }) +} + +function getUpdatedDevice( + device: Device, + variables: UseSetThermostatFanModeMutationVariables +): Device { + const { properties } = device + if ('fan_mode_setting' in properties && properties.fan_mode_setting != null) { + return { + ...device, + properties: { + ...properties, + fan_mode_setting: variables.fan_mode_setting, + }, + } + } + return device +} diff --git a/src/lib/seam/thermostats/use-update-fan-mode.ts b/src/lib/seam/thermostats/use-update-fan-mode.ts deleted file mode 100644 index d30dbc8b5..000000000 --- a/src/lib/seam/thermostats/use-update-fan-mode.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { - useMutation, - type UseMutationResult, - useQueryClient, -} from '@tanstack/react-query' -import type { - SeamError, - ThermostatDevice, - ThermostatSetFanModeRequest, - ThermostatsListResponse, -} from 'seamapi' - -import { NullSeamClientError, useSeamClient } from 'lib/seam/use-seam-client.js' - -// UPSTREAM: Missing ThermostatSetFanModeResponse in seamapi. -export type UseUpdateFanModeData = Record - -export type UseUpdateFanModeMutationVariables = ThermostatSetFanModeRequest - -export function useUpdateFanMode(): UseMutationResult< - UseUpdateFanModeData, - SeamError, - UseUpdateFanModeMutationVariables -> { - const { client } = useSeamClient() - const queryClient = useQueryClient() - - return useMutation< - UseUpdateFanModeData, - SeamError, - UseUpdateFanModeMutationVariables - >({ - mutationFn: async (variables: UseUpdateFanModeMutationVariables) => { - if (client === null) throw new NullSeamClientError() - - return await client.thermostats.setFanMode(variables) - }, - onSuccess: (_data, variables) => { - queryClient.setQueryData( - ['devices', 'get', { device_id: variables.device_id }], - (thermostat) => { - if (thermostat == null) { - return - } - - return getUpdatedDevice(thermostat, variables) - } - ) - - queryClient.setQueryData( - ['devices', 'list', { device_id: variables.device_id }], - (thermostats): ThermostatDevice[] => { - if (thermostats == null) { - return [] - } - - return thermostats.map((thermostat) => { - if (thermostat.device_id === variables.device_id) { - return getUpdatedDevice(thermostat, variables) - } - - return thermostat - }) - } - ) - }, - }) -} - -function getUpdatedDevice( - thermostat: ThermostatDevice, - variables: UseUpdateFanModeMutationVariables -): ThermostatDevice { - return { - ...thermostat, - properties: { - ...thermostat.properties, - fan_mode_setting: - variables.fan_mode_setting ?? thermostat.properties.fan_mode_setting, - }, - } -}