180 lines
4.0 KiB
JavaScript
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';
|