Files
mocoapp-browser-extension/src/js/components/Form.js
2019-12-24 11:42:43 +01:00

155 lines
4.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, { Component } from "react"
import PropTypes from "prop-types"
import Select from "components/Select"
import { formatDate } from "utils"
import cn from "classnames"
import StopWatch from "components/shared/StopWatch"
class Form extends Component {
static propTypes = {
changeset: PropTypes.shape({
assignment_id: PropTypes.number.isRequired,
billable: PropTypes.bool.isRequired,
date: PropTypes.string.isRequired,
task_id: PropTypes.number.isRequired,
description: PropTypes.string,
remote_id: PropTypes.string,
remote_service: PropTypes.string,
remote_url: PropTypes.string,
seconds: PropTypes.number,
hours: PropTypes.string,
}).isRequired,
errors: PropTypes.object,
projects: PropTypes.array.isRequired,
onChange: PropTypes.func.isRequired,
onSubmit: PropTypes.func.isRequired,
}
static defaultProps = {
inline: true,
}
isValid() {
const { changeset } = this.props
return (
["assignment_id", "task_id"].map(prop => changeset[prop]).every(Boolean) &&
(changeset.date === formatDate(new Date()) || changeset.seconds > 0)
)
}
get isTimerStartable() {
const {
changeset: { seconds, date },
} = this.props
return date === formatDate(new Date()) && seconds === 0
}
buttonStyle() {
const styleMap = {
true: {
border: "none",
borderRadius: "50%",
width: "60px",
height: "60px",
marginTop: "22px",
transition: "all 0.2s ease-in-out",
},
false: {
border: "none",
width: "50px",
height: "36px",
marginTop: "35px",
transition: "all 0.2s ease-in-out",
},
}
return styleMap[this.isTimerStartable]
}
handleTextareaKeyDown = event => {
const { onSubmit } = this.props
if (event.key === "Enter") {
event.preventDefault()
this.isValid() && onSubmit(event)
}
}
render() {
const { projects, changeset, errors, onChange, onSubmit } = this.props
const project = Select.findOptionByValue(projects, changeset.assignment_id)
return (
<form onSubmit={onSubmit}>
<div
className={cn("form-group", {
"has-error": errors.assignment_id || errors.task_id,
})}
>
<Select
className="moco-bx-select"
name="assignment_id"
placeholder="Auswählen..."
options={projects}
value={changeset.assignment_id}
hasError={!!errors.assignment_id}
onChange={onChange}
/>
<Select
className="moco-bx-select"
name="task_id"
placeholder="Auswählen..."
options={project?.tasks || []}
value={changeset.task_id}
onChange={onChange}
hasError={!!errors.task_id}
noOptionsMessage={() => "Zuerst Projekt wählen"}
/>
{errors.assignment_id ? (
<div className="form-error">{errors.assignment_id.join("; ")}</div>
) : null}
{errors.task_id ? <div className="form-error">{errors.task_id.join("; ")}</div> : null}
</div>
<div className={cn("form-group", { "has-error": errors.hours })}>
<input
name="hours"
className="form-control"
onChange={onChange}
value={changeset.hours}
placeholder="0:00"
autoComplete="off"
autoFocus
/>
{errors.hours ? <div className="form-error">{errors.hours.join("; ")}</div> : null}
</div>
<div className={cn("form-group", { "has-error": errors.description })}>
<textarea
name="description"
onChange={onChange}
value={changeset.description}
placeholder="Beschreibung der Tätigkeit optional"
maxLength={255}
rows={3}
onKeyDown={this.handleTextareaKeyDown}
/>
{errors.description ? (
<div className="form-error">{errors.description.join("; ")}</div>
) : null}
</div>
<button
type="submit"
className="moco-bx-btn"
disabled={!this.isValid()}
style={this.buttonStyle()}
>
{this.isTimerStartable ? <StopWatch /> : "OK"}
</button>
</form>
)
}
}
export default Form