You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
187 lines
5.9 KiB
187 lines
5.9 KiB
7 years ago
|
import classNames = require("classnames");
|
||
|
import { observer } from "mobx-react";
|
||
7 years ago
|
import * as React from "react";
|
||
7 years ago
|
import { SortableContainer, SortableElement, SortableHandle, SortEnd } from "react-sortable-hoc";
|
||
|
import { Button, Form, Icon, List } from "semantic-ui-react";
|
||
7 years ago
|
|
||
7 years ago
|
import { DurationView, SectionChooser } from "@client/components/index";
|
||
7 years ago
|
import { Duration } from "@common/Duration";
|
||
7 years ago
|
import { ProgramItem, Section } from "@common/sprinklersRpc";
|
||
|
|
||
7 years ago
|
import "@client/styles/ProgramSequenceView";
|
||
7 years ago
|
|
||
7 years ago
|
type ItemChangeHandler = (index: number, newItem: ProgramItem) => void;
|
||
|
type ItemRemoveHandler = (index: number) => void;
|
||
|
|
||
|
const Handle = SortableHandle(() => <Button basic icon><Icon name="bars"/></Button>);
|
||
7 years ago
|
|
||
7 years ago
|
@observer
|
||
|
class ProgramSequenceItem extends React.Component<{
|
||
7 years ago
|
sequenceItem: ProgramItem,
|
||
|
idx: number,
|
||
|
sections: Section[],
|
||
|
editing: boolean,
|
||
|
onChange: ItemChangeHandler,
|
||
|
onRemove: ItemRemoveHandler,
|
||
7 years ago
|
}> {
|
||
|
renderContent() {
|
||
7 years ago
|
const { editing, sequenceItem, sections } = this.props;
|
||
7 years ago
|
const section = sections[sequenceItem.section];
|
||
|
const duration = Duration.fromSeconds(sequenceItem.duration);
|
||
|
|
||
|
if (editing) {
|
||
|
return (
|
||
7 years ago
|
<Form.Group>
|
||
7 years ago
|
<Button icon negative onClick={this.onRemove}>
|
||
|
<Icon name="cancel" />
|
||
|
</Button>
|
||
7 years ago
|
<SectionChooser
|
||
|
label="Section"
|
||
|
sections={sections}
|
||
|
value={section}
|
||
|
onChange={this.onSectionChange}
|
||
|
/>
|
||
|
<DurationView
|
||
|
label="Duration"
|
||
|
duration={duration}
|
||
|
onDurationChange={this.onDurationChange}
|
||
|
/>
|
||
|
</Form.Group>
|
||
|
);
|
||
|
} else {
|
||
|
return (
|
||
|
<React.Fragment>
|
||
|
<List.Header>{section.toString()}</List.Header>
|
||
|
<List.Description>for {duration.toString()}</List.Description>
|
||
|
</React.Fragment>
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
render() {
|
||
7 years ago
|
const { editing } = this.props;
|
||
7 years ago
|
return (
|
||
7 years ago
|
<li className="programSequence-item ui form">
|
||
|
{editing ? <Handle /> : <List.Icon name="caret right"/>}
|
||
7 years ago
|
<List.Content>{this.renderContent()}</List.Content>
|
||
7 years ago
|
</li>
|
||
7 years ago
|
);
|
||
7 years ago
|
}
|
||
|
|
||
|
private onSectionChange = (newSection: Section) => {
|
||
7 years ago
|
this.props.onChange(this.props.idx, new ProgramItem({
|
||
7 years ago
|
...this.props.sequenceItem, section: newSection.id,
|
||
|
}));
|
||
|
}
|
||
|
|
||
|
private onDurationChange = (newDuration: Duration) => {
|
||
7 years ago
|
this.props.onChange(this.props.idx, new ProgramItem({
|
||
7 years ago
|
...this.props.sequenceItem, duration: newDuration.toSeconds(),
|
||
|
}));
|
||
|
}
|
||
7 years ago
|
|
||
|
private onRemove = () => {
|
||
|
this.props.onRemove(this.props.idx);
|
||
|
}
|
||
7 years ago
|
}
|
||
|
|
||
7 years ago
|
const ProgramSequenceItemD = SortableElement(ProgramSequenceItem);
|
||
|
|
||
7 years ago
|
const ProgramSequenceList = SortableContainer(observer((props: {
|
||
7 years ago
|
className: string,
|
||
|
list: ProgramItem[],
|
||
|
sections: Section[],
|
||
7 years ago
|
editing: boolean,
|
||
|
onChange: ItemChangeHandler,
|
||
|
onRemove: ItemRemoveHandler,
|
||
7 years ago
|
}) => {
|
||
7 years ago
|
const { className, list, sections, ...rest } = props;
|
||
7 years ago
|
const listItems = list.map((item, index) => {
|
||
|
const key = `item-${index}`;
|
||
|
return (
|
||
|
<ProgramSequenceItemD
|
||
7 years ago
|
{...rest}
|
||
7 years ago
|
key={key}
|
||
7 years ago
|
sequenceItem={item}
|
||
7 years ago
|
index={index}
|
||
7 years ago
|
idx={index}
|
||
|
sections={sections}
|
||
7 years ago
|
/>
|
||
|
);
|
||
|
});
|
||
|
return <ul className={className}>{listItems}</ul>;
|
||
|
}), { withRef: true });
|
||
|
|
||
7 years ago
|
@observer
|
||
7 years ago
|
class ProgramSequenceView extends React.Component<{
|
||
7 years ago
|
sequence: ProgramItem[], sections: Section[], editing?: boolean,
|
||
|
}> {
|
||
|
render() {
|
||
|
const { sequence, sections } = this.props;
|
||
|
const editing = this.props.editing || false;
|
||
|
const className = classNames("programSequence", { editing });
|
||
7 years ago
|
let addButton: React.ReactNode = null;
|
||
|
if (editing) {
|
||
|
addButton = (
|
||
|
<Button onClick={this.addItem}>
|
||
|
<Icon name="add"/>
|
||
|
Add item
|
||
|
</Button>
|
||
|
);
|
||
|
}
|
||
7 years ago
|
return (
|
||
7 years ago
|
<div>
|
||
|
<ProgramSequenceList
|
||
|
className={className}
|
||
|
useDragHandle
|
||
|
helperClass="dragging"
|
||
|
list={sequence}
|
||
|
sections={sections}
|
||
|
editing={editing}
|
||
|
onChange={this.changeItem}
|
||
|
onRemove={this.removeItem}
|
||
|
onSortEnd={this.onSortEnd}
|
||
|
/>
|
||
7 years ago
|
{addButton}
|
||
7 years ago
|
</div>
|
||
7 years ago
|
);
|
||
7 years ago
|
}
|
||
|
|
||
7 years ago
|
private changeItem: ItemChangeHandler = (index, newItem) => {
|
||
7 years ago
|
this.props.sequence[index] = newItem;
|
||
|
}
|
||
7 years ago
|
|
||
7 years ago
|
private removeItem: ItemRemoveHandler = (index) => {
|
||
|
this.props.sequence.splice(index, 1);
|
||
|
}
|
||
|
|
||
7 years ago
|
private addItem = () => {
|
||
|
let sectionId = 0;
|
||
|
for (const section of this.props.sections) {
|
||
|
const sectionNotIncluded = this.props.sequence
|
||
|
.every((sequenceItem) =>
|
||
|
sequenceItem.section !== section.id);
|
||
|
if (sectionNotIncluded) {
|
||
|
sectionId = section.id;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
const item = new ProgramItem({
|
||
|
section: sectionId,
|
||
|
duration: new Duration(5, 0).toSeconds(),
|
||
|
});
|
||
|
this.props.sequence.push(item);
|
||
|
}
|
||
|
|
||
7 years ago
|
private onSortEnd = ({oldIndex, newIndex}: SortEnd) => {
|
||
|
const { sequence: array } = this.props;
|
||
|
if (newIndex >= array.length) {
|
||
|
return;
|
||
|
}
|
||
|
array.splice(newIndex, 0, array.splice(oldIndex, 1)[0]);
|
||
|
}
|
||
7 years ago
|
}
|
||
7 years ago
|
|
||
|
const ProgramSequenceViewD = SortableContainer(ProgramSequenceView);
|
||
|
export default ProgramSequenceViewD;
|