From 73a5c7fae9ffbe9ada721148c8c454a643aceebe Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Sun, 20 Feb 2022 16:11:50 +0100 Subject: chore!: restructure repo I separated public files from the config/dev files. It improves repo readability. I also moved dotenv helper to public/inc directory and extract the Matomo tracker in the same directory. --- .../apps/todos/src/views/Account/Account.js | 26 +++++++ .../apps/todos/src/views/Account/Account.scss | 15 ++++ .../apps/todos/src/views/LoginForm/LoginForm.js | 84 +++++++++++++++++++++ .../apps/todos/src/views/Logout/Logout.js | 18 +++++ .../apps/todos/src/views/Todo/Todo.js | 86 ++++++++++++++++++++++ .../apps/todos/src/views/Todo/Todo.scss | 31 ++++++++ .../apps/todos/src/views/TodoForm/TodoForm.js | 42 +++++++++++ .../apps/todos/src/views/TodoList/TodoList.js | 84 +++++++++++++++++++++ .../apps/todos/src/views/TodoList/TodoList.scss | 63 ++++++++++++++++ .../todos/src/views/TodoList/TodoListFilters.js | 47 ++++++++++++ .../apps/todos/src/views/TodoList/TodoListItem.js | 55 ++++++++++++++ 11 files changed, 551 insertions(+) create mode 100644 public/projects/react-small-apps/apps/todos/src/views/Account/Account.js create mode 100644 public/projects/react-small-apps/apps/todos/src/views/Account/Account.scss create mode 100644 public/projects/react-small-apps/apps/todos/src/views/LoginForm/LoginForm.js create mode 100644 public/projects/react-small-apps/apps/todos/src/views/Logout/Logout.js create mode 100644 public/projects/react-small-apps/apps/todos/src/views/Todo/Todo.js create mode 100644 public/projects/react-small-apps/apps/todos/src/views/Todo/Todo.scss create mode 100644 public/projects/react-small-apps/apps/todos/src/views/TodoForm/TodoForm.js create mode 100644 public/projects/react-small-apps/apps/todos/src/views/TodoList/TodoList.js create mode 100644 public/projects/react-small-apps/apps/todos/src/views/TodoList/TodoList.scss create mode 100644 public/projects/react-small-apps/apps/todos/src/views/TodoList/TodoListFilters.js create mode 100644 public/projects/react-small-apps/apps/todos/src/views/TodoList/TodoListItem.js (limited to 'public/projects/react-small-apps/apps/todos/src/views') diff --git a/public/projects/react-small-apps/apps/todos/src/views/Account/Account.js b/public/projects/react-small-apps/apps/todos/src/views/Account/Account.js new file mode 100644 index 0000000..85aab6b --- /dev/null +++ b/public/projects/react-small-apps/apps/todos/src/views/Account/Account.js @@ -0,0 +1,26 @@ +import { useSelector } from "react-redux"; +import { Link } from "react-router-dom"; +import "./Account.scss"; + +function Account() { + const currentUser = useSelector((state) => state.auth.currentUser); + + return ( +
+ Back to your todo list +

Account

+
+
Username
+
{currentUser.username}
+
Email
+
{currentUser.email}
+
Creation date
+
+ {new Date(currentUser.createdAt).toLocaleDateString()} +
+
+
+ ); +} + +export default Account; diff --git a/public/projects/react-small-apps/apps/todos/src/views/Account/Account.scss b/public/projects/react-small-apps/apps/todos/src/views/Account/Account.scss new file mode 100644 index 0000000..a8b2ba7 --- /dev/null +++ b/public/projects/react-small-apps/apps/todos/src/views/Account/Account.scss @@ -0,0 +1,15 @@ +.account-details { + display: grid; + grid-template-columns: max-content minmax(0, 1fr); + row-gap: 0.5rem; + column-gap: 1rem; + + &__headings { + grid-column: 1; + font-weight: 600; + } + + &__data { + grid-column: 2; + } +} diff --git a/public/projects/react-small-apps/apps/todos/src/views/LoginForm/LoginForm.js b/public/projects/react-small-apps/apps/todos/src/views/LoginForm/LoginForm.js new file mode 100644 index 0000000..6c90e67 --- /dev/null +++ b/public/projects/react-small-apps/apps/todos/src/views/LoginForm/LoginForm.js @@ -0,0 +1,84 @@ +import { useState } from "react"; +import { useDispatch, useSelector } from "react-redux"; +import { useNavigate } from "react-router-dom"; +import { Button, Fieldset, Input } from "../../components/forms"; +import { login } from "../../store/auth/auth.slice"; + +function LoginForm() { + const [inputEmailValue, setInputEmailValue] = useState(""); + const [inputPasswordValue, setInputPasswordValue] = useState(""); + const [errorMsg, setErrorMsg] = useState(""); + const usersList = useSelector((state) => state.users); + const dispatch = useDispatch(); + const navigate = useNavigate(); + + const getCurrentUser = (email) => { + return usersList.find((user) => user.email === email); + }; + + const isValidUser = (email) => { + const currentUser = getCurrentUser(email); + return currentUser ? true : false; + }; + + const isValidPassword = (currentUser, password) => { + return currentUser.password === password; + }; + + const handleSubmit = (e) => { + e.preventDefault(); + if (isValidUser(inputEmailValue)) { + const currentUser = getCurrentUser(inputEmailValue); + + if (isValidPassword(currentUser, inputPasswordValue)) { + setErrorMsg(""); + dispatch(login(currentUser)); + navigate("/"); + } else { + setErrorMsg("The password does not match."); + } + } else { + setErrorMsg("This email address does not exist."); + } + }; + + const displayError = (msg) => { + return msg ?

{msg}

: ""; + }; + + return ( +
+ {displayError(errorMsg)} +
+ + + +
+
+ ); +} + +export default LoginForm; diff --git a/public/projects/react-small-apps/apps/todos/src/views/Logout/Logout.js b/public/projects/react-small-apps/apps/todos/src/views/Logout/Logout.js new file mode 100644 index 0000000..cf9bbd0 --- /dev/null +++ b/public/projects/react-small-apps/apps/todos/src/views/Logout/Logout.js @@ -0,0 +1,18 @@ +import { useEffect } from "react"; +import { useDispatch } from "react-redux"; +import { useNavigate } from "react-router-dom"; +import { logout } from "../../store/auth/auth.slice"; + +function Logout() { + const dispatch = useDispatch(); + const navigate = useNavigate(); + + useEffect(() => { + dispatch(logout()); + navigate("/"); + }); + + return <>Logging out...; +} + +export default Logout; diff --git a/public/projects/react-small-apps/apps/todos/src/views/Todo/Todo.js b/public/projects/react-small-apps/apps/todos/src/views/Todo/Todo.js new file mode 100644 index 0000000..1160ab5 --- /dev/null +++ b/public/projects/react-small-apps/apps/todos/src/views/Todo/Todo.js @@ -0,0 +1,86 @@ +import { useEffect, useRef } from "react"; +import { useDispatch, useSelector } from "react-redux"; +import { Link, useLocation } from "react-router-dom"; +import { updateTodo } from "../../store/todos/todos.slice"; +import useToggle from "../../utilities/hooks"; +import "./Todo.scss"; + +function Todo() { + const [isTitleEditable, setIsTitleEditable] = useToggle(); + const [isBodyEditable, setIsBodyEditable] = useToggle(); + const titleRef = useRef(null); + const bodyRef = useRef(null); + const location = useLocation(); + const todoId = location.state.todoId; + const currentTodo = useSelector((state) => state.todos).find( + (todo) => todo.id === todoId + ); + const { title, body } = currentTodo; + const dispatch = useDispatch(); + + useEffect(() => { + titleRef.current && titleRef.current.focus(); + bodyRef.current && bodyRef.current.focus(); + }); + + const handleSubmit = (e) => { + console.log(e); + }; + + return ( + <> + Back to your todo list +
+ {isTitleEditable ? ( +
+ + dispatch(updateTodo({ ...currentTodo, title: e.target.value })) + } + onBlur={setIsTitleEditable} + /> +
+ ) : ( +
+ {title} +
+ )} + {isBodyEditable ? ( +
+