diff --git a/.storybook/seed-fake.js b/.storybook/seed-fake.js index 7f7e4807a..6e1fc8977 100644 --- a/.storybook/seed-fake.js +++ b/.storybook/seed-fake.js @@ -23,11 +23,7 @@ export const seedFake = (db) => { }) db.simulateWorkspaceOutage(ws3.workspace_id, { - routes: [ - '/devices/list', - '/access_codes/list', - '/thermostats/climate_setting_schedules/list', - ], + routes: ['/devices/list', '/access_codes/list'], }) const cw = db.addConnectWebview({ @@ -426,7 +422,6 @@ export const seedFake = (db) => { image_url: 'https://connect.getseam.com/assets/images/devices/ecobee_3-lite_front.png', image_alt_text: 'Placeholder Lock Image', - is_climate_setting_schedule_active: false, }, errors: [], }) @@ -479,7 +474,6 @@ export const seedFake = (db) => { image_url: 'https://connect.getseam.com/assets/images/devices/ecobee_3-lite_front.png', image_alt_text: 'Placeholder Lock Image', - is_climate_setting_schedule_active: false, }, errors: [], }) @@ -551,51 +545,6 @@ export const seedFake = (db) => { noise_threshold_name: 'Active Hours', }) - // add climate setting schedules - db.addClimateSettingSchedule({ - device_id: device5.device_id, - workspace_id: ws2.workspace_id, - created_at: '2023-05-17T00:16:12.000', - name: 'Guest - Robinson', - schedule_starts_at: '2024-07-24T00:00:00.000Z', - schedule_ends_at: '2024-08-01T00:00:00.000Z', - schedule_type: 'time_bound', - manual_override_allowed: true, - hvac_mode_setting: 'cool', - cooling_set_point_fahrenheit: 70, - cooling_set_point_celsius: 21, - }) - - db.addClimateSettingSchedule({ - device_id: device5.device_id, - workspace_id: ws2.workspace_id, - created_at: '2023-05-17T00:16:12.000', - name: 'Guest - Cabrero', - schedule_starts_at: '2024-07-04T00:00:00.000Z', - schedule_ends_at: '2024-07-14T00:00:00.000Z', - schedule_type: 'time_bound', - manual_override_allowed: true, - hvac_mode_setting: 'heat_cool', - heating_set_point_fahrenheit: 65, - heating_set_point_celsius: 18, - cooling_set_point_fahrenheit: 72, - cooling_set_point_celsius: 22, - }) - - db.addClimateSettingSchedule({ - device_id: device5.device_id, - workspace_id: ws2.workspace_id, - created_at: '2022-05-17T00:16:12.000', - name: 'Guest - Robinson with a very long title to test truncation and text wrap', - schedule_starts_at: '2023-07-04T00:00:00.000Z', - schedule_ends_at: '2027-08-14T00:00:00.000Z', - schedule_type: 'time_bound', - manual_override_allowed: true, - hvac_mode_setting: 'cool', - cooling_set_point_fahrenheit: 72, - cooling_set_point_celsius: 22.2222, - }) - db.addClientSession({ workspace_id: ws2.workspace_id, created_at: '2023-05-29T01:02:02.000', diff --git a/package-lock.json b/package-lock.json index 44adcd3ad..5943adacc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "3.1.2", "license": "MIT", "dependencies": { - "@seamapi/http": "^1.2.0", + "@seamapi/http": "^1.13.1", "@tanstack/react-query": "^5.27.5", "classnames": "^2.3.2", "luxon": "^3.3.0", @@ -25,8 +25,8 @@ "@rollup/plugin-replace": "^5.0.5", "@rxfork/r2wc-react-to-web-component": "^2.4.0", "@seamapi/fake-devicedb": "^1.6.1", - "@seamapi/fake-seam-connect": "^1.69.1", - "@seamapi/types": "^1.228.0", + "@seamapi/fake-seam-connect": "^1.72.1", + "@seamapi/types": "^1.292.2", "@storybook/addon-designs": "^7.0.1", "@storybook/addon-essentials": "^7.0.2", "@storybook/addon-links": "^7.0.2", @@ -83,7 +83,7 @@ "npm": ">= 9.0.0" }, "peerDependencies": { - "@seamapi/types": "^1.26.2", + "@seamapi/types": "^1.292.2", "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", "react": "^18.0.0", @@ -5478,10 +5478,11 @@ } }, "node_modules/@seamapi/fake-seam-connect": { - "version": "1.69.1", - "resolved": "https://registry.npmjs.org/@seamapi/fake-seam-connect/-/fake-seam-connect-1.69.1.tgz", - "integrity": "sha512-22mY2U/t8pV7BWlL8qu2dYNBbw0ER9chzyktcN+Yv/J/F7wuJE+h6yTA+5rpuje7CoK/EWUtWLWCq7EK3y+iSw==", + "version": "1.72.1", + "resolved": "https://npm.pkg.github.com/download/@seamapi/fake-seam-connect/1.72.1/97581069d4b5794ad0bddc3636e533718c2d7feb", + "integrity": "sha512-ydDnKE+iOVRU0xEBpTYwpNjIRgV/pVkmPvXNRG76JBYtYf2whZxAPhcMUEjQbRk6tW1r8ykY051aLsWoKfjNPQ==", "dev": true, + "license": "MIT", "bin": { "fake-seam-connect": "dist/server.js" }, @@ -5496,9 +5497,9 @@ } }, "node_modules/@seamapi/http": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@seamapi/http/-/http-1.2.0.tgz", - "integrity": "sha512-I9U//qm7ifPJowMFI18piQe5/cMXeBPn66TuuobhviT2cda5gRihAAsX5VtT4ZGTNPyPCkMZbVWzujgA6xkliA==", + "version": "1.13.1", + "resolved": "https://npm.pkg.github.com/download/@seamapi/http/1.13.1/d9050ea02557f3fcaf334bee809fb7e5b9ae7562", + "integrity": "sha512-16kjvuMZ7X46Q82xpp/Ptx5g6k9SZvOGAT/UAlmWWxTlhXg9qZajQqLZYTBSPCwdDpQa8XV+sdTYRdLeUotr1Q==", "license": "MIT", "dependencies": { "@seamapi/url-search-params-serializer": "^1.1.0", @@ -5511,19 +5512,13 @@ "npm": ">= 9.0.0" }, "peerDependencies": { - "@seamapi/types": "^1.227.0" - }, - "peerDependenciesMeta": { - "@seamapi/types": { - "optional": true - } + "@seamapi/types": "^1.286.3" } }, "node_modules/@seamapi/types": { - "version": "1.228.0", - "resolved": "https://registry.npmjs.org/@seamapi/types/-/types-1.228.0.tgz", - "integrity": "sha512-p7ZKWMdKp36QIAA7ta3qa0Z1qzXcTpyzAU9rw2IptES5oI8wwpR5hxK+VzdccJW4/Z3kT/9+K3RxPhUIgEB0jQ==", - "devOptional": true, + "version": "1.292.2", + "resolved": "https://npm.pkg.github.com/download/@seamapi/types/1.292.2/1adfe6a68d4bd8c23de4c15a938cb1cdbfc1a0ff", + "integrity": "sha512-mOCFatzYy89uzu4IEV3kFoPz5SCVd3w2TMC0G3hVrzxL3PYFRnuUa4LNKMsd583prDgoh6rmEHhKEAICqibXFQ==", "license": "MIT", "engines": { "node": ">=18.12.0", @@ -25962,7 +25957,6 @@ "version": "3.23.8", "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", - "devOptional": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/package.json b/package.json index 193e8d4d0..dab5e89e1 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,7 @@ "npm": ">= 9.0.0" }, "peerDependencies": { - "@seamapi/types": "^1.26.2", + "@seamapi/types": "^1.292.2", "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", "react": "^18.0.0", @@ -127,7 +127,7 @@ } }, "dependencies": { - "@seamapi/http": "^1.2.0", + "@seamapi/http": "^1.13.1", "@tanstack/react-query": "^5.27.5", "classnames": "^2.3.2", "luxon": "^3.3.0", @@ -143,8 +143,8 @@ "@rollup/plugin-replace": "^5.0.5", "@rxfork/r2wc-react-to-web-component": "^2.4.0", "@seamapi/fake-devicedb": "^1.6.1", - "@seamapi/fake-seam-connect": "^1.69.1", - "@seamapi/types": "^1.228.0", + "@seamapi/fake-seam-connect": "^1.72.1", + "@seamapi/types": "^1.292.2", "@storybook/addon-designs": "^7.0.1", "@storybook/addon-essentials": "^7.0.2", "@storybook/addon-links": "^7.0.2", diff --git a/src/lib/element.tsx b/src/lib/element.tsx index eccc2f9a7..cede18816 100644 --- a/src/lib/element.tsx +++ b/src/lib/element.tsx @@ -47,7 +47,6 @@ const commonProps: R2wcProps = { disableDeleteAccessCode: 'boolean', disableResourceIds: 'boolean', disableConnectedAccountInformation: 'boolean', - disableClimateSettingSchedules: 'boolean', onBack: 'object', className: 'string', } diff --git a/src/lib/icons/ClimateSettingSchedule.tsx b/src/lib/icons/ClimateSettingSchedule.tsx deleted file mode 100644 index f9af35259..000000000 --- a/src/lib/icons/ClimateSettingSchedule.tsx +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Automatically generated by SVGR from assets/icons/*.svg. - * Do not edit this file or add other components to this directory. - */ -import type { SVGProps } from 'react' -export function ClimateSettingScheduleIcon( - props: SVGProps -): JSX.Element { - return ( - - - - ) -} diff --git a/src/lib/seam/components/AccessCodeDetails/AccessCodeDetails.tsx b/src/lib/seam/components/AccessCodeDetails/AccessCodeDetails.tsx index a215d90ac..e1725bdc2 100644 --- a/src/lib/seam/components/AccessCodeDetails/AccessCodeDetails.tsx +++ b/src/lib/seam/components/AccessCodeDetails/AccessCodeDetails.tsx @@ -51,7 +51,6 @@ export function AccessCodeDetails({ disableDeleteAccessCode = false, disableResourceIds = false, disableConnectedAccountInformation = false, - disableClimateSettingSchedules, onBack, className, }: AccessCodeDetailsProps): JSX.Element | null { @@ -114,7 +113,6 @@ export function AccessCodeDetails({ disableDeleteAccessCode={disableDeleteAccessCode} disableResourceIds={disableResourceIds} disableConnectedAccountInformation={disableConnectedAccountInformation} - disableClimateSettingSchedules={disableClimateSettingSchedules} onBack={() => { setEditFormOpen(false) }} @@ -139,7 +137,6 @@ export function AccessCodeDetails({ disableDeleteAccessCode={disableDeleteAccessCode} disableResourceIds={disableResourceIds} disableConnectedAccountInformation={disableConnectedAccountInformation} - disableClimateSettingSchedules={disableClimateSettingSchedules} onBack={() => { selectDevice(null) }} diff --git a/src/lib/seam/components/AccessCodeTable/AccessCodeTable.tsx b/src/lib/seam/components/AccessCodeTable/AccessCodeTable.tsx index daeae90e0..47a73ea5e 100644 --- a/src/lib/seam/components/AccessCodeTable/AccessCodeTable.tsx +++ b/src/lib/seam/components/AccessCodeTable/AccessCodeTable.tsx @@ -66,7 +66,6 @@ export function AccessCodeTable({ disableDeleteAccessCode = false, disableResourceIds = false, disableConnectedAccountInformation = false, - disableClimateSettingSchedules, }: AccessCodeTableProps): JSX.Element { useComponentTelemetry('AccessCodeTable') @@ -141,7 +140,6 @@ export function AccessCodeTable({ disableDeleteAccessCode={disableDeleteAccessCode} disableResourceIds={disableResourceIds} disableConnectedAccountInformation={disableConnectedAccountInformation} - disableClimateSettingSchedules={disableClimateSettingSchedules} onBack={() => { setSelectedEditAccessCodeId(null) }} @@ -165,7 +163,6 @@ export function AccessCodeTable({ disableDeleteAccessCode={disableDeleteAccessCode} disableResourceIds={disableResourceIds} disableConnectedAccountInformation={disableConnectedAccountInformation} - disableClimateSettingSchedules={disableClimateSettingSchedules} onBack={() => { setSelectedViewAccessCodeId(null) }} @@ -186,7 +183,6 @@ export function AccessCodeTable({ disableDeleteAccessCode={disableDeleteAccessCode} disableResourceIds={disableResourceIds} disableConnectedAccountInformation={disableConnectedAccountInformation} - disableClimateSettingSchedules={disableClimateSettingSchedules} onBack={toggleAddAccessCodeForm} className={className} onSuccess={() => { diff --git a/src/lib/seam/components/ClimateSettingScheduleDetails/ClimateSettingScheduleCard.stories.tsx b/src/lib/seam/components/ClimateSettingScheduleDetails/ClimateSettingScheduleCard.stories.tsx deleted file mode 100644 index 951fa7f3a..000000000 --- a/src/lib/seam/components/ClimateSettingScheduleDetails/ClimateSettingScheduleCard.stories.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { Meta, StoryObj } from '@storybook/react' - -import { ClimateSettingScheduleCard } from './ClimateSettingScheduleCard.js' - -const meta: Meta = { - title: 'Library/ClimateSettingScheduleCard', - tags: ['autodocs'], - component: ClimateSettingScheduleCard, -} - -type Story = StoryObj - -export const Content: Story = { - render: (props) => ( - - ), -} - -export default meta diff --git a/src/lib/seam/components/ClimateSettingScheduleDetails/ClimateSettingScheduleCard.tsx b/src/lib/seam/components/ClimateSettingScheduleDetails/ClimateSettingScheduleCard.tsx deleted file mode 100644 index 857d70bac..000000000 --- a/src/lib/seam/components/ClimateSettingScheduleDetails/ClimateSettingScheduleCard.tsx +++ /dev/null @@ -1,107 +0,0 @@ -import type { ClimateSettingSchedule } from '@seamapi/types/connect' -import { DateTime } from 'luxon' - -import { ClimateSettingScheduleIcon } from 'lib/icons/ClimateSettingSchedule.js' -import { ClimateSettingScheduleDeviceBar } from 'lib/seam/components/ClimateSettingScheduleDetails/ClimateSettingScheduleDeviceBar.js' -import { useClimateSettingSchedule } from 'lib/seam/thermostats/climate-setting-schedules/use-climate-setting-schedule.js' -import { DotDivider } from 'lib/ui/layout/DotDivider.js' -import { ClimateSettingStatus } from 'lib/ui/thermostat/ClimateSettingStatus.js' -import { useNow } from 'lib/ui/use-now.js' - -import { formatDateTime } from './dates.js' - -interface ClimateSettingScheduleCardProps { - climateSettingScheduleId: string - onSelectDevice: (deviceId: string) => void -} - -export function ClimateSettingScheduleCard({ - climateSettingScheduleId, - onSelectDevice, -}: ClimateSettingScheduleCardProps): JSX.Element { - return ( -
- -
- ) -} - -function Content(props: { - climateSettingScheduleId: string - onSelectDevice: (deviceId: string) => void -}): JSX.Element | null { - const { climateSettingScheduleId, onSelectDevice } = props - - const { climateSettingSchedule } = useClimateSettingSchedule({ - climate_setting_schedule_id: climateSettingScheduleId, - }) - - if (climateSettingSchedule == null) { - return null - } - - const name = climateSettingSchedule.name ?? t.fallbackName - - return ( -
-
-
- -
-
-
{name}
-
- - - -
-
-
- -
- ) -} - -function ClimateSettingScheduleTiming(props: { - climateSettingSchedule: ClimateSettingSchedule -}): JSX.Element | null { - const { climateSettingSchedule } = props - - const now = useNow() - - if (now === null) return null - - const startTime = DateTime.fromISO(climateSettingSchedule.schedule_starts_at) - const endTime = DateTime.fromISO(climateSettingSchedule.schedule_ends_at) - - if (now < startTime) - return ( - - {t.starts} {formatDateTime(climateSettingSchedule.schedule_starts_at)} - - ) - - if (startTime <= now && now <= endTime) - return ( - - {t.ends} {formatDateTime(climateSettingSchedule.schedule_starts_at)} - - ) - - return {t.expired} -} - -const t = { - starts: 'Starts', - ends: 'Ends', - expired: 'Expired', - fallbackName: 'Climate Setting Schedule', -} diff --git a/src/lib/seam/components/ClimateSettingScheduleDetails/ClimateSettingScheduleDetails.element.ts b/src/lib/seam/components/ClimateSettingScheduleDetails/ClimateSettingScheduleDetails.element.ts deleted file mode 100644 index 9104fad4e..000000000 --- a/src/lib/seam/components/ClimateSettingScheduleDetails/ClimateSettingScheduleDetails.element.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { ElementProps } from 'lib/element.js' - -import type { ClimateSettingScheduleDetailsProps } from './ClimateSettingScheduleDetails.js' - -export const name = 'seam-climate-setting-schedule-details' - -export const props: ElementProps = { - climateSettingScheduleId: 'string', -} - -export { ClimateSettingScheduleDetails as Component } from './ClimateSettingScheduleDetails.js' diff --git a/src/lib/seam/components/ClimateSettingScheduleDetails/ClimateSettingScheduleDetails.stories.tsx b/src/lib/seam/components/ClimateSettingScheduleDetails/ClimateSettingScheduleDetails.stories.tsx deleted file mode 100644 index f0a18ed73..000000000 --- a/src/lib/seam/components/ClimateSettingScheduleDetails/ClimateSettingScheduleDetails.stories.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import { Button, Dialog } from '@mui/material' -import type { Meta, StoryObj } from '@storybook/react' - -import { ClimateSettingScheduleDetails } from 'lib/seam/components/ClimateSettingScheduleDetails/ClimateSettingScheduleDetails.js' -import { seamComponentsClassName } from 'lib/seam/SeamProvider.js' -import { useToggle } from 'lib/ui/use-toggle.js' - -const meta: Meta = { - title: 'Components/ClimateSettingScheduleDetails', - component: ClimateSettingScheduleDetails, - tags: ['autodocs'], - parameters: { - design: { - type: 'figma', - url: 'https://www.figma.com/file/WTdzEh4CudGdQFOtuVR3Eh/Thermostat%2FNoise-components?type=design&node-id=830-88257&mode=design&t=PEFHm2uapLILRbqf-0', - }, - }, -} - -export default meta - -type Story = StoryObj - -export const Content: Story = { - render: (props) => ( - - ), -} - -export const InsideModal: Story = { - render: (props) => { - const [open, toggleOpen] = useToggle() - return ( - <> - - - - - - ) - }, -} diff --git a/src/lib/seam/components/ClimateSettingScheduleDetails/ClimateSettingScheduleDetails.tsx b/src/lib/seam/components/ClimateSettingScheduleDetails/ClimateSettingScheduleDetails.tsx deleted file mode 100644 index add69a99b..000000000 --- a/src/lib/seam/components/ClimateSettingScheduleDetails/ClimateSettingScheduleDetails.tsx +++ /dev/null @@ -1,175 +0,0 @@ -import classNames from 'classnames' -import { useState } from 'react' - -import { ArrowRightIcon } from 'lib/icons/ArrowRight.js' -import { ClimateSettingScheduleCard } from 'lib/seam/components/ClimateSettingScheduleDetails/ClimateSettingScheduleCard.js' -import { - type CommonProps, - withRequiredCommonProps, -} from 'lib/seam/components/common-props.js' -import { NestedDeviceDetails } from 'lib/seam/components/DeviceDetails/DeviceDetails.js' -import { useClimateSettingSchedule } from 'lib/seam/thermostats/climate-setting-schedules/use-climate-setting-schedule.js' -import { useUpdateClimateSettingSchedule } from 'lib/seam/thermostats/climate-setting-schedules/use-update-climate-setting-schedule.js' -import { useComponentTelemetry } from 'lib/telemetry/index.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 { Switch } from 'lib/ui/Switch/Switch.js' -import { ClimateSettingStatus } from 'lib/ui/thermostat/ClimateSettingStatus.js' - -import { formatDateTime } from './dates.js' - -export interface ClimateSettingScheduleDetailsProps extends CommonProps { - climateSettingScheduleId: string -} - -export const NestedClimateSettingScheduleDetails = withRequiredCommonProps( - ClimateSettingScheduleDetails -) - -export function ClimateSettingScheduleDetails({ - climateSettingScheduleId, - disableLockUnlock = false, - disableDeleteAccessCode = false, - onBack, - className, - errorFilter = () => true, - warningFilter = () => true, - disableCreateAccessCode, - disableEditAccessCode, - disableResourceIds = false, - disableConnectedAccountInformation = false, - disableClimateSettingSchedules, -}: ClimateSettingScheduleDetailsProps): JSX.Element | null { - useComponentTelemetry('ClimateSettingScheduleDetails') - - const { climateSettingSchedule } = useClimateSettingSchedule({ - climate_setting_schedule_id: climateSettingScheduleId, - }) - - const { mutate, isSuccess, isError } = useUpdateClimateSettingSchedule() - - const [selectedDeviceId, selectDevice] = useState(null) - - if (climateSettingSchedule == null) { - return null - } - - const isManualOverrideAllowed = - climateSettingSchedule.manual_override_allowed ?? false - - if (selectedDeviceId != null) { - return ( - { - selectDevice(null) - }} - className={className} - /> - ) - } - - return ( - <> -
- -
- -
- - {t.defaultSettingMessagePart1}{' '} - - {t.defaultSetting} - {' '} - {t.defaultSettingMessagePart2} - -
- - - - - {formatDateTime(climateSettingSchedule.schedule_starts_at)} - - {formatDateTime(climateSettingSchedule.schedule_ends_at)} - - - - - - - - { - mutate({ - climate_setting_schedule_id: - climateSettingSchedule.climate_setting_schedule_id, - manual_override_allowed: checked, - }) - }} - /> - - - - - -
- {formatDateTime(climateSettingSchedule.created_at)} -
-
-
-
-
-
- - - - - ) -} - -const t = { - climateSettingSchedule: 'Climate setting schedule', - startEndTime: 'Start/End Time', - climateSetting: 'Climate setting', - allowManualOverride: 'Allow manual override', - creationDate: 'Creation date', - defaultSettingMessagePart1: 'Thermostat will return to its', - defaultSetting: 'default setting', - defaultSettingMessagePart2: 'at end time.', - manualOverrideSuccess: 'Successfully updated manual override!', - manualOverrideError: 'Error updating manual override. Please try again.', -} diff --git a/src/lib/seam/components/ClimateSettingScheduleDetails/ClimateSettingScheduleDeviceBar.tsx b/src/lib/seam/components/ClimateSettingScheduleDetails/ClimateSettingScheduleDeviceBar.tsx deleted file mode 100644 index 3e1ff4c72..000000000 --- a/src/lib/seam/components/ClimateSettingScheduleDetails/ClimateSettingScheduleDeviceBar.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import { ChevronWideIcon } from 'lib/icons/ChevronWide.js' -import { useDevice } from 'lib/seam/devices/use-device.js' -import { - isThermostatDevice, - type ThermostatDevice, -} from 'lib/seam/thermostats/thermostat-device.js' -import { DeviceImage } from 'lib/ui/device/DeviceImage.js' -import { ClimateSettingStatus } from 'lib/ui/thermostat/ClimateSettingStatus.js' - -export function ClimateSettingScheduleDeviceBar({ - deviceId, - onSelectDevice, -}: { - deviceId: string - onSelectDevice: (deviceId: string) => void -}): JSX.Element | null { - const { isPending, device } = useDevice({ - device_id: deviceId, - }) - - if (isPending) { - return null - } - - if (device == null) { - return null - } - - if (!isThermostatDevice(device)) { - return null - } - - return -} - -function Content(props: { - device: ThermostatDevice - onSelectDevice: (deviceId: string) => void -}): JSX.Element { - const { device, onSelectDevice } = props - - return ( -
{ - onSelectDevice(device.device_id) - }} - > -
-
- -
-
-
{device.properties.name}
-
- {t.currentClimate}: - -
-
-
-
- -
-
- ) -} - -const t = { - currentClimate: 'Current climate', -} diff --git a/src/lib/seam/components/ClimateSettingScheduleDetails/dates.ts b/src/lib/seam/components/ClimateSettingScheduleDetails/dates.ts deleted file mode 100644 index 4a24bedde..000000000 --- a/src/lib/seam/components/ClimateSettingScheduleDetails/dates.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { DateTime } from 'luxon' - -export const formatDateTime = (date: string): string => - DateTime.fromISO(date).toLocaleString({ - month: 'short', - day: 'numeric', - hour: 'numeric', - minute: '2-digit', - timeZoneName: 'short', - }) diff --git a/src/lib/seam/components/ClimateSettingScheduleTable/ClimateSettingScheduleRow.tsx b/src/lib/seam/components/ClimateSettingScheduleTable/ClimateSettingScheduleRow.tsx deleted file mode 100644 index 9d47081e6..000000000 --- a/src/lib/seam/components/ClimateSettingScheduleTable/ClimateSettingScheduleRow.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import type { ClimateSettingSchedule } from '@seamapi/types/connect' - -import { ClimateSettingScheduleIcon } from 'lib/icons/ClimateSettingSchedule.js' -import { ClimateSettingScheduleRowDetails } from 'lib/seam/components/ClimateSettingScheduleTable/ClimateSettingScheduleRowDetails.js' -import { TableCell } from 'lib/ui/Table/TableCell.js' -import { TableRow } from 'lib/ui/Table/TableRow.js' -import { Title } from 'lib/ui/typography/Title.js' - -interface ClimateSettingScheduleRowProps { - climateSettingSchedule: ClimateSettingSchedule - onClick: () => void -} - -export function ClimateSettingScheduleRow({ - climateSettingSchedule, - onClick, -}: ClimateSettingScheduleRowProps): JSX.Element { - return ( - - -
- -
-
- - - {climateSettingSchedule.name} - - - -
- ) -} diff --git a/src/lib/seam/components/ClimateSettingScheduleTable/ClimateSettingScheduleRowDetails.tsx b/src/lib/seam/components/ClimateSettingScheduleTable/ClimateSettingScheduleRowDetails.tsx deleted file mode 100644 index 39817f5a8..000000000 --- a/src/lib/seam/components/ClimateSettingScheduleTable/ClimateSettingScheduleRowDetails.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import type { ClimateSettingSchedule } from '@seamapi/types/connect' -import { DateTime } from 'luxon' - -import { useDevice } from 'lib/seam/devices/use-device.js' -import { DotDivider } from 'lib/ui/layout/DotDivider.js' -import { ClimateSettingStatus } from 'lib/ui/thermostat/ClimateSettingStatus.js' -import { useIsDateInPast } from 'lib/ui/use-is-date-in-past.js' - -export function ClimateSettingScheduleRowDetails(props: { - climateSettingSchedule: ClimateSettingSchedule -}): JSX.Element { - const { climateSettingSchedule } = props - const { device } = useDevice({ device_id: climateSettingSchedule.device_id }) - - return ( -
- - {device?.properties.name} - - - - - -
- ) -} - -function Duration(props: { - climateSettingSchedule: ClimateSettingSchedule -}): JSX.Element { - const { climateSettingSchedule } = props - - const hasStarted = - useIsDateInPast(climateSettingSchedule.schedule_starts_at) ?? false - - if (hasStarted) { - return ( - - {t.ends} {formatDate(climateSettingSchedule.schedule_ends_at)}{' '} - - ) - } - - return ( - - {t.starts} {formatDate(climateSettingSchedule.schedule_starts_at)} - - ) -} - -const formatDate = (date: string): string => - DateTime.fromISO(date).toLocaleString({ - month: 'long', - day: 'numeric', - }) - -const t = { - starts: 'Starts', - ends: 'Ends', -} diff --git a/src/lib/seam/components/ClimateSettingScheduleTable/ClimateSettingScheduleTable.element.ts b/src/lib/seam/components/ClimateSettingScheduleTable/ClimateSettingScheduleTable.element.ts deleted file mode 100644 index d71449575..000000000 --- a/src/lib/seam/components/ClimateSettingScheduleTable/ClimateSettingScheduleTable.element.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { ElementProps } from 'lib/element.js' - -import type { ClimateSettingScheduleTableProps } from './ClimateSettingScheduleTable.js' - -export const name = 'seam-climate-setting-schedule-table' - -export const props: ElementProps = { - deviceId: 'string', - disableSearch: 'boolean', - onClimateSettingScheduleClick: 'object', - preventDefaultOnClimateSettingScheduleClick: 'boolean', - climateSettingScheduleFilter: 'object', - climateSettingScheduleComparator: 'object', - heading: 'string', -} - -export { ClimateSettingScheduleTable as Component } from './ClimateSettingScheduleTable.js' diff --git a/src/lib/seam/components/ClimateSettingScheduleTable/ClimateSettingScheduleTable.stories.tsx b/src/lib/seam/components/ClimateSettingScheduleTable/ClimateSettingScheduleTable.stories.tsx deleted file mode 100644 index b62af390f..000000000 --- a/src/lib/seam/components/ClimateSettingScheduleTable/ClimateSettingScheduleTable.stories.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import { Button, Dialog, DialogActions } from '@mui/material' -import type { Meta, StoryObj } from '@storybook/react' - -import { seamComponentsClassName } from 'lib/seam/SeamProvider.js' -import { useToggle } from 'lib/ui/use-toggle.js' - -import { ClimateSettingScheduleTable } from './ClimateSettingScheduleTable.js' - -const meta: Meta = { - title: 'Components/ClimateSettingScheduleTable', - component: ClimateSettingScheduleTable, - tags: ['autodocs'], - parameters: { - design: { - type: 'figma', - url: 'https://www.figma.com/file/WTdzEh4CudGdQFOtuVR3Eh/Thermostat%2FNoise-components?type=design&node-id=830-88257&mode=design&t=Rfl61v9plkuuCF2h-0', - }, - }, -} - -export default meta - -type Story = StoryObj - -export const Content: Story = { - render: (props) => ( - - ), -} - -export const InsideModal: Story = { - render: (props) => { - const [open, toggleOpen] = useToggle() - return ( - <> - - - - - - - - - ) - }, -} - -export const ReadOnlyCustomerSupportPanel: Story = { - render: (props) => ( - - ), -} diff --git a/src/lib/seam/components/ClimateSettingScheduleTable/ClimateSettingScheduleTable.tsx b/src/lib/seam/components/ClimateSettingScheduleTable/ClimateSettingScheduleTable.tsx deleted file mode 100644 index 4d8bfba7c..000000000 --- a/src/lib/seam/components/ClimateSettingScheduleTable/ClimateSettingScheduleTable.tsx +++ /dev/null @@ -1,220 +0,0 @@ -import type { ClimateSettingSchedule } from '@seamapi/types/connect' -import classNames from 'classnames' -import { useCallback, useMemo, useState } from 'react' - -import { compareByCreatedAtDesc } from 'lib/dates.js' -import { NestedClimateSettingScheduleDetails } from 'lib/seam/components/ClimateSettingScheduleDetails/ClimateSettingScheduleDetails.js' -import { ClimateSettingScheduleRow } from 'lib/seam/components/ClimateSettingScheduleTable/ClimateSettingScheduleRow.js' -import { - type CommonProps, - withRequiredCommonProps, -} from 'lib/seam/components/common-props.js' -import { useClimateSettingSchedules } from 'lib/seam/thermostats/climate-setting-schedules/use-climate-setting-schedules.js' -import { useComponentTelemetry } from 'lib/telemetry/index.js' -import { ContentHeader } from 'lib/ui/layout/ContentHeader.js' -import { LoadingToast } from 'lib/ui/LoadingToast/LoadingToast.js' -import { Snackbar } from 'lib/ui/Snackbar/Snackbar.js' -import { EmptyPlaceholder } from 'lib/ui/Table/EmptyPlaceholder.js' -import { TableBody } from 'lib/ui/Table/TableBody.js' -import { TableHeader } from 'lib/ui/Table/TableHeader.js' -import { TableTitle } from 'lib/ui/Table/TableTitle.js' -import { SearchTextField } from 'lib/ui/TextField/SearchTextField.js' -import { Caption } from 'lib/ui/typography/Caption.js' - -export const NestedClimateSettingScheduleTable = withRequiredCommonProps( - ClimateSettingScheduleTable -) - -export interface ClimateSettingScheduleTableProps extends CommonProps { - deviceId: string - disableSearch?: boolean - onClimateSettingScheduleClick?: (climateSettingScheduleId: string) => void - preventDefaultOnClimateSettingScheduleClick?: boolean - climateSettingScheduleFilter?: ( - climateSettingSchedule: ClimateSettingSchedule, - searchInputValue: string - ) => boolean - climateSettingScheduleComparator?: ( - climateSettingScheduleA: ClimateSettingSchedule, - climateSettingScheduleB: ClimateSettingSchedule - ) => number - heading?: string | null -} - -const defaultClimateSettingScheduleFilter = ( - climateSettingSchedule: ClimateSettingSchedule, - searchInputValue: string -): boolean => { - const value = searchInputValue.trim().toLowerCase() - if (value === '') return true - const name = climateSettingSchedule.name ?? '' - return name.trim().toLowerCase().includes(value) -} - -export function ClimateSettingScheduleTable({ - deviceId, - disableSearch = false, - onClimateSettingScheduleClick = () => {}, - preventDefaultOnClimateSettingScheduleClick = false, - climateSettingScheduleFilter = defaultClimateSettingScheduleFilter, - climateSettingScheduleComparator = compareByCreatedAtDesc, - heading = t.climateSettingSchedules, - disableLockUnlock = false, - disableDeleteAccessCode = false, - onBack, - className, - errorFilter = () => true, - warningFilter = () => true, - disableCreateAccessCode, - disableEditAccessCode, - disableResourceIds = false, - disableConnectedAccountInformation = false, - disableClimateSettingSchedules, -}: ClimateSettingScheduleTableProps): JSX.Element { - useComponentTelemetry('ClimateSettingScheduleTable') - - const { climateSettingSchedules, isInitialLoading, isError, refetch } = - useClimateSettingSchedules({ - device_id: deviceId, - }) - - const [searchInputValue, setSearchInputValue] = useState('') - const [ - selectedViewClimateSettingScheduleId, - setSelectedViewClimateSettingScheduleId, - ] = useState(null) - - const filteredClimateSettingSchedules = useMemo( - () => - climateSettingSchedules - ?.filter((schedule) => - climateSettingScheduleFilter(schedule, searchInputValue) - ) - ?.sort(climateSettingScheduleComparator) ?? [], - [ - climateSettingSchedules, - searchInputValue, - climateSettingScheduleFilter, - climateSettingScheduleComparator, - ] - ) - - const handleClimateSettingScheduleClick = useCallback( - (climateSettingScheduleId: string): void => { - onClimateSettingScheduleClick(climateSettingScheduleId) - if (preventDefaultOnClimateSettingScheduleClick) return - setSelectedViewClimateSettingScheduleId(climateSettingScheduleId) - }, - [ - onClimateSettingScheduleClick, - preventDefaultOnClimateSettingScheduleClick, - setSelectedViewClimateSettingScheduleId, - ] - ) - - if (selectedViewClimateSettingScheduleId != null) { - return ( - { - setSelectedViewClimateSettingScheduleId(null) - }} - className={className} - /> - ) - } - - return ( -
- - - {heading != null ? ( - - {heading ?? t.climateSettingSchedules}{' '} - ({filteredClimateSettingSchedules.length}) - - ) : ( -
- )} -
- -
- {!disableSearch && ( - - )} - - - - - - { - void refetch() - }, - }} - disableCloseButton - /> -
- ) -} - -function Content(props: { - climateSettingSchedules: ClimateSettingSchedule[] - onClimateSettingScheduleClick: (climateSettingScheduleId: string) => void -}): JSX.Element { - const { climateSettingSchedules, onClimateSettingScheduleClick } = props - - if (climateSettingSchedules.length === 0) { - return ( - {t.noClimateSettingSchedulesMessage} - ) - } - - return ( - <> - {climateSettingSchedules.map((schedule) => ( - { - onClimateSettingScheduleClick(schedule.climate_setting_schedule_id) - }} - /> - ))} - - ) -} - -const t = { - climateSettingSchedules: 'Climate setting schedules', - noClimateSettingSchedulesMessage: - 'Sorry, no climate setting schedules were found', - loading: 'Loading schedules', - tryAgain: 'Try again', - fallbackErrorMessage: 'Climate settings could not be loaded', -} diff --git a/src/lib/seam/components/CreateClimateSettingScheduleForm/CreateClimateSettingScheduleForm.element.ts b/src/lib/seam/components/CreateClimateSettingScheduleForm/CreateClimateSettingScheduleForm.element.ts deleted file mode 100644 index 0543cca3e..000000000 --- a/src/lib/seam/components/CreateClimateSettingScheduleForm/CreateClimateSettingScheduleForm.element.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { ElementProps } from 'lib/element.js' - -import type { CreateClimateSettingScheduleFormProps } from './CreateClimateSettingScheduleForm.js' - -export const name = 'seam-create-climate-setting-schedule-form' - -export const props: ElementProps = {} - -export { CreateClimateSettingScheduleForm as Component } from './CreateClimateSettingScheduleForm.js' diff --git a/src/lib/seam/components/CreateClimateSettingScheduleForm/CreateClimateSettingScheduleForm.stories.tsx b/src/lib/seam/components/CreateClimateSettingScheduleForm/CreateClimateSettingScheduleForm.stories.tsx deleted file mode 100644 index 502fac05f..000000000 --- a/src/lib/seam/components/CreateClimateSettingScheduleForm/CreateClimateSettingScheduleForm.stories.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { Button, Dialog } from '@mui/material' -import type { Meta, StoryObj } from '@storybook/react' - -import { seamComponentsClassName } from 'lib/seam/SeamProvider.js' -import { useToggle } from 'lib/ui/use-toggle.js' - -import { CreateClimateSettingScheduleForm } from './CreateClimateSettingScheduleForm.js' - -/** - * Coming Soon - * These stories showcase creating a climate setting schedule. - */ -const meta: Meta = { - title: 'Components/CreateClimateSettingScheduleForm', - component: CreateClimateSettingScheduleForm, - tags: ['autodocs'], - parameters: { - design: { - type: 'figma', - url: 'https://www.figma.com/file/WTdzEh4CudGdQFOtuVR3Eh/Thermostat%2FNoise-components?type=design&node-id=1052-90947&mode=design&t=0A3IQFDW4owsQE0f-0', - }, - }, -} - -export default meta - -type Story = StoryObj - -export const Content: Story = { - render: (props) => , -} - -export const InsideModal: Story = { - render: (props) => { - const [open, toggleOpen] = useToggle() - return ( - <> - - - - - - ) - }, -} diff --git a/src/lib/seam/components/CreateClimateSettingScheduleForm/CreateClimateSettingScheduleForm.tsx b/src/lib/seam/components/CreateClimateSettingScheduleForm/CreateClimateSettingScheduleForm.tsx deleted file mode 100644 index 39d54069d..000000000 --- a/src/lib/seam/components/CreateClimateSettingScheduleForm/CreateClimateSettingScheduleForm.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import type { CommonProps } from 'lib/seam/components/common-props.js' -import { useCreateClimateSettingSchedule } from 'lib/seam/thermostats/climate-setting-schedules/use-create-climate-setting-schedule.js' -import { useComponentTelemetry } from 'lib/telemetry/index.js' -import { - ClimateSettingScheduleForm, - type ClimateSettingScheduleFormSubmitData, -} from 'lib/ui/ClimateSettingForm/ClimateSettingScheduleForm.js' - -export interface CreateClimateSettingScheduleFormProps extends CommonProps {} - -export function CreateClimateSettingScheduleForm({ - className, - onBack, -}: CreateClimateSettingScheduleFormProps): JSX.Element | null { - useComponentTelemetry('CreateClimateSettingScheduleForm') - - const { submit, isSubmitting } = useSubmitCreateClimateSettingSchedule(onBack) - - return ( - - ) -} - -function useSubmitCreateClimateSettingSchedule(onSuccess?: () => void): { - submit: (data: ClimateSettingScheduleFormSubmitData) => void - isSubmitting: boolean -} { - const { mutate, isPending: isSubmitting } = useCreateClimateSettingSchedule() - const submit = (data: ClimateSettingScheduleFormSubmitData): void => { - const { name, deviceId, startDate, endDate, climateSetting } = data - - if (isSubmitting) { - return - } - - mutate( - { - name, - device_id: deviceId, - schedule_starts_at: startDate, - schedule_ends_at: endDate, - ...climateSetting, - }, - { - onSuccess, - } - ) - } - - return { submit, isSubmitting } -} diff --git a/src/lib/seam/components/DeviceDetails/DeviceDetails.tsx b/src/lib/seam/components/DeviceDetails/DeviceDetails.tsx index 7e95fa589..29e4ef625 100644 --- a/src/lib/seam/components/DeviceDetails/DeviceDetails.tsx +++ b/src/lib/seam/components/DeviceDetails/DeviceDetails.tsx @@ -33,7 +33,6 @@ export function DeviceDetails({ disableConnectedAccountInformation = false, disableCreateAccessCode = false, disableEditAccessCode = false, - disableClimateSettingSchedules = false, onBack, className, }: DeviceDetailsProps): JSX.Element | null { @@ -56,7 +55,6 @@ export function DeviceDetails({ disableConnectedAccountInformation, disableCreateAccessCode, disableEditAccessCode, - disableClimateSettingSchedules, onBack, className, } diff --git a/src/lib/seam/components/DeviceDetails/LockDeviceDetails.tsx b/src/lib/seam/components/DeviceDetails/LockDeviceDetails.tsx index 6fabfac0a..5c729ead1 100644 --- a/src/lib/seam/components/DeviceDetails/LockDeviceDetails.tsx +++ b/src/lib/seam/components/DeviceDetails/LockDeviceDetails.tsx @@ -31,7 +31,6 @@ export function LockDeviceDetails({ disableDeleteAccessCode, disableResourceIds, disableConnectedAccountInformation, - disableClimateSettingSchedules, onBack, className, }: LockDeviceDetailsProps): JSX.Element | null { @@ -62,7 +61,6 @@ export function LockDeviceDetails({ disableDeleteAccessCode={disableDeleteAccessCode} disableResourceIds={disableResourceIds} disableConnectedAccountInformation={disableConnectedAccountInformation} - disableClimateSettingSchedules={disableClimateSettingSchedules} onBack={toggleAccessCodesOpen} className={className} /> diff --git a/src/lib/seam/components/DeviceDetails/ThermostatDeviceDetails.tsx b/src/lib/seam/components/DeviceDetails/ThermostatDeviceDetails.tsx index 8d06b5b5a..4afb9f271 100644 --- a/src/lib/seam/components/DeviceDetails/ThermostatDeviceDetails.tsx +++ b/src/lib/seam/components/DeviceDetails/ThermostatDeviceDetails.tsx @@ -3,11 +3,8 @@ import { useEffect, useState } from 'react' import { debounce } from 'lib/debounce.js' import { CheckBlackIcon } from 'lib/icons/CheckBlack.js' -import { ChevronWideIcon } from 'lib/icons/ChevronWide.js' -import { NestedClimateSettingScheduleTable } from 'lib/seam/components/ClimateSettingScheduleTable/ClimateSettingScheduleTable.js' import type { NestedSpecificDeviceDetailsProps } from 'lib/seam/components/DeviceDetails/DeviceDetails.js' import { DeviceInfo } from 'lib/seam/components/DeviceDetails/DeviceInfo.js' -import { useClimateSettingSchedules } from 'lib/seam/thermostats/climate-setting-schedules/use-climate-setting-schedules.js' import type { HvacModeSetting, ThermostatDevice, @@ -17,14 +14,12 @@ import { useHeatCoolThermostat } from 'lib/seam/thermostats/use-heat-cool-thermo 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 { 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' 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 { Switch } from 'lib/ui/Switch/Switch.js' import { ClimateModeMenu } from 'lib/ui/thermostat/ClimateModeMenu.js' import { ClimateSettingStatus } from 'lib/ui/thermostat/ClimateSettingStatus.js' import { FanModeMenu } from 'lib/ui/thermostat/FanModeMenu.js' @@ -38,54 +33,15 @@ interface ThermostatDeviceDetailsProps export function ThermostatDeviceDetails({ device, - errorFilter, - warningFilter, - disableLockUnlock, - disableCreateAccessCode, - disableEditAccessCode, - disableDeleteAccessCode, disableResourceIds, disableConnectedAccountInformation, - disableClimateSettingSchedules, onBack, className, }: ThermostatDeviceDetailsProps): JSX.Element | null { - const [climateSettingsOpen, setClimateSettingsOpen] = useState(false) - - const { climateSettingSchedules } = useClimateSettingSchedules({ - device_id: device.device_id, - }) - - if (climateSettingsOpen) { - return ( - { - setClimateSettingsOpen(false) - }} - className={className} - /> - ) - } - if (device == null) { return null } - const climateSettingSchedulesLabel = - climateSettingSchedules?.length !== 1 - ? t.climateSchedules - : t.climateSchedule - return (
@@ -95,28 +51,6 @@ export function ThermostatDeviceDetails({
- {!disableClimateSettingSchedules && ( - - { - setClimateSettingsOpen(true) - }} - > -
- -
-
-
- )} - - {!disableClimateSettingSchedules && ( - - - {device.properties.default_climate_setting != null ? ( - - ) : ( -

{t.none}

- )} -
- - -
- )} + + + {device.properties.default_climate_setting != null ? ( + + ) : ( +

{t.none}

+ )} +
+
-
- - { - mutate({ - device_id: device.device_id, - default_climate_setting: { - manual_override_allowed: checked, - }, - }) - }} - /> - -
- - - - - - ) -} - function FanModeRow({ device }: { device: ThermostatDevice }): JSX.Element { const { mutate, isSuccess, isError } = useSetThermostatFanMode() @@ -430,12 +315,6 @@ function ClimateSettingRow({ const t = { thermostat: 'Thermostat', - climateSchedule: 'scheduled climate', - climateSchedules: 'scheduled climates', - viewingClimateSchedules: 'View scheduled climates', - scheduledClimates: 'Scheduled climates', - scheduledClimatesTooltip: - "Scheduled climates let you automatically change the thermostat's climate at a set time.", currentSettings: 'Current settings', currentSettingsTooltip: 'These are the settings currently on the device. If you change them here, they change on the device.', diff --git a/src/lib/seam/components/DeviceTable/DeviceTable.tsx b/src/lib/seam/components/DeviceTable/DeviceTable.tsx index 996fb4802..356e18568 100644 --- a/src/lib/seam/components/DeviceTable/DeviceTable.tsx +++ b/src/lib/seam/components/DeviceTable/DeviceTable.tsx @@ -68,7 +68,6 @@ export function DeviceTable({ disableDeleteAccessCode = false, disableResourceIds = false, disableConnectedAccountInformation = false, - disableClimateSettingSchedules = false, onBack, className, }: DeviceTableProps = {}): JSX.Element { @@ -117,7 +116,6 @@ export function DeviceTable({ disableDeleteAccessCode={disableDeleteAccessCode} disableResourceIds={disableResourceIds} disableConnectedAccountInformation={disableConnectedAccountInformation} - disableClimateSettingSchedules={disableClimateSettingSchedules} onBack={() => { setSelectedDeviceId(null) }} diff --git a/src/lib/seam/components/common-props.tsx b/src/lib/seam/components/common-props.tsx index df2bb700b..8d843dfc8 100644 --- a/src/lib/seam/components/common-props.tsx +++ b/src/lib/seam/components/common-props.tsx @@ -23,7 +23,6 @@ export interface RequiredCommonProps { disableLockUnlock: boolean | undefined disableResourceIds: boolean | undefined disableConnectedAccountInformation: boolean | undefined - disableClimateSettingSchedules: boolean | undefined } export type CommonProps = Partial diff --git a/src/lib/seam/components/elements.ts b/src/lib/seam/components/elements.ts index 115e3b053..ba9a050ae 100644 --- a/src/lib/seam/components/elements.ts +++ b/src/lib/seam/components/elements.ts @@ -1,7 +1,5 @@ export * as AccessCodeDetails from './AccessCodeDetails/AccessCodeDetails.element.js' export * as AccessCodeTable from './AccessCodeTable/AccessCodeTable.element.js' -export * as ClimateSettingScheduleDetails from './ClimateSettingScheduleDetails/ClimateSettingScheduleDetails.element.js' -export * as ClimateSettingScheduleTable from './ClimateSettingScheduleTable/ClimateSettingScheduleTable.element.js' export * as ConnectAccountButton from './ConnectAccountButton/ConnectAccountButton.element.js' export * as CreateAccessCodeForm from './CreateAccessCodeForm/CreateAccessCodeForm.element.js' export * as DeviceDetails from './DeviceDetails/DeviceDetails.element.js' diff --git a/src/lib/seam/components/index.ts b/src/lib/seam/components/index.ts index 974455479..58451ffaa 100644 --- a/src/lib/seam/components/index.ts +++ b/src/lib/seam/components/index.ts @@ -1,7 +1,5 @@ export * from './AccessCodeDetails/AccessCodeDetails.js' export * from './AccessCodeTable/AccessCodeTable.js' -export * from './ClimateSettingScheduleDetails/ClimateSettingScheduleDetails.js' -export * from './ClimateSettingScheduleTable/ClimateSettingScheduleTable.js' export * from './common-props.js' export * from './ConnectAccountButton/ConnectAccountButton.js' export * from './CreateAccessCodeForm/CreateAccessCodeForm.js' diff --git a/src/lib/seam/index.ts b/src/lib/seam/index.ts index 11d9b69e4..091e8517d 100644 --- a/src/lib/seam/index.ts +++ b/src/lib/seam/index.ts @@ -11,7 +11,5 @@ export * from './devices/use-device.js' export * from './devices/use-device-providers.js' export * from './devices/use-devices.js' export * from './SeamProvider.js' -export * from './thermostats/climate-setting-schedules/use-climate-setting-schedule.js' -export * from './thermostats/climate-setting-schedules/use-climate-setting-schedules.js' export * from './use-seam-client.js' export * from './use-seam-query-result.js' diff --git a/src/lib/seam/thermostats/climate-setting-schedules/use-climate-setting-schedule.ts b/src/lib/seam/thermostats/climate-setting-schedules/use-climate-setting-schedule.ts deleted file mode 100644 index e3bbdbbf1..000000000 --- a/src/lib/seam/thermostats/climate-setting-schedules/use-climate-setting-schedule.ts +++ /dev/null @@ -1,34 +0,0 @@ -import type { - SeamHttpApiError, - ThermostatsClimateSettingSchedulesGetParams, -} from '@seamapi/http/connect' -import type { ClimateSettingSchedule } from '@seamapi/types/connect' -import { useQuery } from '@tanstack/react-query' - -import { useSeamClient } from 'lib/seam/use-seam-client.js' -import type { UseSeamQueryResult } from 'lib/seam/use-seam-query-result.js' - -export type UseClimateSettingScheduleParams = - ThermostatsClimateSettingSchedulesGetParams - -export type UseClimateSettingScheduleData = ClimateSettingSchedule | null - -export function useClimateSettingSchedule( - params: UseClimateSettingScheduleParams -): UseSeamQueryResult<'climateSettingSchedule', UseClimateSettingScheduleData> { - const { client } = useSeamClient() - - const { data, ...rest } = useQuery< - UseClimateSettingScheduleData, - SeamHttpApiError - >({ - enabled: client != null, - queryKey: ['thermostats', 'climate_setting_schedules', 'get', params], - queryFn: async () => { - if (client == null) return null - return await client.thermostats.climateSettingSchedules.get(params) - }, - }) - - return { ...rest, climateSettingSchedule: data } -} diff --git a/src/lib/seam/thermostats/climate-setting-schedules/use-climate-setting-schedules.ts b/src/lib/seam/thermostats/climate-setting-schedules/use-climate-setting-schedules.ts deleted file mode 100644 index f06a105c7..000000000 --- a/src/lib/seam/thermostats/climate-setting-schedules/use-climate-setting-schedules.ts +++ /dev/null @@ -1,53 +0,0 @@ -import type { - SeamHttpApiError, - ThermostatsClimateSettingSchedulesListParams, -} from '@seamapi/http/connect' -import type { ClimateSettingSchedule } from '@seamapi/types/connect' -import { useQuery, useQueryClient } from '@tanstack/react-query' - -import { useSeamClient } from 'lib/seam/use-seam-client.js' -import type { UseSeamQueryResult } from 'lib/seam/use-seam-query-result.js' - -export type UseClimateSettingSchedulesParams = - ThermostatsClimateSettingSchedulesListParams - -export type UseClimateSettingSchedulesData = ClimateSettingSchedule[] - -export function useClimateSettingSchedules( - params: UseClimateSettingSchedulesParams -): UseSeamQueryResult< - 'climateSettingSchedules', - UseClimateSettingSchedulesData -> { - const { client } = useSeamClient() - const queryClient = useQueryClient() - - const { data, ...rest } = useQuery< - UseClimateSettingSchedulesData, - SeamHttpApiError - >({ - enabled: client != null, - queryKey: ['thermostats', 'climate_setting_schedules', 'list', params], - queryFn: async () => { - if (client == null) return [] - const climateSettingSchedules = - await client.thermostats.climateSettingSchedules.list(params) - for (const schedule of climateSettingSchedules) { - queryClient.setQueryData( - [ - 'thermostats', - 'climate_setting_schedules', - 'get', - { - climate_setting_schedule_id: schedule.climate_setting_schedule_id, - }, - ], - schedule - ) - } - return climateSettingSchedules - }, - }) - - return { ...rest, climateSettingSchedules: data } -} diff --git a/src/lib/seam/thermostats/climate-setting-schedules/use-create-climate-setting-schedule.ts b/src/lib/seam/thermostats/climate-setting-schedules/use-create-climate-setting-schedule.ts deleted file mode 100644 index 72decff0d..000000000 --- a/src/lib/seam/thermostats/climate-setting-schedules/use-create-climate-setting-schedule.ts +++ /dev/null @@ -1,53 +0,0 @@ -import type { - SeamHttpApiError, - ThermostatsClimateSettingSchedulesCreateBody, -} from '@seamapi/http/connect' -import type { ClimateSettingSchedule } 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 UseCreateClimateSettingScheduleParams = never - -export type UseCreateClimateSettingScheduleData = ClimateSettingSchedule - -export type UseCreateClimateSettingScheduleMutationVariables = - ThermostatsClimateSettingSchedulesCreateBody - -export function useCreateClimateSettingSchedule(): UseMutationResult< - UseCreateClimateSettingScheduleData, - SeamHttpApiError, - UseCreateClimateSettingScheduleMutationVariables -> { - const { client } = useSeamClient() - const queryClient = useQueryClient() - - return useMutation< - UseCreateClimateSettingScheduleData, - SeamHttpApiError, - UseCreateClimateSettingScheduleMutationVariables - >({ - mutationFn: async (variables) => { - if (client === null) throw new NullSeamClientError() - return await client.thermostats.climateSettingSchedules.create(variables) - }, - onSuccess: (data) => { - queryClient.setQueryData( - [ - 'thermostats', - 'climate_setting_schedules', - 'get', - { climate_setting_schedules: data.climate_setting_schedule_id }, - ], - data - ) - void queryClient.invalidateQueries({ - queryKey: ['thermostats', 'climate_setting_schedules', 'list'], - }) - }, - }) -} diff --git a/src/lib/seam/thermostats/climate-setting-schedules/use-delete-climate-setting-schedule.ts b/src/lib/seam/thermostats/climate-setting-schedules/use-delete-climate-setting-schedule.ts deleted file mode 100644 index 2a990fdef..000000000 --- a/src/lib/seam/thermostats/climate-setting-schedules/use-delete-climate-setting-schedule.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { - SeamHttpApiError, - ThermostatsClimateSettingSchedulesDeleteParams, -} from '@seamapi/http/connect' -import { - useMutation, - type UseMutationResult, - useQueryClient, -} from '@tanstack/react-query' - -import { NullSeamClientError, useSeamClient } from 'lib/seam/use-seam-client.js' - -export type UseDeleteClimateSettingScheduleParams = never - -export type UseDeleteClimateSettingScheduleData = undefined - -export type UseDeleteClimateSettingScheduleMutationVariables = - ThermostatsClimateSettingSchedulesDeleteParams - -export function useDeleteClimateSettingSchedule(): UseMutationResult< - UseDeleteClimateSettingScheduleData, - SeamHttpApiError, - UseDeleteClimateSettingScheduleMutationVariables -> { - const { client } = useSeamClient() - const queryClient = useQueryClient() - - return useMutation< - UseDeleteClimateSettingScheduleData, - SeamHttpApiError, - UseDeleteClimateSettingScheduleMutationVariables - >({ - mutationFn: async (variables) => { - if (client === null) throw new NullSeamClientError() - await client.thermostats.climateSettingSchedules.delete(variables) - }, - onSuccess: (_data, variables) => { - void queryClient.invalidateQueries({ - queryKey: [ - 'thermostats', - 'climate_setting_schedules', - 'get', - { climate_setting_schedules: variables.climate_setting_schedule_id }, - ], - }) - void queryClient.invalidateQueries({ - queryKey: ['thermostats', 'climate_setting_schedules', 'list'], - }) - }, - }) -} diff --git a/src/lib/seam/thermostats/climate-setting-schedules/use-update-climate-setting-schedule.ts b/src/lib/seam/thermostats/climate-setting-schedules/use-update-climate-setting-schedule.ts deleted file mode 100644 index c8bee2a40..000000000 --- a/src/lib/seam/thermostats/climate-setting-schedules/use-update-climate-setting-schedule.ts +++ /dev/null @@ -1,83 +0,0 @@ -import type { - SeamHttpApiError, - ThermostatsClimateSettingSchedulesUpdateBody, -} from '@seamapi/http/connect' -import type { ClimateSettingSchedule } from '@seamapi/types/connect' -import { - useMutation, - type UseMutationResult, - useQueryClient, -} from '@tanstack/react-query' - -import { shake } from 'lib/object.js' -import { NullSeamClientError, useSeamClient } from 'lib/seam/use-seam-client.js' - -export type UseUpdateClimateSettingScheduleParams = never - -export type UseUpdateClimateSettingScheduleData = undefined - -export type UseUpdateClimateSettingScheduleMutationVariables = - ThermostatsClimateSettingSchedulesUpdateBody - -export function useUpdateClimateSettingSchedule(): UseMutationResult< - UseUpdateClimateSettingScheduleData, - SeamHttpApiError, - UseUpdateClimateSettingScheduleMutationVariables -> { - const { client } = useSeamClient() - const queryClient = useQueryClient() - - return useMutation< - UseUpdateClimateSettingScheduleData, - SeamHttpApiError, - UseUpdateClimateSettingScheduleMutationVariables - >({ - mutationFn: async (variables) => { - if (client === null) throw new NullSeamClientError() - await client.thermostats.climateSettingSchedules.update(variables) - }, - onSuccess: (_data, variables) => { - queryClient.setQueryData( - [ - 'thermostats', - 'climate_setting_schedules', - 'get', - { climate_setting_schedules: variables.climate_setting_schedule_id }, - ], - (climateSettingSchedule) => { - if (climateSettingSchedule == null) { - return - } - - return { - ...climateSettingSchedule, - ...shake(variables), - } - } - ) - - queryClient.setQueryData( - ['thermostats', 'climate_setting_schedules', 'list'], - (climateSettingSchedules) => { - if (climateSettingSchedules == null) { - return climateSettingSchedules - } - - return climateSettingSchedules.map((climateSettingSchedule) => { - if ( - climateSettingSchedule.climate_setting_schedule_id === - variables.climate_setting_schedule_id - ) { - return { - ...climateSettingSchedule, - ...shake(variables), - } - } - - return climateSettingSchedule - }) - } - ) - }, - }) -} diff --git a/src/lib/seam/thermostats/use-update-thermostat.ts b/src/lib/seam/thermostats/use-update-thermostat.ts deleted file mode 100644 index c4a3674b7..000000000 --- a/src/lib/seam/thermostats/use-update-thermostat.ts +++ /dev/null @@ -1,90 +0,0 @@ -import type { - SeamHttpApiError, - ThermostatsUpdateBody, -} from '@seamapi/http/connect' -import type { Device } from '@seamapi/types/connect' -import { - useMutation, - type UseMutationResult, - useQueryClient, -} from '@tanstack/react-query' - -import { shake } from 'lib/object.js' -import { NullSeamClientError, useSeamClient } from 'lib/seam/use-seam-client.js' - -export type UseUpdateThermostatParams = never - -export type UseUpdateThermostatData = undefined - -export type UseUpdateThermostatMutationVariables = ThermostatsUpdateBody - -export function useUpdateThermostat(): UseMutationResult< - UseUpdateThermostatData, - SeamHttpApiError, - UseUpdateThermostatMutationVariables -> { - const { client } = useSeamClient() - const queryClient = useQueryClient() - - return useMutation< - UseUpdateThermostatData, - SeamHttpApiError, - UseUpdateThermostatMutationVariables - >({ - mutationFn: async (variables) => { - if (client === null) throw new NullSeamClientError() - await client.thermostats.update(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 - }) - } - ) - }, - }) -} - -const getUpdatedDevice = ( - device: Device, - variables: UseUpdateThermostatMutationVariables -): Device => { - const { properties } = device - if ( - 'default_climate_setting' in properties && - properties.default_climate_setting != null - ) { - return { - ...device, - properties: { - ...properties, - default_climate_setting: { - ...properties.default_climate_setting, - ...shake(variables.default_climate_setting), - }, - }, - } - } - return device -} diff --git a/src/lib/ui/ClimateSettingForm/ClimateSettingScheduleForm.tsx b/src/lib/ui/ClimateSettingForm/ClimateSettingScheduleForm.tsx deleted file mode 100644 index b67596947..000000000 --- a/src/lib/ui/ClimateSettingForm/ClimateSettingScheduleForm.tsx +++ /dev/null @@ -1,189 +0,0 @@ -import classNames from 'classnames' -import { useEffect, useState } from 'react' -import { useForm } from 'react-hook-form' - -import { getSystemTimeZone } from 'lib/dates.js' -import { useSeamClient } from 'lib/index.js' -import { - type ClimateSetting, - type HvacModeSetting, - isThermostatDevice, -} from 'lib/seam/thermostats/thermostat-device.js' -import { ClimateSettingScheduleFormClimateSetting } from 'lib/ui/ClimateSettingForm/ClimateSettingScheduleFormClimateSetting.js' -import { ClimateSettingScheduleFormDefaultClimateSetting } from 'lib/ui/ClimateSettingForm/ClimateSettingScheduleFormDefaultClimateSetting.js' -import { ClimateSettingScheduleFormDeviceSelect } from 'lib/ui/ClimateSettingForm/ClimateSettingScheduleFormDeviceSelect.js' -import { ClimateSettingScheduleFormNameAndSchedule } from 'lib/ui/ClimateSettingForm/ClimateSettingScheduleFormNameAndSchedule.js' -import { ClimateSettingScheduleFormTimeZonePicker } from 'lib/ui/ClimateSettingForm/ClimateSettingScheduleFormTimeZonePicker.js' - -export interface ClimateSettingScheduleFormSubmitData { - name: string - deviceId: string - startDate: string - endDate: string - timeZone: string - climateSetting: ClimateSetting -} - -export interface ClimateSettingScheduleFormProps { - className?: string - onBack?: () => void - isSubmitting: boolean - onSubmit: (data: ClimateSettingScheduleFormSubmitData) => void -} - -export interface ClimateSettingScheduleFormFields { - name: string - deviceId: string - startDate: string - endDate: string - timeZone: string - climateSetting: { - hvacModeSetting: HvacModeSetting - // may have to ignore one or the other fields here on submit - heatingSetPoint: number - coolingSetPoint: number - } -} - -export function ClimateSettingScheduleForm({ - className, - ...props -}: ClimateSettingScheduleFormProps): JSX.Element | null { - return ( -
- -
- ) -} - -function Content({ - onBack, -}: Omit): JSX.Element { - const { client } = useSeamClient() - const { control, watch, resetField } = - useForm({ - defaultValues: { - deviceId: '', - name: '', - startDate: '', - endDate: '', - timeZone: getSystemTimeZone(), - climateSetting: { - hvacModeSetting: 'heat_cool', - heatingSetPoint: 70, - coolingSetPoint: 75, - }, - }, - }) - - const deviceId = watch('deviceId') - const timeZone = watch('timeZone') - - const [page, setPage] = useState< - | 'device_select' - | 'default_setting' - | 'name_and_schedule' - | 'time_zone_select' - | 'climate_setting' - >('device_select') - - const returnToDeviceSelect = (): void => { - resetField('deviceId') - setPage('device_select') - } - - useEffect(() => { - if (page === 'device_select' && deviceId !== '' && client != null) { - client.devices - .get({ device_id: deviceId }) - .then((device) => { - if (!isThermostatDevice(device)) return - - if (device.properties.default_climate_setting != null) { - setPage('name_and_schedule') - return - } - - setPage('default_setting') - }) - .catch(() => {}) - } - }, [client, deviceId, page, setPage]) - - if (page === 'device_select') { - return ( - - ) - } - - if (page === 'default_setting') { - return ( - { - setPage('name_and_schedule') - }} - /> - ) - } - - if (page === 'name_and_schedule') { - return ( - { - setPage('climate_setting') - }} - onChangeTimeZone={() => { - setPage('time_zone_select') - }} - timeZone={timeZone} - /> - ) - } - - if (page === 'time_zone_select') { - return ( - { - setPage('name_and_schedule') - }} - /> - ) - } - - if (page === 'climate_setting') { - return ( - { - setPage('name_and_schedule') - }} - onCancel={onBack} - onSave={() => {}} - /> - ) - } - - return <> -} - -export const t = { - addNewClimateSettingSchedule: 'Add a climate setting schedule', -} diff --git a/src/lib/ui/ClimateSettingForm/ClimateSettingScheduleFormClimateSetting.tsx b/src/lib/ui/ClimateSettingForm/ClimateSettingScheduleFormClimateSetting.tsx deleted file mode 100644 index c2e4f011b..000000000 --- a/src/lib/ui/ClimateSettingForm/ClimateSettingScheduleFormClimateSetting.tsx +++ /dev/null @@ -1,118 +0,0 @@ -import { type Control, Controller } from 'react-hook-form' - -import { useDevice } from 'lib/seam/devices/use-device.js' -import { isThermostatDevice } from 'lib/seam/thermostats/thermostat-device.js' -import { Button } from 'lib/ui/Button.js' -import type { ClimateSettingScheduleFormFields } from 'lib/ui/ClimateSettingForm/ClimateSettingScheduleForm.js' -import { - getSetPointBounds, - type SetPointBounds, -} from 'lib/ui/ClimateSettingForm/set-point-bounds.js' -import { FormField } from 'lib/ui/FormField.js' -import { InputLabel } from 'lib/ui/InputLabel.js' -import { ContentHeader } from 'lib/ui/layout/ContentHeader.js' -import { ClimateSettingControlGroup } from 'lib/ui/thermostat/ClimateSettingControlGroup.js' - -interface ClimateSettingScheduleFormClimateSettingProps { - title: string - control: Control - deviceId: string - onBack: () => void - onCancel: (() => void) | undefined - onSave: () => void -} - -export function ClimateSettingScheduleFormClimateSetting({ - title, - control, - deviceId, - onBack, - onCancel, - onSave, -}: ClimateSettingScheduleFormClimateSettingProps): JSX.Element { - const { device } = useDevice({ - device_id: deviceId, - }) - - if (device == null) return <> - if (!isThermostatDevice(device)) return <> - - const setPointBounds = getSetPointBounds(device) - - return ( - <> - -
-
-
-
- {t.climateSetting} - {t.climateSettingSubHeading} -
- -
-
-
- - -
-
- - ) -} - -interface FormContentProps { - control: Control - setPointBounds: SetPointBounds -} - -function FormContent({ - control, - setPointBounds, -}: FormContentProps): JSX.Element { - return ( - - ( - { - onChange({ ...value, hvacModeSetting: mode }) - }} - coolValue={value.coolingSetPoint} - heatValue={value.heatingSetPoint} - {...setPointBounds} - onCoolValueChange={(coolingSetPoint) => { - onChange({ - ...value, - coolingSetPoint, - }) - }} - onHeatValueChange={(heatingSetPoint) => { - onChange({ - ...value, - heatingSetPoint, - }) - }} - /> - )} - /> - - ) -} - -const t = { - climateSetting: 'Climate setting', - climateSettingSubHeading: 'Choose mode and adjust the climate', - cancel: 'Cancel', - save: 'Save', - next: 'Next', -} diff --git a/src/lib/ui/ClimateSettingForm/ClimateSettingScheduleFormDefaultClimateSetting.tsx b/src/lib/ui/ClimateSettingForm/ClimateSettingScheduleFormDefaultClimateSetting.tsx deleted file mode 100644 index 92520d33d..000000000 --- a/src/lib/ui/ClimateSettingForm/ClimateSettingScheduleFormDefaultClimateSetting.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import { useState } from 'react' - -import { useDevice } from 'lib/seam/devices/use-device.js' -import type { HvacModeSetting } from 'lib/seam/thermostats/thermostat-device.js' -import { Button } from 'lib/ui/Button.js' -import { InputLabel } from 'lib/ui/InputLabel.js' -import { ContentHeader } from 'lib/ui/layout/ContentHeader.js' -import { ClimateSettingControlGroup } from 'lib/ui/thermostat/ClimateSettingControlGroup.js' - -interface ClimateSettingScheduleFormDefaultClimateSettingProps { - title: string - deviceId: string - onBack: () => void - onCancel: (() => void) | undefined - onSave: () => void -} - -export function ClimateSettingScheduleFormDefaultClimateSetting({ - title, - deviceId, - onBack, - onCancel, - onSave, -}: ClimateSettingScheduleFormDefaultClimateSettingProps): JSX.Element { - const { device } = useDevice({ - device_id: deviceId, - }) - - const [mode, setMode] = useState('heat_cool') - const [heatValue, setHeatValue] = useState(70) - const [coolValue, setCoolValue] = useState(75) - - return ( - <> - -
-
-
-
-

{t.defaultClimateMessage}

-
-
- {t.defaultClimate} - {t.defautClimateSubHeading} -
- -
-
-
- - -
-
- - ) -} - -const t = { - defaultClimate: 'Default Climate', - defautClimateSubHeading: - 'Choose the default mode and climate for this device', - defaultClimateMessage: - '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.', - cancel: 'Cancel', - save: 'Save', -} diff --git a/src/lib/ui/ClimateSettingForm/ClimateSettingScheduleFormDeviceSelect.tsx b/src/lib/ui/ClimateSettingForm/ClimateSettingScheduleFormDeviceSelect.tsx deleted file mode 100644 index 6aa7d5970..000000000 --- a/src/lib/ui/ClimateSettingForm/ClimateSettingScheduleFormDeviceSelect.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { type Control, Controller } from 'react-hook-form' - -import type { ClimateSettingScheduleFormFields } from 'lib/ui/ClimateSettingForm/ClimateSettingScheduleForm.js' -import { ContentHeader } from 'lib/ui/layout/ContentHeader.js' -import { ThermostatSelect } from 'lib/ui/thermostat/ThermostatSelect.js' - -interface ClimateSettingScheduleFormDeviceSelectProps { - title: string - control: Control - onBack: (() => void) | undefined -} - -export function ClimateSettingScheduleFormDeviceSelect({ - title, - control, - onBack, -}: ClimateSettingScheduleFormDeviceSelectProps): JSX.Element { - return ( - <> - -
- ( - { - onChange(deviceId) - }} - /> - )} - /> -
- - ) -} diff --git a/src/lib/ui/ClimateSettingForm/ClimateSettingScheduleFormNameAndSchedule.tsx b/src/lib/ui/ClimateSettingForm/ClimateSettingScheduleFormNameAndSchedule.tsx deleted file mode 100644 index 5bd741ae6..000000000 --- a/src/lib/ui/ClimateSettingForm/ClimateSettingScheduleFormNameAndSchedule.tsx +++ /dev/null @@ -1,120 +0,0 @@ -import { type Control, Controller } from 'react-hook-form' - -import { formatTimeZone } from 'lib/dates.js' -import { ChevronRightIcon } from 'lib/icons/ChevronRight.js' -import { useDevice } from 'lib/seam/devices/use-device.js' -import { Button } from 'lib/ui/Button.js' -import type { ClimateSettingScheduleFormFields } from 'lib/ui/ClimateSettingForm/ClimateSettingScheduleForm.js' -import { DateTimePicker } from 'lib/ui/DateTimePicker/DateTimePicker.js' -import { FormField } from 'lib/ui/FormField.js' -import { InputLabel } from 'lib/ui/InputLabel.js' -import { ContentHeader } from 'lib/ui/layout/ContentHeader.js' -import { TextField } from 'lib/ui/TextField/TextField.js' - -interface ClimateSettingScheduleFormNameAndScheduleProps { - title: string - control: Control - deviceId: string - timeZone: string - onBack: () => void - onCancel: (() => void) | undefined - onNext: () => void - onChangeTimeZone: () => void -} - -export function ClimateSettingScheduleFormNameAndSchedule({ - title, - control, - deviceId, - timeZone, - onBack, - onCancel, - onNext, - onChangeTimeZone, -}: ClimateSettingScheduleFormNameAndScheduleProps): JSX.Element { - const { device } = useDevice({ - device_id: deviceId, - }) - - return ( - <> - -
-
-
- - {t.nameInputLabel} - { - return ( - - ) - }} - /> - - - - {t.startTimeLabel} -
- {t.selectedTimeZoneLabel} - - {formatTimeZone(timeZone)} - - -
- ( - - )} - /> -
- - {t.endTimeLabel} - ( - - )} - /> - -
-
-
- - -
-
- - ) -} - -const t = { - nameInputLabel: 'Name the climate setting schedule', - startTimeLabel: 'Start time', - endTimeLabel: 'End time', - addNewClimateSettingSchedule: 'Add a climate setting schedule', - cancel: 'Cancel', - save: 'Save', - next: 'Next', - selectedTimeZoneLabel: 'All times in', -} diff --git a/src/lib/ui/ClimateSettingForm/ClimateSettingScheduleFormTimeZonePicker.tsx b/src/lib/ui/ClimateSettingForm/ClimateSettingScheduleFormTimeZonePicker.tsx deleted file mode 100644 index 396371d37..000000000 --- a/src/lib/ui/ClimateSettingForm/ClimateSettingScheduleFormTimeZonePicker.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { useState } from 'react' -import { type Control, Controller } from 'react-hook-form' - -import type { ClimateSettingScheduleFormFields } from 'lib/ui/ClimateSettingForm/ClimateSettingScheduleForm.js' -import { ContentHeader } from 'lib/ui/layout/ContentHeader.js' -import { TimeZonePicker } from 'lib/ui/TimeZonePicker/TimeZonePicker.js' - -interface ClimateSettingScheduleFormTimeZonePickerProps { - control: Control - onClose: () => void -} - -export function ClimateSettingScheduleFormTimeZonePicker({ - control, - onClose, -}: ClimateSettingScheduleFormTimeZonePickerProps): JSX.Element { - const [title, setTitle] = useState(t.titleAuto) - - return ( - <> - -
- ( - { - setTitle(manualTimeZoneSelected ? t.titleManual : t.titleAuto) - }} - /> - )} - /> -
- - ) -} - -const t = { - titleAuto: 'Time Zone (automatic)', - titleManual: 'Time Zone (manual)', -} diff --git a/src/lib/ui/thermostat/FanModeMenu.tsx b/src/lib/ui/thermostat/FanModeMenu.tsx index fbd6a2444..e8c3b2780 100644 --- a/src/lib/ui/thermostat/FanModeMenu.tsx +++ b/src/lib/ui/thermostat/FanModeMenu.tsx @@ -49,4 +49,5 @@ export function FanModeMenu({ mode, onChange }: FanModeMenuProps): JSX.Element { const t = { auto: 'Auto', on: 'On', + circulate: 'Circulate', }