From 4a0d62d419e19c766fec08c4a2f4cd8d0b8cee36 Mon Sep 17 00:00:00 2001 From: Tomasz Kasprowicz Date: Fri, 25 Dec 2020 19:13:54 +0100 Subject: [PATCH] added improvements, validation --- src/App.tsx | 26 +++++- src/components/CreateTask.tsx | 51 +++++++---- src/components/TodoList.tsx | 148 +++++++++++++++++++++++++++---- src/store/actions/actionTypes.ts | 4 +- src/store/actions/actions.ts | 48 ++++++++++ src/store/actions/index.ts | 10 ++- src/store/reducers/reducer.ts | 10 +++ 7 files changed, 259 insertions(+), 38 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 52cd8bc..b65e7d1 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useState, useEffect } from "react"; import Header from "./components/Header"; import styled from "styled-components"; import SideDrawer from "./components/SideDrawer"; @@ -6,13 +6,14 @@ import { Switch, Route } from "react-router-dom"; import Login from "./components/Login"; import CreateTask from "./components/CreateTask"; import TodoList from "./components/TodoList"; +import { connect } from "react-redux"; const StyledApp = styled.div` height: 100vh; background-color: #eee; `; -function App() { +const App = (props: any)=> { const [sideDrawer, setSiderDrawer] = useState(false); const toggleSideDrawerHandler = () => { @@ -23,6 +24,10 @@ function App() { setSiderDrawer(false); } + useEffect(()=>{ + props.error !== null && alert(props.error); + }, [props.error]) + return (
@@ -60,4 +65,19 @@ function App() { ); } -export default App; +interface RootState { + isAuth: boolean; + todos: []; + userId: boolean; + idToken: string; + isLoading: boolean; + error:string; +} + +const mapStateToProps = (state: RootState) => { + return { + error: state.error, + }; +}; + +export default connect(mapStateToProps, null)(App); diff --git a/src/components/CreateTask.tsx b/src/components/CreateTask.tsx index 5cb481b..8e74560 100644 --- a/src/components/CreateTask.tsx +++ b/src/components/CreateTask.tsx @@ -4,7 +4,7 @@ import "../../node_modules/bootstrap/dist/css/bootstrap.min.css"; import { connect } from "react-redux"; import * as actions from "../store/actions/actions"; import { withRouter } from "react-router-dom"; -import dayjs from'dayjs'; +import dayjs from "dayjs"; const StyledTasks = styled.div` width: 100%; @@ -33,25 +33,36 @@ const CreateTask = (props: any) => { const [isImportant, setIsImportant] = useState(false); const [date, setDate] = useState(""); - const currDate = dayjs(new Date()).format('YYYY-MM-DD'); + const currDate = dayjs(new Date()).format("YYYY-MM-DD"); const addTaskHandler = () => { const isValid = formValidator(); if (isValid) { - props.isAuth - ? props.addToDo( - taskName, - taskDesc, - taskType, - isImportant, - date, - props.idToken, - props.userId - ) - : props.history.push("/login"); + if (props.isAuth) { + props.addToDo( + taskName, + taskDesc, + taskType, + isImportant, + date, + props.idToken, + props.userId + ); + clearFormHandler(); + } else { + props.history.push("/login"); + } } }; + const clearFormHandler = () => { + setTaskName(""); + setTaskDesc(""); + setTaskType("bussiness"); + setIsImportant(false); + setDate(""); + }; + const radioButtonsHandler = (type: string) => { setTaskType(type); }; @@ -61,8 +72,11 @@ const CreateTask = (props: any) => { }; const formValidator = () => { - if (taskName.length > 1 && taskDesc.length > 1 && date.length > 1) + if (taskName.length > 1 && taskDesc.length > 1 && date.length > 1) { return true; + } else { + alert("Fill in inputs!!!"); + } }; return ( @@ -160,7 +174,7 @@ const CreateTask = (props: any) => { interface RootState { isAuth: boolean; idToken: string; - userId: string + userId: string; } const mapStateToProps = (state: RootState) => { @@ -180,8 +194,11 @@ const mapDispatchToProps = (dispatch: any) => { important: boolean, date: string, token: string, - userId: string, - ) => dispatch(actions.addToDo(name, desc, type, important, date, token, userId)), + userId: string + ) => + dispatch( + actions.addToDo(name, desc, type, important, date, token, userId) + ), }; }; diff --git a/src/components/TodoList.tsx b/src/components/TodoList.tsx index 89e77ba..604bd1f 100644 --- a/src/components/TodoList.tsx +++ b/src/components/TodoList.tsx @@ -3,8 +3,8 @@ import * as actions from "../store/actions/actions"; import "../../node_modules/bootstrap/dist/css/bootstrap.min.css"; import { connect } from "react-redux"; import styled from "styled-components"; -import sadFace from "../assets/images/sadFace.png"; import { withRouter } from "react-router-dom"; +import dayjs from "dayjs"; interface TODOtype { date: string; @@ -14,6 +14,7 @@ interface TODOtype { taskType: string; hash: string; isFinished: boolean; + isCanceled: boolean; } const TodosStyled = styled.div` @@ -21,7 +22,7 @@ const TodosStyled = styled.div` height: 92%; overflow: scroll; justify-content: center; - grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); .description { height: 100px; overflow: scroll; @@ -34,23 +35,20 @@ const TodoList = (props: any) => { }, []); const taskType = props.match.path.substring(1); - console.log(taskType); - const finishTaskHandler = (hash: string, idToken: string) => { - console.log("update"); + const finishTaskHandler = (hash: string, idToken: string) => props.finishToDo(hash, idToken, props.todos); - }; - const deleteTaskHandler = (hash: string, idToken: string) => { - console.log("delete"); + const deleteTaskHandler = (hash: string, idToken: string) => props.deleteToDo(hash, idToken, props.todos); - }; + + const cancelTaskHandler = (hash: string, idToken: string) => + props.cancelToDo(hash, idToken, props.todos); let cards = []; if (props.isLoading === false && props.isAuth === true) { cards = props.todos.map((todo: TODOtype) => { - console.log(todo); - if (todo.isFinished === true && taskType === "finished") { + if (taskType === "finished" && todo.isFinished === true) { return (
{ className="btn btn-danger" onClick={() => deleteTaskHandler(todo.hash, props.idToken)} > - Delete + Delete
); - } else if (taskType === "all" && todo.isFinished === false ) { + } else if (taskType === "all" && todo.isFinished === false) { return (
{ className="btn btn-danger" onClick={() => deleteTaskHandler(todo.hash, props.idToken)} > - Delete + Delete + {!todo.isCanceled && ( + + )}
); @@ -163,8 +170,17 @@ const TodoList = (props: any) => { className="btn btn-danger" onClick={() => deleteTaskHandler(todo.hash, props.idToken)} > - Delete + Delete + {!todo.isCanceled && ( + + )} ); @@ -208,7 +224,105 @@ const TodoList = (props: any) => { className="btn btn-danger" onClick={() => deleteTaskHandler(todo.hash, props.idToken)} > - Delete + Delete + + {!todo.isCanceled && ( + + )} + + + ); + } else if ( + todo.isFinished === false && + (dayjs(new Date()).diff(todo.date) < 0 || + dayjs(new Date()).format("YYYY-MM-DD") === todo.date) && + taskType === "current" + ) { + return ( +
+
End Date: {todo.date}
+
+
Title: {todo.taskName}
+

+ Description: {todo.taskDesc} +

+
+

+ Important:{" "} + {todo.isImportant ? ( + + ) : ( + + )} +

+
+

type: {todo.taskType}

+ + + {!todo.isCanceled && ( + + )} +
+
+ ); + } else if (todo.isCanceled === true && taskType === "Canceled") { + return ( +
+
End Date: {todo.date}
+
+
Title: {todo.taskName}
+

+ Description: {todo.taskDesc} +

+
+

+ Important:{" "} + {todo.isImportant ? ( + + ) : ( + + )} +

+
+

type: {todo.taskType}

+
@@ -252,6 +366,8 @@ const mapDispatchToProps = (dispatch: any) => { dispatch(actions.finishToDo(hash, idToken, todoList)), deleteToDo: (hash: string, idToken: string, todoList: []) => dispatch(actions.deleteToDo(hash, idToken, todoList)), + cancelToDo: (hash: string, idToken: string, todoList: []) => + dispatch(actions.cancelToDo(hash, idToken, todoList)), }; }; diff --git a/src/store/actions/actionTypes.ts b/src/store/actions/actionTypes.ts index 0efc3ba..2bfdef3 100644 --- a/src/store/actions/actionTypes.ts +++ b/src/store/actions/actionTypes.ts @@ -11,4 +11,6 @@ export const LOAD_SUCCESS = 'LOAD_SUCCESS'; export const UPDATE_SUCCESS = 'UPDATE_SUCCESS'; export const UPDATE_FAIL = 'UPDATE_FAIL'; export const DELETE_SUCCESS = 'DELETE_SUCCESS'; -export const DELETE_FAIL = 'DELETE_FAIL'; \ No newline at end of file +export const DELETE_FAIL = 'DELETE_FAIL'; +export const CANCEL_SUCCESS = 'CANCEL_SUCCESS'; +export const CANCEL_FAIL = 'CANCEL_FAIL'; \ No newline at end of file diff --git a/src/store/actions/actions.ts b/src/store/actions/actions.ts index 06fb895..8192560 100644 --- a/src/store/actions/actions.ts +++ b/src/store/actions/actions.ts @@ -14,6 +14,7 @@ type ToDos = { type: string; userId: string; hash: string; + isCanceled: boolean; }; export const loadToDos = (userId: string, token: string) => { @@ -36,6 +37,7 @@ export const loadToDos = (userId: string, token: string) => { date: data[key].date, userId: data[key].userId, isFinished: data[key].isFinished, + isCanceled: data[key].isCanceled, }); } dispatch({ @@ -118,6 +120,7 @@ export const addToDo = ( date: date, userId: userId, isFinished: false, + isCanceled: false }; let url = `https://to-do-studia.firebaseio.com/todos.json?auth=${token}`; @@ -221,3 +224,48 @@ export const deleteToDo = ( }) }; }; + +export const cancelToDo = ( + hash: string, + token: string, + todoList: Array +) => { + return (dispatch: any) => { + const data = { + isCanceled: true, + }; + + const newArr = todoList.filter(todo => { + if(hash === todo.hash){ + todo.isCanceled = true; + } + return todo; + }); + + let url = `https://to-do-studia.firebaseio.com/todos/${hash}.json?auth=${token}`; + + fetch(url, { + method: "PATCH", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(data), + }) + .then((res) => res.json()) + .then((data) => { + if (data.error) { + throw new Error(data.error.message); + } + dispatch({ + type: actionType.CANCEL_SUCCESS, + todos: newArr + }); + }) + .catch((err) => { + dispatch({ + type: actionType.CANCEL_FAIL, + error: err, + }); + }); + }; +}; diff --git a/src/store/actions/index.ts b/src/store/actions/index.ts index 55bc736..50304f5 100644 --- a/src/store/actions/index.ts +++ b/src/store/actions/index.ts @@ -1 +1,9 @@ -export {loadToDos, addToDo, auth, authLogout, finishToDo, deleteToDo} from './actions'; \ No newline at end of file +export { + loadToDos, + addToDo, + auth, + authLogout, + finishToDo, + deleteToDo, + cancelToDo, +} from "./actions"; diff --git a/src/store/reducers/reducer.ts b/src/store/reducers/reducer.ts index 0128e5e..7d44ace 100644 --- a/src/store/reducers/reducer.ts +++ b/src/store/reducers/reducer.ts @@ -88,6 +88,16 @@ const reducer = (state = initialState, action: ActionType) => { ...state, error: action.error, }; + case actionType.CANCEL_SUCCESS: + return { + ...state, + todos: action.todos, + }; + case actionType.CANCEL_FAIL: + return { + ...state, + error: action.error, + }; default: return state; }