Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
f71355f
data structure added
iigunchev Feb 15, 2022
6634bd9
basic sass structure added
iigunchev Feb 15, 2022
0e34557
layout WIP
iigunchev Feb 15, 2022
4a98248
CreateToDo component
iigunchev Feb 16, 2022
5fae0f7
ToDoItem component WIP
iigunchev Feb 16, 2022
bdb618f
display all todos
gcachonc Feb 16, 2022
47e8fe2
delete Todo Items
gcachonc Feb 16, 2022
31282cd
update work in progress
gcachonc Feb 16, 2022
c8b0f12
todo item isCompleted fix
iigunchev Feb 16, 2022
c65c18f
empty todo list message
iigunchev Feb 17, 2022
20c7066
error message in the main input
iigunchev Feb 17, 2022
5c898d2
render total number of todos
gcachonc Feb 17, 2022
ea265c1
update todo wip
gcachonc Feb 17, 2022
8e9be8c
input component data transfer
gcachonc Feb 17, 2022
769ed46
fix update and added styles to update
iigunchev Feb 18, 2022
76fe4b6
merge from components
iigunchev Feb 18, 2022
d8aee37
router wip
iigunchev Feb 18, 2022
af6a65d
cleaning up consolelogs and adding comments
iigunchev Feb 18, 2022
5903abb
refactor update value of a ToDo Item function
iigunchev Feb 20, 2022
29a3061
added animations to the ui elements
iigunchev Feb 21, 2022
2de79e4
Merge pull request #1 from iigunchev/animations
iigunchev Feb 21, 2022
614973e
local storage implemented
iigunchev Feb 21, 2022
373866b
dark mode wip
iigunchev Feb 21, 2022
3247e77
responsive container fix
iigunchev Feb 21, 2022
6cb8be8
create todo with label
iigunchev Feb 21, 2022
3c9ec98
update placeholder, empty error and useRef
iigunchev Feb 22, 2022
b998457
es6 arrow functions refactoring of App component
iigunchev Feb 22, 2022
633f26b
refactoring todo item
iigunchev Feb 22, 2022
d197526
Add quotes from API
gcachonc Feb 22, 2022
38dba2b
fix quotes style
gcachonc Feb 22, 2022
2f8f11b
clean code and comments
iigunchev Feb 23, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file modified .all-contributorsrc
100644 → 100755
Empty file.
Empty file modified .babelrc
100644 → 100755
Empty file.
Empty file modified .eslintignore
100644 → 100755
Empty file.
1 change: 1 addition & 0 deletions .eslintrc.js
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ module.exports = {
},
],
rules: {
"no-param-reassign": 0,
"prettier/prettier": [
"error",
{
Expand Down
Empty file modified .github/CONTRIBUTING.md
100644 → 100755
Empty file.
Empty file modified .github/ISSUE_TEMPLATE/FEATURE.md
100644 → 100755
Empty file.
Empty file modified .github/ISSUE_TEMPLATE/ISSUE.md
100644 → 100755
Empty file.
Empty file modified .github/ISSUE_TEMPLATE/QUESTION.md
100644 → 100755
Empty file.
Empty file modified .github/PULL_REQUEST_TEMPLATE/pull_request_template.md
100644 → 100755
Empty file.
Empty file modified .github/workflows/ci.yml
100644 → 100755
Empty file.
Empty file modified .gitignore
100644 → 100755
Empty file.
1 change: 1 addition & 0 deletions .husky/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
_
Empty file modified .prettierrc
100644 → 100755
Empty file.
Empty file modified LICENSE
100644 → 100755
Empty file.
Empty file modified README.md
100644 → 100755
Empty file.
Empty file modified cypress.json
100644 → 100755
Empty file.
Empty file modified cypress/fixtures/todos.json
100644 → 100755
Empty file.
Empty file modified cypress/integration/render-todos.spec.js
100644 → 100755
Empty file.
Empty file modified cypress/plugins/index.js
100644 → 100755
Empty file.
Empty file modified cypress/support/commands.js
100644 → 100755
Empty file.
Empty file modified cypress/support/index.js
100644 → 100755
Empty file.
657 changes: 280 additions & 377 deletions package-lock.json
100644 → 100755

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions package.json
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@
"clsx": "^1.1.1",
"cypress": "^7.5.0",
"formik": "^2.2.6",
"framer-motion": "^6.2.6",
"prop-types": "^15.7.2",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-redux": "^7.2.3",
"react-router-dom": "^5.2.0",
"react-router-dom": "^5.3.0",
"react-scripts": "4.0.3",
"redux": "^4.0.5",
"redux-thunk": "^2.3.0",
Expand Down Expand Up @@ -57,7 +58,7 @@
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-jest": "^24.3.5",
"eslint-plugin-jsx-a11y": "^6.4.1",
"eslint-plugin-markdown": "^2.0.1",
"eslint-plugin-markdown": "^2.2.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-react": "^7.23.2",
Expand Down
Empty file modified public/favicon.ico
100644 → 100755
Empty file.
1 change: 1 addition & 0 deletions public/index.html
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
name="description"
content="Web site created using create-react-app"
/>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons+Outlined">
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
Expand Down
Empty file modified public/logo192.png
100644 → 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified public/logo512.png
100644 → 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file modified public/manifest.json
100644 → 100755
Empty file.
Empty file modified public/robots.txt
100644 → 100755
Empty file.
179 changes: 171 additions & 8 deletions src/App.js
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,14 +1,177 @@
import React from "react";
import React, { useState, useEffect } from "react";
import { BrowserRouter, Route } from "react-router-dom";
import { motion } from "framer-motion/dist/framer-motion";

import "./sass/main.scss";
import imgLight from "./img/motivation.jpg";
import imgDark from "./img/motivation2.jpg";
import { data } from "./utils/data";
import makeNewId from "./utils/hash";

// Components
import ToDoList from "./components/ToDoList";
import CreateToDo from "./components/CreateToDo";
import Quote from "./components/Quote";

const classNames = require("classnames");

function App() {
const [toDoItems, setToDoItems] = useState(data);
const [formData, setFormData] = useState({
id: "",
text: "",
done: false,
isEditing: false,
label: "",
});

// React Router routes
const [isEmpty, setIsEmpty] = useState(false);
const [todoIsEmpty, setTodoIsEmpty] = useState(false);
const [darkTheme, setDarkTheme] = useState(false);

const completedTodos = toDoItems.filter((item) => item.done === true);
const activeTodos = toDoItems.filter((item) => item.done !== true);

// Local storage
useEffect(() => {
const storedTodos = JSON.parse(localStorage.getItem("todos"));
if (storedTodos) setToDoItems(storedTodos);
}, []);

useEffect(() => {
localStorage.setItem("todos", JSON.stringify(toDoItems));
}, [toDoItems]);

const routes = [
{ path: "/", data: toDoItems },
{ path: "/completed", data: completedTodos },
{ path: "/active", data: activeTodos },
];

// Create New Item
const handleChange = (e) => {
const { name, value } = e.target;
setFormData((prevState) => {
return {
...prevState,
[name]: value,
};
});
setIsEmpty(false);
};
const handleSubmit = (e) => {
e.preventDefault();
// Empty error
if (formData.text === "") {
setIsEmpty(true);
return;
}
const newToDo = {
id: makeNewId(),
text: formData.text,
done: false,
isEditing: false,
label: formData.label,
};
setToDoItems((prevState) => [newToDo, ...prevState]);
setFormData({
id: "",
text: "",
done: false,
isEditing: false,
label: "",
});
};
// Delete
const handleDelete = (id) => {
const deleteIndex = toDoItems.find((index) => index.id === id);
setToDoItems((prevState) => {
const newState = prevState.filter((item) => item !== deleteIndex);
return newState;
});
};
// Modify a formData of a ToDo Item
const changeformData = (id, param) => {
const element = toDoItems.find((index) => index.id === id);
const index = toDoItems.indexOf(element);
const newState = Array.from(toDoItems);
newState[index][param] = !newState[index][param];
setToDoItems(newState);
};
// Is Completed
const isCompleted = (id) => {
const element = toDoItems.find((index) => index.id === id);
handleDelete(id);
const newToDo = {
id: element.id,
text: element.text,
done: !element.done,
isEditing: false,
label: element.label,
};
setToDoItems((prevState) => [...prevState, newToDo]);
};
// Is Editing
const toggleEditing = (id) => changeformData(id, "isEditing");
// Clear Completed Items
const clearCompleted = () => setToDoItems(activeTodos);

const changeTheme = () => setDarkTheme(!darkTheme);

return (
<main className="container mt-5">
<section className="row">
<div className="col col-12">
<h1>Hola mundo</h1>
</div>
</section>
</main>
<BrowserRouter>
<main className={darkTheme ? classNames("dark-mode") : ""}>
<header>
<img
src={darkTheme ? imgDark : imgLight}
alt="motivated person in the mountains"
/>
</header>
<section
id="container-sm"
className="container-sm d-flex flex-column fixed-top align-items-center h-100"
>
<div className="main-header w-100 mt-5 d-flex justify-content-between">
<h1>TODO</h1>
<motion.button
initial={{ opacity: 0, y: -25 }}
animate={{ opacity: 1, y: 0 }}
className=""
type="button"
onClick={changeTheme}
>
<span className="material-icons-outlined md-48">
{darkTheme ? "dark_mode" : "light_mode"}
</span>
</motion.button>
</div>
<Quote />
<CreateToDo
value={formData.text}
handleChange={handleChange}
handleSubmit={handleSubmit}
emptyError={isEmpty}
/>
{routes.map((route) => (
<Route key={route} path={route.path} exact>
<ToDoList
data={route.data}
handleDelete={handleDelete}
isCompleted={isCompleted}
handleError={setTodoIsEmpty}
emptyError={todoIsEmpty}
toggleEditing={toggleEditing}
handleClear={clearCompleted}
reorderList={setToDoItems}
theme={darkTheme}
/>
</Route>
))}
<h6 className="mt-5">Drag and drop to reorder list</h6>
</section>
</main>
</BrowserRouter>
);
}

Expand Down
Empty file modified src/__tests__/App.test.js
100644 → 100755
Empty file.
131 changes: 131 additions & 0 deletions src/components/CreateToDo/CreateToDo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import React, { useState, useRef, useEffect } from "react";

import { motion } from "framer-motion/dist/framer-motion";

import "./CreateToDo.scss";

const classNames = require("classnames");

export default function CreateToDo({
value,
handleChange,
handleSubmit,
handleKeyPress,
emptyError,
}) {
const [todoLabel, setTodoLabel] = useState("");
const inputRef = useRef();

useEffect(() => {
inputRef.current.focus();
}, []);
return (
<form action="" className="create-todo-input">
<span className="material-icons-outlined md-30">circle</span>
<input
ref={inputRef}
className={emptyError ? "inputError" : ""}
type="text"
placeholder={
!emptyError
? "Create new item"
: "Please enter at least one character"
}
value={value}
onChange={handleChange}
onKeyPress={handleKeyPress}
data-testid="create-todo-input"
name="text"
/>
<fieldset required>
<motion.label
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.9 }}
htmlFor="green-option"
className={
todoLabel === "green"
? classNames("label-border-green", "green-label")
: "green-label"
}
>
<input
type="radio"
id="green-option"
name="label"
value="#06d6a0"
onChange={handleChange}
style={{ display: "none" }}
onClick={() => setTodoLabel("green")}
/>
</motion.label>
<motion.label
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.9 }}
className={
todoLabel === "red"
? classNames("label-border-red", "red-label")
: "red-label"
}
htmlFor="red-option"
>
<input
type="radio"
id="red-option"
name="label"
value="#ef476f"
onChange={handleChange}
style={{ display: "none" }}
onClick={() => setTodoLabel("red")}
/>
</motion.label>
<motion.label
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.9 }}
className={
todoLabel === "orange"
? classNames("label-border-orange", "orange-label")
: "orange-label"
}
htmlFor="orange-option"
>
<input
type="radio"
id="orange-option"
name="label"
value="#fb5607"
onChange={handleChange}
style={{ display: "none" }}
onClick={() => setTodoLabel("orange")}
/>
</motion.label>
<motion.label
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.9 }}
className={
todoLabel === "blue"
? classNames("label-border-blue", "blue-label")
: "blue-label"
}
htmlFor="blue-option"
>
<input
type="radio"
id="blue-option"
name="label"
value="#3a86ff"
onChange={handleChange}
style={{ display: "none" }}
onClick={() => setTodoLabel("blue")}
/>
</motion.label>
</fieldset>
<button
type="submit"
style={{ display: "none" }}
onClick={handleSubmit}
name=""
value=""
/>
</form>
);
}
Loading