mirror of
https://github.com/usatiuk/ustk-todolist.git
synced 2025-10-28 07:37:49 +01:00
offline remove, toggle, edit todos
This commit is contained in:
28
package-lock.json
generated
28
package-lock.json
generated
@@ -3084,12 +3084,14 @@
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
@@ -3104,17 +3106,20 @@
|
||||
"code-point-at": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
@@ -3231,7 +3236,8 @@
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
@@ -3243,6 +3249,7 @@
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"number-is-nan": "^1.0.0"
|
||||
}
|
||||
@@ -3257,6 +3264,7 @@
|
||||
"version": "3.0.4",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
@@ -3264,12 +3272,14 @@
|
||||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"minipass": {
|
||||
"version": "2.2.4",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"safe-buffer": "^5.1.1",
|
||||
"yallist": "^3.0.0"
|
||||
@@ -3288,6 +3298,7 @@
|
||||
"version": "0.5.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
}
|
||||
@@ -3368,7 +3379,8 @@
|
||||
"number-is-nan": {
|
||||
"version": "1.0.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
@@ -3380,6 +3392,7 @@
|
||||
"version": "1.4.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
@@ -3501,6 +3514,7 @@
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"code-point-at": "^1.0.0",
|
||||
"is-fullwidth-code-point": "^1.0.0",
|
||||
|
||||
28
react/package-lock.json
generated
28
react/package-lock.json
generated
@@ -4143,11 +4143,13 @@
|
||||
},
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
@@ -4160,15 +4162,18 @@
|
||||
},
|
||||
"code-point-at": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
@@ -4271,7 +4276,8 @@
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
@@ -4281,6 +4287,7 @@
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"number-is-nan": "^1.0.0"
|
||||
}
|
||||
@@ -4293,17 +4300,20 @@
|
||||
"minimatch": {
|
||||
"version": "3.0.4",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
},
|
||||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"minipass": {
|
||||
"version": "2.2.4",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"safe-buffer": "^5.1.1",
|
||||
"yallist": "^3.0.0"
|
||||
@@ -4320,6 +4330,7 @@
|
||||
"mkdirp": {
|
||||
"version": "0.5.1",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
}
|
||||
@@ -4392,7 +4403,8 @@
|
||||
},
|
||||
"number-is-nan": {
|
||||
"version": "1.0.1",
|
||||
"bundled": true
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
@@ -4402,6 +4414,7 @@
|
||||
"once": {
|
||||
"version": "1.4.0",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
@@ -4507,6 +4520,7 @@
|
||||
"string-width": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"code-point-at": "^1.0.0",
|
||||
"is-fullwidth-code-point": "^1.0.0",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { API_ROOT, getToken } from './util';
|
||||
import { fetchLists } from './lists';
|
||||
import { fetchLists, INVALIDATE_LISTS } from './lists';
|
||||
|
||||
export const ADD_TODO = 'ADD_TODO';
|
||||
export const REMOVE_TODO = 'REMOVE_TODO';
|
||||
@@ -70,66 +70,78 @@ export function addTodo(text) {
|
||||
|
||||
export function removeTodo(id) {
|
||||
return async dispatch => {
|
||||
dispatch(invalidateTodos());
|
||||
const response = await fetch(`${API_ROOT}/todos/${id}`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
'content-type': 'application/json',
|
||||
dispatch({
|
||||
type: REMOVE_TODO,
|
||||
id,
|
||||
meta: {
|
||||
offline: {
|
||||
effect: {
|
||||
url: `${API_ROOT}/todos/${id}`,
|
||||
headers: {
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
'content-type': 'application/json',
|
||||
},
|
||||
method: 'DELETE',
|
||||
},
|
||||
rollback: {
|
||||
type: INVALIDATE_LISTS,
|
||||
},
|
||||
},
|
||||
},
|
||||
method: 'DELETE',
|
||||
});
|
||||
const json = await response.json();
|
||||
if (json.success) {
|
||||
dispatch({ type: REMOVE_TODO, id });
|
||||
} else {
|
||||
dispatch(fetchLists());
|
||||
}
|
||||
dispatch(validateTodos());
|
||||
};
|
||||
}
|
||||
|
||||
export function toggleTodo(id) {
|
||||
return async (dispatch, getState) => {
|
||||
dispatch(invalidateTodos());
|
||||
const state = getState();
|
||||
const todoObj = state.todos.todos[id];
|
||||
const completed = !todoObj.completed;
|
||||
const response = await fetch(`${API_ROOT}/todos/${id}`, {
|
||||
body: JSON.stringify({ completed }),
|
||||
headers: {
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
'content-type': 'application/json',
|
||||
dispatch({
|
||||
type: TOGGLE_TODO,
|
||||
id,
|
||||
meta: {
|
||||
offline: {
|
||||
effect: {
|
||||
url: `${API_ROOT}/todos/${id}`,
|
||||
body: JSON.stringify({ completed }),
|
||||
headers: {
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
'content-type': 'appl ication/json',
|
||||
},
|
||||
method: 'PATCH',
|
||||
},
|
||||
rollback: {
|
||||
type: INVALIDATE_LISTS,
|
||||
},
|
||||
},
|
||||
},
|
||||
method: 'PATCH',
|
||||
});
|
||||
const json = await response.json();
|
||||
if (json.success) {
|
||||
dispatch({ type: TOGGLE_TODO, id });
|
||||
} else {
|
||||
dispatch(fetchLists());
|
||||
}
|
||||
dispatch(validateTodos());
|
||||
};
|
||||
}
|
||||
|
||||
export function editTodo(id, text) {
|
||||
return async dispatch => {
|
||||
dispatch(invalidateTodos());
|
||||
const response = await fetch(`${API_ROOT}/todos/${id}`, {
|
||||
body: JSON.stringify({ text }),
|
||||
headers: {
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
'content-type': 'application/json',
|
||||
dispatch({
|
||||
type: EDIT_TODO,
|
||||
id,
|
||||
text,
|
||||
meta: {
|
||||
offline: {
|
||||
effect: {
|
||||
url: `${API_ROOT}/todos/${id}`,
|
||||
body: JSON.stringify({ text }),
|
||||
headers: {
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
'content-type': 'application/json',
|
||||
},
|
||||
method: 'PATCH',
|
||||
},
|
||||
rollback: {
|
||||
type: INVALIDATE_LISTS,
|
||||
},
|
||||
},
|
||||
},
|
||||
method: 'PATCH',
|
||||
});
|
||||
const json = await response.json();
|
||||
if (json.success) {
|
||||
const todo = json.data;
|
||||
dispatch({ type: EDIT_TODO, id, todo });
|
||||
} else {
|
||||
dispatch(fetchLists());
|
||||
}
|
||||
dispatch(validateTodos());
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,15 +1,34 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import LogoutLink from '../containers/LogoutLink';
|
||||
import FetchButton from '../containers/FetchButton';
|
||||
import Status from '../containers/Status';
|
||||
|
||||
export default function UserHeader() {
|
||||
return (
|
||||
<div id="user-header">
|
||||
<FetchButton>sync</FetchButton>
|
||||
<Status />
|
||||
<LogoutLink>logout</LogoutLink>
|
||||
</div>
|
||||
);
|
||||
export default class UserHeader extends React.Component {
|
||||
componentDidUpdate() {
|
||||
if (
|
||||
(this.props.dirtyLists || this.props.dirtyTodos) &&
|
||||
!this.props.fetchingLists
|
||||
) {
|
||||
this.props.fetchLists();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div id="user-header">
|
||||
<FetchButton>sync</FetchButton>
|
||||
<Status />
|
||||
<LogoutLink>logout</LogoutLink>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
UserHeader.propTypes = {
|
||||
dirtyLists: PropTypes.bool.isRequired,
|
||||
dirtyTodos: PropTypes.bool.isRequired,
|
||||
fetchingLists: PropTypes.bool.isRequired,
|
||||
fetchLists: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
@@ -13,8 +13,8 @@ function Status({ userFetching, listsFetching }) {
|
||||
marginLeft: '1rem',
|
||||
}}
|
||||
>
|
||||
{userFetching ? 'user' : null}
|
||||
{listsFetching ? 'lists' : null}
|
||||
{userFetching ? 'loading user' : null}
|
||||
{listsFetching ? 'loading lists' : null}
|
||||
</ButtonBase>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,23 @@
|
||||
import { connect } from 'react-redux';
|
||||
import UserHeader from '../components/UserHeader';
|
||||
import { fetchLists } from '../actions/lists';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
user: state.user,
|
||||
dirtyLists: state.lists.dirty,
|
||||
dirtyTodos: state.todos.dirty,
|
||||
fetchingLists: state.lists.fetching,
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(UserHeader);
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
fetchLists: () => dispatch(fetchLists()),
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps,
|
||||
)(UserHeader);
|
||||
|
||||
@@ -53,7 +53,7 @@ export default function todos(
|
||||
...state,
|
||||
todos: {
|
||||
...state.todos,
|
||||
[action.id]: action.todo,
|
||||
[action.id]: { ...state.todos[action.id], text: action.text },
|
||||
},
|
||||
};
|
||||
case REQUEST_TODOS:
|
||||
|
||||
Reference in New Issue
Block a user