homehub/packages/homehub_tradfri/src/TradfriWidgetView.js

180 lines
4.0 KiB
JavaScript

import {FatalError, Widget} from '@bthlabs/homehub-components';
import {
IconArrowsRotate, IconBasicLightbulb, Icon,
} from '@bthlabs/homehub-icons';
import ClassName from 'classnames';
import React from 'react';
import {Form} from 'react-bootstrap';
import './TradfriWidgetView.scss';
export const TradfriWidgetSettingsView = (props) => {
const onHostInputChange = React.useCallback(
(event) => {
props.setNextCharacteristics({
...props.nextCharacteristics,
host: event.target.value,
});
},
[props]
);
const onKeyInputChange = React.useCallback(
(event) => {
props.setNextCharacteristics({
...props.nextCharacteristics,
key: event.target.value,
});
},
[props]
);
if (!props.nextCharacteristics) {
return null;
}
return (
<Form>
<Form.Group controlId="input-host">
<Form.Label>Host</Form.Label>
<Form.Control
size="sm"
value={props.nextCharacteristics.host}
onChange={onHostInputChange}
/>
</Form.Group>
<Form.Group controlId="input-key">
<Form.Label>Key</Form.Label>
<Form.Control
size="sm"
value={props.nextCharacteristics.key}
onChange={onKeyInputChange}
/>
</Form.Group>
</Form>
);
};
export const Group = (props) => {
const lights = React.useMemo(
() => {
return props.lights.filter((light) => {
return props.group.member_ids.includes(light.id);
});
},
[props]
);
const isOn = React.useMemo(
() => {
return lights.every((light) => {
return light.state;
});
},
[lights]
);
const onClick = React.useCallback(
() => {
props.onSetLightsState(
lights.map((light) => {
return light.id;
}),
!isOn
);
},
[props, lights, isOn]
);
const groupClassName = ClassName('group', {
'group-on': isOn,
});
return (
<div className={groupClassName} onClick={onClick}>
<span _hint="GroupName">{props.group.name}</span>
<Icon icon={IconBasicLightbulb} size={24} />
</div>
);
};
export const TradfriWidgetView = (props) => {
const onGroupSetLightsState = React.useCallback(
(lightIds, nextState) => {
(async () => {
const nextServiceState = {
data: {
...props.serviceState.data(),
lights: props.serviceState.data().lights.map((light) => {
if (lightIds.includes(light.id)) {
return {
...light,
state: nextState,
};
}
return light;
}),
},
};
props.setServiceState(nextServiceState);
await props.service.setLightsState(lightIds, nextState);
})();
},
[props]
);
if (props.serviceState === null) {
return null;
}
const className = ClassName('TradfriWidgetView', {
'is-loading': (
props.serviceState.isLoading() || props.serviceState.hasFatalError()
),
});
return (
<Widget className={className} {...props}>
{props.serviceState.isLoading() &&
<Icon
_hint="Loader"
className="animation-loading loader"
icon={IconArrowsRotate}
size={78}
/>
}
{props.serviceState.hasData() && props.serviceState.data().groups.map((group) => {
return (
<Group
key={`${group.id}`}
group={group}
lights={props.serviceState.data().lights}
onSetLightsState={onGroupSetLightsState}
/>
);
})}
{props.serviceState.hasFatalError() &&
<FatalError
service={props.service}
serviceState={props.serviceState}
/>
}
</Widget>
);
};
TradfriWidgetView.defaultLayout = {
h: 4,
w: 6,
};
TradfriWidgetView.icon = IconBasicLightbulb;
TradfriWidgetView.layoutConstraints = {
minH: 4,
minW: 6,
};
TradfriWidgetView.settingsView = TradfriWidgetSettingsView;
TradfriWidgetView.title = 'Tradfri';