edit todos

This commit is contained in:
2018-05-27 18:52:04 +03:00
parent cc64fe78b8
commit c7a4e49c36
6 changed files with 122 additions and 16 deletions

View File

@@ -102,7 +102,35 @@ li:first-child .item {
font-size: 0.75rem;
transition: 0.3s ease-in-out;
overflow: hidden;
box-shadow: inset -3px 0 3px -3px rgba(0, 0, 0, 0.5);
box-shadow: inset -3px 0 6px -3px rgba(0, 0, 0, 0.5);
}
.edit {
flex-shrink: 0;
box-sizing: border-box;
padding: 0.5rem;
text-align: center;
background-color: lightcyan;
border-top: 1px solid #dddddd;
max-width: 2rem;
font-size: 0.75rem;
transition: 0.3s ease-in-out;
overflow: hidden;
box-shadow: inset -3px 0 6px -3px rgba(0, 0, 0, 0.5);
}
.save {
flex-shrink: 0;
box-sizing: border-box;
padding: 0.5rem;
text-align: center;
background-color: lightgreen;
border-top: 1px solid #dddddd;
max-width: 2rem;
font-size: 0.75rem;
transition: 0.3s ease-in-out;
overflow: hidden;
box-shadow: inset -3px 0 6px -3px rgba(0, 0, 0, 0.5);
}
.todo {
@@ -116,6 +144,18 @@ li:first-child .item {
transition: 0.1s ease-in-out;
}
.todo--input {
border: none;
margin: 0;
padding: 0;
box-sizing: border-box;
word-wrap: break-word;
max-width: 100%;
flex-grow: 2;
flex-shrink: 1;
transition: 0.1s ease-in-out;
}
.disabled {
max-width: 0;
padding: 0.5rem 0;

View File

@@ -1,9 +1,19 @@
import React from 'react';
import ReactDOM from 'react-dom';
import thunk from 'redux-thunk';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import App from './App';
import todoApp from './reducers';
it('renders without crashing', () => {
const store = createStore(todoApp, applyMiddleware(thunk));
const div = document.createElement('div');
ReactDOM.render(<App />, div);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
div,
);
ReactDOM.unmountComponentAtNode(div);
});

View File

@@ -1,4 +1,4 @@
import { faTrash } from '@fortawesome/free-solid-svg-icons';
import { faTrash, faEdit, faCheck } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import * as React from 'react';
import PropTypes from 'prop-types';
@@ -11,29 +11,73 @@ class Todo extends React.Component {
};
this.onMouseOver = this.onMouseOver.bind(this);
this.onMouseOut = this.onMouseOut.bind(this);
this.startEdit = this.startEdit.bind(this);
this.stopEdit = this.stopEdit.bind(this);
}
onMouseOver() {
this.setState({
...this.state,
hover: true,
});
}
onMouseOut() {
this.setState({
...this.state,
hover: false,
});
}
startEdit() {
this.setState({
...this.state,
editing: true,
});
}
stopEdit(value) {
this.props.editTodo(value);
this.setState({
...this.state,
editing: false,
});
}
render() {
const deleteClasses = ['delete'];
if (!this.state.hover) {
deleteClasses.push('disabled');
}
const editClasses = ['edit'];
if (!this.state.hover) {
editClasses.push('disabled');
}
const todoClasses = ['todo'];
if (this.props.todo.completed) {
todoClasses.push('done');
}
if (this.state.editing) {
let input;
return (
<li>
<div className="save" onClick={() => this.stopEdit(input.value)}>
<FontAwesomeIcon icon={faCheck} />
</div>
<div className={todoClasses.join(' ')}>
<input
className="todo--input"
type="text"
defaultValue={this.props.todo.text}
ref={(node) => {
input = node;
}}
/>
</div>
</li>
);
}
return (
<li
onMouseOver={this.onMouseOver}
@@ -41,10 +85,13 @@ class Todo extends React.Component {
onMouseOut={this.onMouseOut}
onBlur={this.onMouseOut}
>
<div className={deleteClasses.join(' ')} onClick={this.props.handleDelete}>
<div className={deleteClasses.join(' ')} onClick={this.props.removeTodo}>
<FontAwesomeIcon icon={faTrash} />
</div>
<div className={todoClasses.join(' ')} onClick={this.props.onClick}>
<div className={editClasses.join(' ')} onClick={this.startEdit}>
<FontAwesomeIcon icon={faEdit} />
</div>
<div className={todoClasses.join(' ')} onClick={this.props.toggleTodo}>
{this.props.todo.text}
</div>
</li>
@@ -58,8 +105,9 @@ Todo.propTypes = {
text: PropTypes.string.isRequired,
completed: PropTypes.bool.isRequired,
}).isRequired,
handleDelete: PropTypes.func.isRequired,
onClick: PropTypes.func.isRequired,
removeTodo: PropTypes.func.isRequired,
toggleTodo: PropTypes.func.isRequired,
editTodo: PropTypes.func.isRequired,
};
export default Todo;

View File

@@ -8,8 +8,9 @@ export default function TodosContainer(props) {
<Todo
key={todo.id}
todo={todo}
onClick={() => props.onTodoClick(todo.id)}
handleDelete={() => props.handleDelete(todo.id)}
toggleTodo={() => props.toggleTodo(todo.id)}
removeTodo={() => props.removeTodo(todo.id)}
editTodo={text => props.editTodo(todo.id, text)}
/>
));
return <ul id="list">{todos}</ul>;
@@ -21,6 +22,7 @@ TodosContainer.propTypes = {
text: PropTypes.string.isRequired,
completed: PropTypes.bool.isRequired,
})).isRequired,
handleDelete: PropTypes.func.isRequired,
onTodoClick: PropTypes.func.isRequired,
removeTodo: PropTypes.func.isRequired,
toggleTodo: PropTypes.func.isRequired,
editTodo: PropTypes.func.isRequired,
};

View File

@@ -1,6 +1,6 @@
import { connect } from 'react-redux';
import TodoList from '../components/TodoList';
import { toggleTodo, removeTodo } from '../actions';
import { toggleTodo, removeTodo, editTodo } from '../actions';
import getVisibleTodos from './getVisibleTodos';
@@ -26,8 +26,9 @@ function mapStateToProps(state) {
function mapDispatchToProps(dispatch) {
return {
onTodoClick: id => dispatch(toggleTodo(id)),
handleDelete: id => dispatch(removeTodo(id)),
toggleTodo: id => dispatch(toggleTodo(id)),
removeTodo: id => dispatch(removeTodo(id)),
editTodo: (id, text) => dispatch(editTodo(id, text)),
};
}

View File

@@ -14,13 +14,17 @@ import {
ADD_LIST,
REMOVE_LIST,
EDIT_LIST,
EDIT_TODO,
} from '../actions';
import list from './list';
export default function lists(
state = {
dirty: true, fetching: false, lists: {}, list: '',
dirty: true,
fetching: false,
lists: {},
list: '',
},
action,
) {
@@ -70,6 +74,7 @@ export default function lists(
};
case RECIEVE_TODOS:
case ADD_TODO:
case EDIT_TODO:
case INVALIDATE_TODOS:
case VALIDATE_TODOS:
case REQUEST_TODOS: