diff --git a/frontend/src/component/Entry/Project.js b/frontend/src/component/Entry/Project.js new file mode 100644 index 0000000..16f4b97 --- /dev/null +++ b/frontend/src/component/Entry/Project.js @@ -0,0 +1,74 @@ +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import { observer } from 'mobx-react'; +import { observable } from 'mobx'; +import { sortBy } from 'lodash'; +import { EntryItemProject } from '../EntryList'; +import { Entry } from 'store/Entry'; +import { ProjectStore } from 'store/Project'; +import InputSelect from '../InputSelect'; + +function formatProjectToOption(project) { + return { + value: String(project.id), + label: project.name, + }; +} + +@observer +export default class EntryProject extends Component { + static propTypes = { + entry: PropTypes.instanceOf(Entry).isRequired, + projectStore: PropTypes.instanceOf(ProjectStore).isRequired, + allowEdit: PropTypes.bool, + }; + + @observable editing = false; + + handleBlur = () => { + this.editing = false; + this.props.entry.save(); + }; + + handleClick = () => { + if (this.props.allowEdit) { + this.editing = true; + } + }; + + handleChange = (name, value) => { + this.props.entry.project = isNaN(value) ? null : parseInt(value); + }; + + render() { + const { entry, allowEdit } = this.props; + const project = entry.project + ? this.props.projectStore.get(entry.project) + : null; + + let projectOptions = this.props.projectStore.map(formatProjectToOption); + projectOptions = sortBy(projectOptions, m => m.label.toLowerCase()); + + if (this.editing) { + return ( + + + + ); + } + return ( + + {project ? project.name : No project} + + ); + } +} diff --git a/frontend/src/component/EntryList.js b/frontend/src/component/EntryList.js index ed2aea7..f5af09a 100644 --- a/frontend/src/component/EntryList.js +++ b/frontend/src/component/EntryList.js @@ -20,12 +20,15 @@ export const EntryDay = styled.div` export const EntryItemDescription = styled.div` font-weight: bold; + margin-right: 20px; flex: 3; cursor: ${props => (props.allowEdit ? 'pointer' : 'default')}; `; export const EntryItemProject = styled.div` flex: 1; + margin-right: 20px; + cursor: ${props => (props.allowEdit ? 'pointer' : 'default')}; `; export const EntryItemTime = styled.div` diff --git a/frontend/src/component/InputSelect.js b/frontend/src/component/InputSelect.js index b8e1e36..dd98f58 100644 --- a/frontend/src/component/InputSelect.js +++ b/frontend/src/component/InputSelect.js @@ -6,23 +6,23 @@ import styled from 'styled-components'; const StyledSelect = styled(Select)` .Select-control { - height: 48px; + height: ${props => (props.small ? '35' : '48')}px; border: 0; border-radius: 8px; cursor: pointer; } .Select-input { - height: 48px; + height: ${props => (props.small ? '35' : '48')}px; } .Select-input > input { - line-height: 28px; + line-height: ${props => (props.small ? '14' : '28')}px; } .Select-placeholder, .Select-control .Select-value { - line-height: 48px !important; + line-height: ${props => (props.small ? '35' : '48')}px!important; } .Select-value-label { @@ -52,6 +52,9 @@ export default class InputSelect extends Component { options: MobxTypes.arrayOrObservableArray.isRequired, value: PropTypes.string, placeholder: PropTypes.string, + autoFocus: PropTypes.bool, + onBlur: PropTypes.func, + small: PropTypes.bool, }; static defaultProps = { @@ -77,6 +80,9 @@ export default class InputSelect extends Component { options={this.props.options} onChange={this.handleChange} placeholder={this.props.placeholder} + autofocus={this.props.autoFocus} + onBlur={this.props.onBlur} + small={this.props.small} /> ); } diff --git a/frontend/src/container/EntryOverviewItem.js b/frontend/src/container/EntryOverviewItem.js index 9b3323e..200fb1e 100644 --- a/frontend/src/container/EntryOverviewItem.js +++ b/frontend/src/container/EntryOverviewItem.js @@ -13,6 +13,7 @@ import { UserStore } from 'store/User'; import { Entry } from 'store/Entry'; import IconDelete from 'image/icon-delete.svg'; import EntryDescription from 'component/Entry/Description'; +import EntryProject from 'component/Entry/Project'; function formatDiffMinutes(minutes) { const hours = Math.floor(minutes / 60); @@ -36,11 +37,9 @@ export default class EntryOverviewItem extends Component { }; render() { - const { entry, allowEdit } = this.props; + const { entry, allowEdit, projectStore } = this.props; const diffMinutes = entry.differenceInMinutes; - const project = entry.project - ? this.props.projectStore.get(entry.project) - : null; + let userColumn = null; if (this.props.userStore) { const user = entry.user @@ -50,9 +49,11 @@ export default class EntryOverviewItem extends Component { } return ( - - {project ? project.name : No project} - + {entry.startedAt.format('H:mm')}