mirror of
https://github.com/usatiuk/ustk-todolist.git
synced 2025-10-28 23:57:49 +01:00
edit todos
This commit is contained in:
42
src/App.css
42
src/App.css
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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)),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user