diff --git a/.eslintcache b/.eslintcache new file mode 100644 index 0000000..7d34386 --- /dev/null +++ b/.eslintcache @@ -0,0 +1 @@ +[{"/Users/tomasz.kasprowicz/Documents/UAM/todo-list/src/index.tsx":"1","/Users/tomasz.kasprowicz/Documents/UAM/todo-list/src/components/Button.tsx":"2","/Users/tomasz.kasprowicz/Documents/UAM/todo-list/src/components/CreateTask.tsx":"3","/Users/tomasz.kasprowicz/Documents/UAM/todo-list/src/components/Header.tsx":"4","/Users/tomasz.kasprowicz/Documents/UAM/todo-list/src/store/actions/actionTypes.ts":"5","/Users/tomasz.kasprowicz/Documents/UAM/todo-list/src/store/reducers/reducer.ts":"6","/Users/tomasz.kasprowicz/Documents/UAM/todo-list/src/components/Login.tsx":"7","/Users/tomasz.kasprowicz/Documents/UAM/todo-list/src/components/SideDrawer.tsx":"8","/Users/tomasz.kasprowicz/Documents/UAM/todo-list/src/store/actions/actions.ts":"9","/Users/tomasz.kasprowicz/Documents/UAM/todo-list/src/App.tsx":"10","/Users/tomasz.kasprowicz/Documents/UAM/todo-list/src/components/TodoList.tsx":"11"},{"size":1082,"mtime":1607870572555,"results":"12","hashOfConfig":"13"},{"size":694,"mtime":1608811793339,"results":"14","hashOfConfig":"13"},{"size":4881,"mtime":1608819417483,"results":"15","hashOfConfig":"13"},{"size":2016,"mtime":1608815616436,"results":"16","hashOfConfig":"13"},{"size":401,"mtime":1608819875103,"results":"17","hashOfConfig":"13"},{"size":1441,"mtime":1608826539038,"results":"18","hashOfConfig":"13"},{"size":3050,"mtime":1608816450132,"results":"19","hashOfConfig":"13"},{"size":2622,"mtime":1608820837478,"results":"20","hashOfConfig":"13"},{"size":3136,"mtime":1608826712990,"results":"21","hashOfConfig":"13"},{"size":1509,"mtime":1608821206467,"results":"22","hashOfConfig":"13"},{"size":1936,"mtime":1608827652874,"results":"23","hashOfConfig":"13"},{"filePath":"24","messages":"25","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"26","usedDeprecatedRules":"27"},"mxnhpw",{"filePath":"28","messages":"29","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"30","messages":"31","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"32"},{"filePath":"33","messages":"34","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"35","messages":"36","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"37","messages":"38","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"39","messages":"40","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"41","messages":"42","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"43","messages":"44","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"45","messages":"46","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"47","messages":"48","errorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},"/Users/tomasz.kasprowicz/Documents/UAM/todo-list/src/index.tsx",["49"],"import React from \"react\";\nimport ReactDOM from \"react-dom\";\nimport \"./index.css\";\nimport App from \"./App\";\nimport reportWebVitals from \"./reportWebVitals\";\nimport { BrowserRouter } from \"react-router-dom\";\nimport { Provider } from \"react-redux\";\nimport { createStore, applyMiddleware, compose } from \"redux\";\nimport reducer from \"./store/reducers/reducer\";\nimport { composeWithDevTools } from \"redux-devtools-extension\";\nimport thunk from \"redux-thunk\";\n\nconst store = createStore(\n reducer,\n compose(\n applyMiddleware(thunk),\n (window as any).__REDUX_DEVTOOLS_EXTENSION__ &&\n (window as any).__REDUX_DEVTOOLS_EXTENSION__()\n )\n);\n\nReactDOM.render(\n \n \n \n \n \n \n ,\n document.getElementById(\"root\")\n);\n\n// If you want to start measuring performance in your app, pass a function\n// to log results (for example: reportWebVitals(console.log))\n// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals\nreportWebVitals();\n",["50","51"],"/Users/tomasz.kasprowicz/Documents/UAM/todo-list/src/components/Button.tsx",[],"/Users/tomasz.kasprowicz/Documents/UAM/todo-list/src/components/CreateTask.tsx",["52"],"import React, { ReactEventHandler, useState } from \"react\";\r\nimport styled from \"styled-components\";\r\nimport \"../../node_modules/bootstrap/dist/css/bootstrap.min.css\";\r\nimport { connect } from \"react-redux\";\r\nimport * as actions from \"../store/actions/actions\";\r\nimport { withRouter } from \"react-router-dom\";\r\n\r\nconst StyledTasks = styled.div`\r\n width: 100%;\r\n height: 92%;\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n form {\r\n width: 100%;\r\n max-width: 40rem;\r\n padding: 2rem;\r\n a {\r\n color: blue !important;\r\n cursor: pointer;\r\n }\r\n textarea {\r\n resize: none;\r\n }\r\n }\r\n`;\r\n\r\nconst CreateTask = (props: any) => {\r\n const [taskName, setTaskName] = useState(\"\");\r\n const [taskDesc, setTaskDesc] = useState(\"\");\r\n const [taskType, setTaskType] = useState(\"bussiness\");\r\n const [isImportant, setIsImportant] = useState(false);\r\n const [date, setDate] = useState(\"\");\r\n\r\n const addTaskHandler = () => {\r\n const isValid = formValidator();\r\n if (isValid) {\r\n props.isAuth\r\n ? props.addToDo(\r\n taskName,\r\n taskDesc,\r\n taskType,\r\n isImportant,\r\n date,\r\n props.idToken,\r\n props.userId\r\n )\r\n : props.history.push(\"/login\");\r\n }\r\n };\r\n\r\n const radioButtonsHandler = (type: string) => {\r\n setTaskType(type);\r\n };\r\n\r\n const importantButtonsHandler = (e: any) => {\r\n if (e.target.value === \"true\") setIsImportant(true);\r\n };\r\n\r\n const formValidator = () => {\r\n if (taskName.length > 1 && taskDesc.length > 1 && date.length > 1)\r\n return true;\r\n };\r\n\r\n return (\r\n \r\n \r\n Create Task\r\n\r\n \r\n Task Name\r\n setTaskName(e.target.value)}\r\n />\r\n \r\n\r\n \r\n Task Description\r\n setTaskDesc(e.target.value)}\r\n >\r\n \r\n\r\n \r\n radioButtonsHandler(\"bussiness\")}\r\n />\r\n \r\n Bussiness\r\n \r\n \r\n \r\n radioButtonsHandler(\"personal\")}\r\n />\r\n \r\n Personal\r\n \r\n \r\n \r\n importantButtonsHandler(e)}\r\n />\r\n \r\n Important\r\n \r\n \r\n \r\n \r\n End Date\r\n setDate(e.target.value)}\r\n />\r\n \r\n\r\n \r\n Create Task\r\n \r\n \r\n \r\n );\r\n};\r\n\r\ninterface RootState {\r\n isAuth: boolean;\r\n idToken: string;\r\n userId: string\r\n}\r\n\r\nconst mapStateToProps = (state: RootState) => {\r\n return {\r\n isAuth: state.isAuth,\r\n idToken: state.idToken,\r\n userId: state.userId,\r\n };\r\n};\r\n\r\nconst mapDispatchToProps = (dispatch: any) => {\r\n return {\r\n addToDo: (\r\n name: string,\r\n desc: string,\r\n type: string,\r\n important: boolean,\r\n date: string,\r\n token: string,\r\n userId: string,\r\n ) => dispatch(actions.addToDo(name, desc, type, important, date, token, userId)),\r\n };\r\n};\r\n\r\nexport default connect(\r\n mapStateToProps,\r\n mapDispatchToProps\r\n)(withRouter(CreateTask));\r\n","/Users/tomasz.kasprowicz/Documents/UAM/todo-list/src/components/Header.tsx",[],"/Users/tomasz.kasprowicz/Documents/UAM/todo-list/src/store/actions/actionTypes.ts",[],"/Users/tomasz.kasprowicz/Documents/UAM/todo-list/src/store/reducers/reducer.ts",["53"],"/Users/tomasz.kasprowicz/Documents/UAM/todo-list/src/components/Login.tsx",["54"],"/Users/tomasz.kasprowicz/Documents/UAM/todo-list/src/components/SideDrawer.tsx",[],"/Users/tomasz.kasprowicz/Documents/UAM/todo-list/src/store/actions/actions.ts",["55"],"/Users/tomasz.kasprowicz/Documents/UAM/todo-list/src/App.tsx",[],"/Users/tomasz.kasprowicz/Documents/UAM/todo-list/src/components/TodoList.tsx",["56","57"],{"ruleId":"58","severity":1,"message":"59","line":10,"column":10,"nodeType":"60","messageId":"61","endLine":10,"endColumn":29},{"ruleId":"62","replacedBy":"63"},{"ruleId":"64","replacedBy":"65"},{"ruleId":"58","severity":1,"message":"66","line":1,"column":17,"nodeType":"60","messageId":"61","endLine":1,"endColumn":34},{"ruleId":"58","severity":1,"message":"67","line":2,"column":8,"nodeType":"60","messageId":"61","endLine":2,"endColumn":15},{"ruleId":"58","severity":1,"message":"68","line":1,"column":27,"nodeType":"60","messageId":"61","endLine":1,"endColumn":36},{"ruleId":"58","severity":1,"message":"69","line":3,"column":6,"nodeType":"60","messageId":"61","endLine":3,"endColumn":16},{"ruleId":"58","severity":1,"message":"70","line":1,"column":28,"nodeType":"60","messageId":"61","endLine":1,"endColumn":36},{"ruleId":"71","severity":1,"message":"72","line":26,"column":6,"nodeType":"73","endLine":26,"endColumn":8,"suggestions":"74"},"@typescript-eslint/no-unused-vars","'composeWithDevTools' is defined but never used.","Identifier","unusedVar","no-native-reassign",["75"],"no-negated-in-lhs",["76"],"'ReactEventHandler' is defined but never used.","'produce' is defined but never used.","'useEffect' is defined but never used.","'ILoadToDos' is defined but never used.","'useState' is defined but never used.","react-hooks/exhaustive-deps","React Hook useEffect has a missing dependency: 'props'. Either include it or remove the dependency array. However, 'props' will change when *any* prop changes, so the preferred fix is to destructure the 'props' object outside of the useEffect call and refer to those specific props inside useEffect.","ArrayExpression",["77"],"no-global-assign","no-unsafe-negation",{"desc":"78","fix":"79"},"Update the dependencies array to be: [props]",{"range":"80","text":"81"},[628,630],"[props]"] \ No newline at end of file diff --git a/src/App.tsx b/src/App.tsx index 956c17c..eca7063 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -5,6 +5,7 @@ import SideDrawer from "./components/SideDrawer"; import { Switch, Route } from "react-router-dom"; import Login from "./components/Login"; import CreateTask from "./components/CreateTask"; +import TodoList from "./components/TodoList"; const StyledApp = styled.div` height: 100vh; @@ -29,6 +30,27 @@ function App() { + + + + + + + + + + + + + + + + + + + + + ); diff --git a/src/components/Button.tsx b/src/components/Button.tsx index af07b79..e03f81c 100644 --- a/src/components/Button.tsx +++ b/src/components/Button.tsx @@ -17,6 +17,12 @@ const StyledButton = styled.button` &:hover { background-color: rgba(18, 18, 18, 0.6); } + &:focus, &:active { + border-color: inherit; + -webkit-box-shadow: none; + box-shadow: none; + outline:none; +} `; const Button: React.FC = (props) => { diff --git a/src/components/CreateTask.tsx b/src/components/CreateTask.tsx index 7afeea9..c682fc2 100644 --- a/src/components/CreateTask.tsx +++ b/src/components/CreateTask.tsx @@ -1,6 +1,9 @@ -import React from "react"; +import React, { ReactEventHandler, useState } from "react"; import styled from "styled-components"; 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"; const StyledTasks = styled.div` width: 100%; @@ -16,13 +19,49 @@ const StyledTasks = styled.div` color: blue !important; cursor: pointer; } - textarea{ - resize:none; + textarea { + resize: none; } } `; -const CreateTask = () => { +const CreateTask = (props: any) => { + const [taskName, setTaskName] = useState(""); + const [taskDesc, setTaskDesc] = useState(""); + const [taskType, setTaskType] = useState("bussiness"); + const [isImportant, setIsImportant] = useState(false); + const [date, setDate] = useState(""); + + const addTaskHandler = () => { + const isValid = formValidator(); + if (isValid) { + props.isAuth + ? props.addToDo( + taskName, + taskDesc, + taskType, + isImportant, + date, + props.idToken, + props.userId + ) + : props.history.push("/login"); + } + }; + + const radioButtonsHandler = (type: string) => { + setTaskType(type); + }; + + const importantButtonsHandler = (e: any) => { + if (e.target.value === "true") setIsImportant(true); + }; + + const formValidator = () => { + if (taskName.length > 1 && taskDesc.length > 1 && date.length > 1) + return true; + }; + return ( @@ -30,7 +69,13 @@ const CreateTask = () => { Task Name - + setTaskName(e.target.value)} + /> @@ -39,6 +84,8 @@ const CreateTask = () => { className="form-control" id="exampleFormControlTextarea1" rows={4} + value={taskDesc} + onChange={(e) => setTaskDesc(e.target.value)} > @@ -51,6 +98,7 @@ const CreateTask = () => { value="bussiness" checked readOnly + onClick={() => radioButtonsHandler("bussiness")} /> Bussiness @@ -64,6 +112,7 @@ const CreateTask = () => { id="personal" value="personal" readOnly + onClick={() => radioButtonsHandler("personal")} /> Personal @@ -73,20 +122,30 @@ const CreateTask = () => { importantButtonsHandler(e)} /> Important - + End Date - + setDate(e.target.value)} + /> - + Create Task @@ -94,4 +153,35 @@ const CreateTask = () => { ); }; -export default CreateTask; +interface RootState { + isAuth: boolean; + idToken: string; + userId: string +} + +const mapStateToProps = (state: RootState) => { + return { + isAuth: state.isAuth, + idToken: state.idToken, + userId: state.userId, + }; +}; + +const mapDispatchToProps = (dispatch: any) => { + return { + addToDo: ( + name: string, + desc: string, + type: string, + important: boolean, + date: string, + token: string, + userId: string, + ) => dispatch(actions.addToDo(name, desc, type, important, date, token, userId)), + }; +}; + +export default connect( + mapStateToProps, + mapDispatchToProps +)(withRouter(CreateTask)); diff --git a/src/components/Header.tsx b/src/components/Header.tsx index 21f2aa7..2a3fd77 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -2,6 +2,8 @@ import React from "react"; import styled from "styled-components"; import { NavLink } from "react-router-dom"; import Button from "./Button"; +import * as actions from "../store/actions/actions"; +import { connect } from "react-redux"; const StyledHeader = styled.div` height: 8%; @@ -12,6 +14,7 @@ const StyledHeader = styled.div` display: flex; align-items: center; justify-content: space-between; + outline:none; .menu-icon { width: 1rem; height: 1rem; @@ -32,9 +35,16 @@ const StyledHeader = styled.div` interface Props { sideDrawer: () => void; isOpen: boolean; + isAuth: boolean; + logout: () => void; } -const Header: React.FC = (props) => { +const Header: React.FC = (props: Props) => { + + const logoutHandler = ()=>{ + props.isAuth && props.logout(); + } + return ( @@ -51,10 +61,27 @@ const Header: React.FC = (props) => { - Login + {props.isAuth?'Logout': 'Login'} ); }; -export default Header; +interface RootState { + isAuth: boolean; +} + +const mapStateToProps = (state: RootState) => { + return { + isAuth: state.isAuth, + }; +}; + +const mapDispatchToProps = (dispatch: any) => { + return { + auth: (email: string, password: string, isSignupMode: boolean) => dispatch(actions.auth(email, password, isSignupMode)), + logout: () => dispatch(actions.authLogout()) + }; +}; + +export default connect(mapStateToProps, mapDispatchToProps)(Header); diff --git a/src/components/Login.tsx b/src/components/Login.tsx index e22f5fd..82aae23 100644 --- a/src/components/Login.tsx +++ b/src/components/Login.tsx @@ -1,6 +1,9 @@ -import React, { useState } from "react"; +import React, { useState, useEffect } from "react"; +import { connect } from "react-redux"; import styled from "styled-components"; import "../../node_modules/bootstrap/dist/css/bootstrap.min.css"; +import * as actions from "../store/actions/actions"; +import { Redirect } from "react-router-dom"; const StyledForm = styled.div` width: 100%; @@ -12,26 +15,24 @@ const StyledForm = styled.div` width: 100%; max-width: 40rem; padding: 2rem; - a { + .login-button { color: blue !important; cursor: pointer; + border: none; } } `; -const Login = () => { +const Login = (props: any) => { const [signUp, setSignUp] = useState(false); const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); - const authorizationHandler = (e:React.FormEvent) => { + const authorizationHandler = (e: React.FormEvent) => { e.preventDefault(); - if (signUp) { - console.log('rejestracja', email, password); - - } else { - console.log('log', email, password); - } + signUp + ? props.auth(email, password, true) + : props.auth(email, password, false); }; return ( @@ -73,14 +74,38 @@ const Login = () => { Already registered{" "} {signUp ? ( - setSignUp(false)}>sign in? + setSignUp(false)}> + sign in? + ) : ( - setSignUp(true)}>sign up? + setSignUp(true)}> + sign up? + )} + {props.isAuth && } ); }; -export default Login; +interface RootState { + isAuth: boolean; + redirectTo: string; +} + +const mapStateToProps = (state: RootState) => { + return { + isAuth: state.isAuth, + redirectTo: state.redirectTo, + }; +}; + +const mapDispatchToProps = (dispatch: any) => { + return { + auth: (email: string, password: string, isSignupMode: boolean) => + dispatch(actions.auth(email, password, isSignupMode)), + }; +}; + +export default connect(mapStateToProps, mapDispatchToProps)(Login); diff --git a/src/components/SideDrawer.tsx b/src/components/SideDrawer.tsx index 37b9431..23796d5 100644 --- a/src/components/SideDrawer.tsx +++ b/src/components/SideDrawer.tsx @@ -1,11 +1,12 @@ import React from "react"; import styled from "styled-components"; +import { NavLink } from "react-router-dom"; const StyledSidedrawer = styled.div` position: fixed; top: 0; left: 0; - z-index:8; + z-index: 8; overflow-y: hidden; position: absolute; top: 0; @@ -29,14 +30,21 @@ const StyledSidedrawer = styled.div` display: flex; justify-content: flex-start; align-items: center; - padding-right:1rem; + padding-right: 1rem; i { padding: 0 1rem; font-size: 1rem; } span { padding: 0 1rem; - display:contents; + display: contents; + } + a { + text-decoration: none; + color: #fff; + } + .active { + color: #4153af; } } } @@ -50,28 +58,46 @@ const SideDrawer = () => { - - Finished + + + All + - - On going + + + Finished + - - Bussiness + + + On going + - - Personal + + + Bussiness + - - Important + + + Personal + - - Canceled + + + Important + + + + + + Canceled + diff --git a/src/components/TodoList.tsx b/src/components/TodoList.tsx new file mode 100644 index 0000000..559c55e --- /dev/null +++ b/src/components/TodoList.tsx @@ -0,0 +1,78 @@ +import React, { useEffect, useState } from "react"; +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"; + +interface TODOtype { + date: string; + taskName: string; + taskDesc: string; + isImportant: string; + taskType: string; + hash: string; +} + +const TodosStyled = styled.div` + display: flex; + flex-direction:column; + height:92%; + overflow: scroll; +`; + +const TodoList = (props: any) => { + useEffect(() => { + props.isAuth && props.loadToDos(props.userId, props.idToken); + }, []); + + let cards = []; + if (props.isLoading === false) { + cards = props.todos.map((todo: TODOtype) => { + return ( + + {todo.date} + + {todo.taskName} + {todo.taskDesc} + + {todo.isImportant && "important"} + + {todo.taskType} + + + ); + }); + } + return {cards}; +}; + +interface RootState { + isAuth: boolean; + todos: []; + userId: boolean; + idToken: string; + isLoading: boolean; +} + +const mapStateToProps = (state: RootState) => { + return { + todos: state.todos, + userId: state.userId, + idToken: state.idToken, + isAuth: state.isAuth, + isLoading: state.isLoading, + }; +}; + +const mapDispatchToProps = (dispatch: any) => { + return { + loadToDos: (userId: string, idToken: string) => + dispatch(actions.loadToDos(userId, idToken)), + }; +}; + +export default connect(mapStateToProps, mapDispatchToProps)(TodoList); diff --git a/src/store/actions/actionTypes.ts b/src/store/actions/actionTypes.ts index d4b7d2a..c0f5b63 100644 --- a/src/store/actions/actionTypes.ts +++ b/src/store/actions/actionTypes.ts @@ -1,3 +1,10 @@ export const ADD_TODO = 'ADD_TODO'; export const DELETE_TODO = 'DELETE_TODO'; -export const LOAD_TODOS = 'LOAD_TODOS'; \ No newline at end of file +export const LOAD_TODOS = 'LOAD_TODOS'; +export const AUTH_SUCCESS = 'AUTH_SUCCESS'; +export const AUTH_FAIL = 'AUTH_FAIL'; +export const AUTH_LOGOUT = 'AUTH_LOGOUT'; +export const ADD_SUCCESS = 'ADD_SUCCESS'; +export const ADD_FAIL = 'ADD_FAIL'; +export const LOAD_FAIL = 'LOAD_FAIL'; +export const LOAD_SUCCESS = 'LOAD_SUCCESS'; \ No newline at end of file diff --git a/src/store/actions/actions.ts b/src/store/actions/actions.ts index 7677926..88363ed 100644 --- a/src/store/actions/actions.ts +++ b/src/store/actions/actions.ts @@ -1,5 +1,135 @@ -export const loadToDos = ()=>{ - return dispatch =>{ - +import * as actionType from "../actions/actionTypes"; + +type ILoadToDos = { + type: string; + todos: Array; +}; + +export const loadToDos = (userId: string, token: string) => { + return (dispatch: any) => { + let url = `https://to-do-studia.firebaseio.com/todos.json?auth=${token}&orderBy="userId"&equalTo="${userId}"`; + fetch(url) + .then((res) => res.json()) + .then((data) => { + if (data.error) { + throw new Error(data.error.message); + } + let todos = []; + for (let key in data) { + todos.push({ + hash: key, + taskName: data[key].name, + taskDesc: data[key].desc, + taskType: data[key].type, + isImportant: data[key].important, + date: data[key].date, + userId: data[key].userId, + }); + } + dispatch({ + type: actionType.LOAD_SUCCESS, + todos: todos, + }); + }) + .catch((err) => { + dispatch({ + type: actionType.LOAD_FAIL, + error: err, + }); + }); + }; +}; + +export const auth = ( + email: string, + password: string, + isSignupMode: boolean +) => { + return (dispatch: any) => { + const data = { + email: email, + password: password, + returnSecureToken: true, + }; + + let url = `https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=AIzaSyBq4PiZ3S-qQnXK3LBw_8CvfBMSkQU6obY`; + + if (!isSignupMode) { + url = `https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=AIzaSyBq4PiZ3S-qQnXK3LBw_8CvfBMSkQU6obY`; } -} \ No newline at end of file + + fetch(url, { + method: "POST", + 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.AUTH_SUCCESS, + idToken: data.idToken, + userId: data.localId, + }); + }) + .catch((error) => { + dispatch({ type: actionType.AUTH_FAIL, error: error.message }); + }); + }; +}; + +export const authLogout = () => { + return { + type: actionType.AUTH_LOGOUT, + }; +}; + +export const addToDo = ( + name: string, + desc: string, + type: string, + important: boolean, + date: string, + token: string, + userId: string +) => { + return (dispatch: any) => { + const data = { + name: name, + desc: desc, + type: type, + important: important, + date: date, + userId: userId, + }; + + let url = `https://to-do-studia.firebaseio.com/todos.json?auth=${token}`; + + fetch(url, { + method: "POST", + 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.ADD_SUCCESS, + }); + }) + .catch((err) => { + dispatch({ + type: actionType.ADD_FAIL, + error: err, + }); + }); + }; +}; diff --git a/src/store/actions/index.ts b/src/store/actions/index.ts index e69de29..2548e33 100644 --- a/src/store/actions/index.ts +++ b/src/store/actions/index.ts @@ -0,0 +1 @@ +export {loadToDos, addToDo, auth, authLogout} from './actions'; \ No newline at end of file diff --git a/src/store/reducers/reducer.ts b/src/store/reducers/reducer.ts index 950dd46..6568d99 100644 --- a/src/store/reducers/reducer.ts +++ b/src/store/reducers/reducer.ts @@ -1,21 +1,72 @@ import * as actionType from "../actions/actionTypes"; -import produce from "immer" +import produce from "immer"; const initialState = { isLoading: true, todos: [], isAuth: false, + apiError: null, + error: null, + userId: null, + idToken: null, + redirectTo: "", }; -interface ActionType{ - type:string +interface ActionType { + type: any; + userId: any; + idToken: any; + error: any; + todos: []; } -const reducer = (state = initialState, action:ActionType) => { +const reducer = (state = initialState, action: ActionType) => { switch (action.type) { case actionType.LOAD_TODOS: { return state; } + case actionType.AUTH_SUCCESS: + return { + ...state, + isAuth: true, + error: null, + userId: action.userId, + idToken: action.idToken, + redirectTo: "/", + }; + case actionType.AUTH_FAIL: + return { + ...state, + error: action.error, + }; + case actionType.ADD_SUCCESS: + return { + ...state, + }; + case actionType.ADD_FAIL: + return { + ...state, + error: action.error, + }; + case actionType.AUTH_LOGOUT: + return { + ...state, + isAuth: false, + userId: null, + idToken: null, + rateData: null, + }; + case actionType.LOAD_SUCCESS: + return { + ...state, + todos: action.todos, + isLoading: false, + }; + case actionType.LOAD_FAIL: + return { + ...state, + error: action.error, + }; default: return state; }
Already registered{" "} {signUp ? ( - setSignUp(false)}>sign in? + setSignUp(false)}> + sign in? + ) : ( - setSignUp(true)}>sign up? + setSignUp(true)}> + sign up? + )}
{todo.taskDesc}
{todo.isImportant && "important"}
{todo.taskType}