mirror of
https://github.com/usatiuk/ustk-todolist.git
synced 2025-10-28 23:57:49 +01:00
add/edit list better design
This commit is contained in:
@@ -8,6 +8,8 @@ export const REQUEST_LISTS = 'REQUEST_LISTS';
|
||||
export const INVALIDATE_LISTS = 'INVALIDATE_LISTS';
|
||||
export const VALIDATE_LISTS = 'VALIDATE_LISTS';
|
||||
export const CHANGE_LIST = 'CHANGE_LIST';
|
||||
export const START_CREATE_LIST = 'START_CREATE_LIST';
|
||||
export const START_EDIT_LIST = 'START_EDIT_LIST';
|
||||
|
||||
function requestLists() {
|
||||
return { type: REQUEST_LISTS };
|
||||
@@ -26,6 +28,12 @@ export function changeList(list) {
|
||||
return { type: CHANGE_LIST, list };
|
||||
}
|
||||
|
||||
export function startCreateList() {
|
||||
return { type: START_CREATE_LIST };
|
||||
}
|
||||
export function startEditList() {
|
||||
return { type: START_EDIT_LIST };
|
||||
}
|
||||
function addListToState(list) {
|
||||
return { type: ADD_LIST, list };
|
||||
}
|
||||
@@ -53,10 +61,12 @@ function removeListFromState(id) {
|
||||
return { type: REMOVE_LIST, id };
|
||||
}
|
||||
|
||||
export function removeList(id) {
|
||||
export function removeList() {
|
||||
return async (dispatch, getState) => {
|
||||
let state = getState();
|
||||
const { list } = state.lists;
|
||||
dispatch(invalidateLists());
|
||||
const response = await fetch(`${API_ROOT}/lists/${id}`, {
|
||||
const response = await fetch(`${API_ROOT}/lists/${list}`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
'content-type': 'application/json',
|
||||
@@ -65,12 +75,12 @@ export function removeList(id) {
|
||||
});
|
||||
const json = await response.json();
|
||||
if (json.success) {
|
||||
dispatch(removeListFromState(id));
|
||||
const state = getState();
|
||||
const list = state.lists.lists[Object.keys(state.lists.lists)[0]]
|
||||
dispatch(removeListFromState(list));
|
||||
state = getState();
|
||||
const newList = state.lists.lists[Object.keys(state.lists.lists)[0]]
|
||||
? state.lists.lists[Object.keys(state.lists.lists)[0]].id
|
||||
: '';
|
||||
dispatch(changeList(list));
|
||||
dispatch(changeList(newList));
|
||||
}
|
||||
dispatch(validateLists());
|
||||
};
|
||||
@@ -80,10 +90,12 @@ function editListNameInState(id, name) {
|
||||
return { type: EDIT_LIST_NAME, id, name };
|
||||
}
|
||||
|
||||
export function editList(id, name) {
|
||||
return async (dispatch) => {
|
||||
export function editList(name) {
|
||||
return async (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const { list } = state.lists;
|
||||
dispatch(invalidateLists());
|
||||
const response = await fetch(`${API_ROOT}/lists/${id}`, {
|
||||
const response = await fetch(`${API_ROOT}/lists/${list}`, {
|
||||
body: JSON.stringify({ name }),
|
||||
headers: {
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
@@ -93,7 +105,7 @@ export function editList(id, name) {
|
||||
});
|
||||
const json = await response.json();
|
||||
if (json.success) {
|
||||
dispatch(editListNameInState(id, name));
|
||||
dispatch(editListNameInState(list, name));
|
||||
}
|
||||
dispatch(validateLists());
|
||||
};
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#lists {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-grow: 0;
|
||||
max-width: 50%;
|
||||
}
|
||||
|
||||
#listactions {
|
||||
@@ -32,21 +34,7 @@
|
||||
#filters {
|
||||
margin-right: 0.75rem;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
#listselector {
|
||||
margin-left: 0.2rem;
|
||||
align-self: center;
|
||||
background-color: #fbfbfb;
|
||||
}
|
||||
|
||||
#listselector select {
|
||||
color: black;
|
||||
font-size: 1.5rem;
|
||||
font-weight: 400;
|
||||
outline: none;
|
||||
border: none;
|
||||
background-color: #fbfbfb;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
#inputs {
|
||||
|
||||
@@ -4,21 +4,24 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export default function ListActions({
|
||||
addList, removeList, editList, list,
|
||||
startCreateList,
|
||||
removeList,
|
||||
startEditList,
|
||||
list,
|
||||
}) {
|
||||
const editRemoveButtons = list
|
||||
? [
|
||||
<button onClick={() => removeList(list)}>
|
||||
<button onClick={() => removeList()}>
|
||||
<FontAwesomeIcon icon={faTrash} />
|
||||
</button>,
|
||||
<button onClick={() => editList(list, prompt('List name?'))}>
|
||||
<button onClick={() => startEditList()}>
|
||||
<FontAwesomeIcon icon={faEdit} />
|
||||
</button>,
|
||||
]
|
||||
: null;
|
||||
return (
|
||||
<div id="listactions">
|
||||
<button onClick={() => addList(prompt('List name?'))}>
|
||||
<button onClick={() => startCreateList()}>
|
||||
<FontAwesomeIcon icon={faPlus} />
|
||||
</button>
|
||||
{editRemoveButtons}
|
||||
@@ -31,8 +34,8 @@ ListActions.defaultProps = {
|
||||
};
|
||||
|
||||
ListActions.propTypes = {
|
||||
addList: PropTypes.func.isRequired,
|
||||
startCreateList: PropTypes.func.isRequired,
|
||||
removeList: PropTypes.func.isRequired,
|
||||
editList: PropTypes.func.isRequired,
|
||||
startEditList: PropTypes.func.isRequired,
|
||||
list: PropTypes.string,
|
||||
};
|
||||
|
||||
@@ -4,11 +4,33 @@ import Selector from './Selector';
|
||||
import ListActions from './ListActions';
|
||||
|
||||
export default function Lists({
|
||||
list, lists, onChange, addList, removeList, editList,
|
||||
list,
|
||||
lists,
|
||||
onChange,
|
||||
addList,
|
||||
creating,
|
||||
editing,
|
||||
removeList,
|
||||
startCreateList,
|
||||
startEditList,
|
||||
editList,
|
||||
listObjs,
|
||||
}) {
|
||||
const selectorProps = { list, lists, onChange };
|
||||
const selectorProps = {
|
||||
list,
|
||||
lists,
|
||||
creating,
|
||||
editing,
|
||||
onChange,
|
||||
editList,
|
||||
addList,
|
||||
listObjs,
|
||||
};
|
||||
const actionsProps = {
|
||||
addList, removeList, editList, list,
|
||||
startCreateList,
|
||||
removeList,
|
||||
startEditList,
|
||||
list,
|
||||
};
|
||||
return (
|
||||
<div id="lists">
|
||||
@@ -31,4 +53,9 @@ Lists.propTypes = {
|
||||
addList: PropTypes.func.isRequired,
|
||||
removeList: PropTypes.func.isRequired,
|
||||
editList: PropTypes.func.isRequired,
|
||||
startCreateList: PropTypes.func.isRequired,
|
||||
startEditList: PropTypes.func.isRequired,
|
||||
creating: PropTypes.bool.isRequired,
|
||||
editing: PropTypes.bool.isRequired,
|
||||
listObjs: PropTypes.any.isRequired,
|
||||
};
|
||||
|
||||
50
src/components/Selector.css
Normal file
50
src/components/Selector.css
Normal file
@@ -0,0 +1,50 @@
|
||||
#listselector {
|
||||
display: flex;
|
||||
margin-left: 0.2rem;
|
||||
overflow: hidden;
|
||||
align-self: center;
|
||||
background-color: #fbfbfb;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
#listselector input {
|
||||
padding: 0;
|
||||
color: black;
|
||||
font-size: 1.5rem;
|
||||
font-weight: 400;
|
||||
outline: none;
|
||||
border: none;
|
||||
background-color: #fbfbfb;
|
||||
border-bottom: 1px solid #888888;
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
#listselector button {
|
||||
width: 20%;
|
||||
font-size: 0.9rem;
|
||||
color: #1b881b;
|
||||
background: none;
|
||||
border: none;
|
||||
margin: 0.1rem 0.3rem;
|
||||
padding: 0.3rem 0.7em;
|
||||
}
|
||||
|
||||
#listselector select {
|
||||
max-width: 100%;
|
||||
color: black;
|
||||
font-size: 1.5rem;
|
||||
font-weight: 400;
|
||||
outline: none;
|
||||
border: none;
|
||||
background-color: #fbfbfb;
|
||||
}
|
||||
|
||||
#listselector select option {
|
||||
max-width: 100%;
|
||||
color: black;
|
||||
font-size: 1.5rem;
|
||||
font-weight: 400;
|
||||
outline: none;
|
||||
border: none;
|
||||
background-color: #fbfbfb;
|
||||
}
|
||||
@@ -1,16 +1,64 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { faPlus, faCheck } from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
export default function Selector(props) {
|
||||
const lists = props.lists.map(list => (
|
||||
<option key={list.id} value={list.id}>
|
||||
{list.name}
|
||||
import './Selector.css';
|
||||
|
||||
export default function Selector({
|
||||
lists,
|
||||
list,
|
||||
onChange,
|
||||
editing,
|
||||
creating,
|
||||
addList,
|
||||
editList,
|
||||
listObjs,
|
||||
}) {
|
||||
const listElements = lists.map(elem => (
|
||||
<option key={elem.id} value={elem.id}>
|
||||
{elem.name}
|
||||
</option>
|
||||
));
|
||||
if (creating) {
|
||||
let input = null;
|
||||
return (
|
||||
<div id="listselector">
|
||||
<input
|
||||
ref={(node) => {
|
||||
input = node;
|
||||
}}
|
||||
id="input"
|
||||
type="text"
|
||||
/>
|
||||
<button onClick={() => addList(input.value)}>
|
||||
<FontAwesomeIcon icon={faPlus} />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (editing) {
|
||||
let input = null;
|
||||
return (
|
||||
<div id="listselector">
|
||||
<input
|
||||
ref={(node) => {
|
||||
input = node;
|
||||
}}
|
||||
defaultValue={listObjs.lists[list].name}
|
||||
id="input"
|
||||
type="text"
|
||||
/>
|
||||
<button onClick={() => editList(input.value)}>
|
||||
<FontAwesomeIcon icon={faCheck} />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div id="listselector">
|
||||
<select value={props.list} onChange={e => props.onChange(e.target.value)}>
|
||||
{lists}
|
||||
<select value={list} onChange={e => onChange(e.target.value)}>
|
||||
{listElements}
|
||||
</select>
|
||||
</div>
|
||||
);
|
||||
@@ -25,5 +73,10 @@ Selector.propTypes = {
|
||||
id: PropTypes.string.isRequired,
|
||||
})).isRequired,
|
||||
list: PropTypes.string,
|
||||
editing: PropTypes.bool.isRequired,
|
||||
creating: PropTypes.bool.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
editList: PropTypes.func.isRequired,
|
||||
addList: PropTypes.func.isRequired,
|
||||
listObjs: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
@@ -1,11 +1,24 @@
|
||||
import { connect } from 'react-redux';
|
||||
import Lists from '../components/Lists';
|
||||
import { changeList, removeList, addList, editList } from '../actions/lists';
|
||||
import {
|
||||
changeList,
|
||||
removeList,
|
||||
addList,
|
||||
editList,
|
||||
startCreateList,
|
||||
startEditList,
|
||||
} from '../actions/lists';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
const editing = state.lists.lists[state.lists.list]
|
||||
? state.lists.lists[state.lists.list].editing
|
||||
: false;
|
||||
return {
|
||||
lists: Object.values(state.lists.lists),
|
||||
listObjs: state.lists,
|
||||
list: state.lists.list,
|
||||
editing,
|
||||
creating: state.lists.creating,
|
||||
dirty: state.lists.dirty,
|
||||
};
|
||||
}
|
||||
@@ -16,6 +29,8 @@ function mapDispatchToProps(dispatch) {
|
||||
addList: name => dispatch(addList(name)),
|
||||
removeList: id => dispatch(removeList(id)),
|
||||
editList: (id, name) => dispatch(editList(id, name)),
|
||||
startCreateList: () => dispatch(startCreateList()),
|
||||
startEditList: () => dispatch(startEditList()),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,12 @@ import {
|
||||
} from '../actions/todos';
|
||||
|
||||
export default function todos(
|
||||
state = { dirty: true, fetching: false, todos: [] },
|
||||
state = {
|
||||
dirty: true,
|
||||
fetching: false,
|
||||
todos: [],
|
||||
editing: false,
|
||||
},
|
||||
action,
|
||||
) {
|
||||
switch (action.type) {
|
||||
|
||||
@@ -7,6 +7,8 @@ import {
|
||||
ADD_LIST,
|
||||
REMOVE_LIST,
|
||||
EDIT_LIST_NAME,
|
||||
START_CREATE_LIST,
|
||||
START_EDIT_LIST,
|
||||
} from '../actions/lists';
|
||||
import {
|
||||
ADD_TODO,
|
||||
@@ -25,6 +27,7 @@ export default function lists(
|
||||
dirty: true,
|
||||
fetching: false,
|
||||
lists: {},
|
||||
creating: false,
|
||||
list: '',
|
||||
},
|
||||
action,
|
||||
@@ -39,9 +42,15 @@ export default function lists(
|
||||
fetching: false,
|
||||
lists: action.lists,
|
||||
};
|
||||
case START_CREATE_LIST:
|
||||
return {
|
||||
...state,
|
||||
creating: true,
|
||||
};
|
||||
case ADD_LIST:
|
||||
return {
|
||||
...state,
|
||||
creating: false,
|
||||
lists: { ...state.lists, [action.list.id]: action.list },
|
||||
};
|
||||
case REMOVE_LIST: {
|
||||
@@ -52,10 +61,29 @@ export default function lists(
|
||||
lists: newLists,
|
||||
};
|
||||
}
|
||||
case START_EDIT_LIST: {
|
||||
return {
|
||||
...state,
|
||||
lists: {
|
||||
...state.lists,
|
||||
[state.list]: {
|
||||
...state.lists[state.list],
|
||||
editing: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
case EDIT_LIST_NAME: {
|
||||
return {
|
||||
...state,
|
||||
lists: { ...state.lists, [action.id]: { ...state.lists[action.id], name: action.name } },
|
||||
lists: {
|
||||
...state.lists,
|
||||
[action.id]: {
|
||||
...state.lists[action.id],
|
||||
name: action.name,
|
||||
editing: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
case INVALIDATE_LISTS:
|
||||
|
||||
Reference in New Issue
Block a user