Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exercises-1 pull req Dan Menahem #6

Open
wants to merge 32 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
730004d
update title and app name, and add icon
DanMenahem May 14, 2022
c9cc47b
Add all the html elements and css
DanMenahem May 15, 2022
dae8f58
Add all the functionality and fix some CSS and HTML
DanMenahem May 15, 2022
b3aef8d
Change the shape of the functions for adding more functionality in fu…
DanMenahem May 17, 2022
49f0f70
Change the way li are created and saved. fix the bug that when a task…
DanMenahem May 18, 2022
c291d5b
Add animation when a new item is added
DanMenahem May 18, 2022
d21409a
Edit some comments
DanMenahem May 18, 2022
f0f34a1
Merge branch 'monday-u-com:main' into main
DanMenahem May 22, 2022
5569207
start Ex2
DanMenahem May 22, 2022
de78f71
Refactor my current code to use classes with methods
DanMenahem May 24, 2022
931ef53
Add all the new class and the functionality
DanMenahem May 24, 2022
9d3d245
fix a bug
DanMenahem May 24, 2022
ddb4482
delete console.log and rename a function
DanMenahem May 26, 2022
c230c99
Merge branch 'monday-u-com:main' into main
DanMenahem May 30, 2022
77ba7ef
refactor the code to work as cli
DanMenahem May 31, 2022
acf582e
add move the add todo function to ItemManager class
DanMenahem May 31, 2022
ffa366f
fix the קxercise after the mentors comments
DanMenahem Jun 9, 2022
b0060ed
Merge pull request #1 from DanMenahem/Ex2
DanMenahem Jun 9, 2022
4435ae9
add 'this.' before CheckIfEmpty function
DanMenahem Jun 9, 2022
e0e08c3
add image with ascii art when pokemon added
DanMenahem Jun 9, 2022
aebf3e4
Merge pull request #3 from monday-u-com/main
DanMenahem Jun 12, 2022
568035c
change some comments
DanMenahem Jun 13, 2022
dec4ec5
build a express backend and fix the client side
DanMenahem Jun 16, 2022
415ce0a
Merge pull request #2 from DanMenahem/Ex3
DanMenahem Jun 16, 2022
9b06aca
Initialize Sequelize and add items table
DanMenahem Jun 20, 2022
91c5900
add status column and modify client and server to work with it
DanMenahem Jun 21, 2022
bc01042
Merge pull request #4 from DanMenahem/ex4
DanMenahem Jul 3, 2022
84971ca
Merge pull request #5 from DanMenahem/ex5
DanMenahem Jul 3, 2022
1cc8c5d
Merge branch 'ex4'
DanMenahem Jul 6, 2022
94202eb
Merge branch 'main' of https://github.com/DanMenahem/monday-u-exercise-1
DanMenahem Jul 6, 2022
2649797
reset commit
DanMenahem Jul 6, 2022
cfe68e0
Merge branch 'main' of https://github.com/DanMenahem/monday-u-exercise-1
DanMenahem Jul 6, 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
30 changes: 15 additions & 15 deletions src/ex1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,24 @@ A todo app!
Almost as cool as our boards, but with a bit less functionality.
The requirements:
- [x] Import the relevant CSS (style.css) and JS (script.js) files - already done for you
- [ ] Choose a name for your app and update the title to your app name
- [ ] Add your app name in the top of the screen (see mock)
- [ ] Build the layout according to the mock. (background, centered white box, etc...)
- [ ] Add a textbox to be used for adding tasks
- [ ] Add a button ("Add task")
- [ ] When "Add task" button is clicked, add a task to the task list
- [ ] Change the background and cursor type of an item when hovered on
- [ ] When a list item is clicked, show 'alert' (**Hint**: check the [alert](https://developer.mozilla.org/en-US/docs/Web/API/Window/alert) method) with the item name
- [ ] Delete an item when "Delete" button is clicked
- [x] Choose a name for your app and update the title to your app name
- [x] Add your app name in the top of the screen (see mock)
- [x] Build the layout according to the mock. (background, centered white box, etc...)
- [x] Add a textbox to be used for adding tasks
- [x] Add a button ("Add task")
- [x] When "Add task" button is clicked, add a task to the task list
- [x] Change the background and cursor type of an item when hovered on
- [x] When a list item is clicked, show 'alert' (**Hint**: check the [alert](https://developer.mozilla.org/en-US/docs/Web/API/Window/alert) method) with the item name
- [x] Delete an item when "Delete" button is clicked


Bonus
- [ ] Clear the input when a new item is added
- [ ] Add input validation. e.g when the text input is empty, show a message with an error
- [ ] Add "empty state" - when there are no items on the list, show some nice and inviting UI to encourage the user to add items
- [ ] Add ability to sort the list by name
- [ ] Add task when enter key is pressed
- [ ] Add animation when a new item is added
- [x] Clear the input when a new item is added
- [x] Add input validation. e.g when the text input is empty, show a message with an error
- [x] Add "empty state" - when there are no items on the list, show some nice and inviting UI to encourage the user to add items
- [x] Add ability to sort the list by name
- [x] Add task when enter key is pressed
- [x] Add animation when a new item is added
- [ ] have another cool idea? Go wild!

When you finish, it should look like this:
Expand Down
33 changes: 28 additions & 5 deletions src/ex1/index.html
Original file line number Diff line number Diff line change
@@ -1,14 +1,37 @@
<!DOCTYPE html>
<html lang="en">

<head>
<title>Exercise 1</title>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice

<title>My Todo List</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="icon" href="../images/todo-icon.png">
<link rel="stylesheet" href="style.css" />
</head>
<body>

<h1>Todo list</h1>

<body onload="init()">
<div class="container">
<h1>My Todo list</h1>
<div id="add-task">
<input type="text" id="taskInput" placeholder="Add your new todo task">
<button class="btn" id="addBtn" disabled>+</button>
</div>
<ul id="taskList">
</ul>
<div class="placeHolder hidden">
<i class="fa fa-plus"></i>
<p>Time to add your first task</p>
</div>
<div id="info">

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good dom modeling, gj!

<span id="peding-task-text">You have 0 pending tasks</span>
<button class="btn" id="clearAllBtn" disabled>Clear All</button>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job on reusing the btn class!

<button class="btn" id="sortAllBtn" disabled>Sort All</button>
</div>
</div>

</body>
<script src="script.js"></script>
</html>

</html>
100 changes: 100 additions & 0 deletions src/ex1/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
const taskInput = document.querySelector(" #taskInput ");
const addBtn = document.querySelector(" #addBtn ");
const clearAllBtn = document.querySelector(" #clearAllBtn ");
const sortAllBtn = document.querySelector(" #sortAllBtn ");
const taskList = document.querySelector(" #taskList ");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

having all the elements outside here requires all the dom elements exist when this file is loaded, which might not be the case in complex web apps that dynamically change the dom depending on the view

const placeHolder = document.querySelector(" .placeHolder ")
const pedingTaskText = document.querySelector(" #peding-task-text ")

const taskArr = JSON.parse(localStorage.getItem("tasks")) || [];

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice!
consider moving this to a function that handles the initial loading of the tasks



//waiting for user input before enable the add button
taskInput.addEventListener('keyup', () => addBtn.disabled = !taskInput.value)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extract the validation into a function as multiple sources need to use it :)


// add a task when user press Enter key
taskInput.addEventListener("keypress", (e) => { if (e.key === 'Enter') addNewTask(taskInput.value) });

//add click event listener to add button
addBtn.addEventListener("click", () => addNewTask(taskInput.value));

//sort the tasks list add them to html list element and save them to the LocalStorage
sortAllBtn.addEventListener("click", () => {
taskArr.sort();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the sort method mutates the original array, therefore it's better to copy it beforehand ex: taskArr = [...taskArr.sort()];

As mutating the state directly (and complex data structures in general) is considered a bad practice as other parts of the code might be using it, not expecting it to suddenly change.
Read more on pure functions and the immutability approach in coding https://css-tricks.com/understanding-immutability-in-javascript/

taskList.innerHTML = '';
insertAllTasks();
localStorage.setItem("tasks", JSON.stringify(taskArr)); //add the updated task array to the localStorage
})

//Clear the tasks list
clearAllBtn.addEventListener("click", () => {
taskArr.length = 0;
Copy link

@SergeiSafrigin SergeiSafrigin May 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not a common usage, I would change it to taskArr = [];
Also it mutates taskArr directly which is a bad practice due to the comment above

taskList.innerHTML = ''; //Clear the list of tasks element
localStorage.setItem("tasks", JSON.stringify(taskArr)); //add the updated task array to the localStorage
updateForm();
})

//function to add task and update the list and the localStorage
function addNewTask(taskValue) {
taskArr.push(taskValue); //add the user value to the task array
taskList.appendChild(createLi(taskValue));
taskInput.value = ''; //clear the input after added
addBtn.disabled = true;
localStorage.setItem("tasks", JSON.stringify(taskArr)); //add the updated task array to the localStorage
updateForm();
}

// function to remove task that have been clicked
function removeTask(li, taskValue) {
taskArr.splice(taskArr.indexOf(taskValue), 1);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As task holds only the text value it is not unique, therefore you might be removing the wrong task from the list. Consider an alternative approach. hint: find a way to uniquely identify tasks

taskList.removeChild(li);
localStorage.setItem("tasks", JSON.stringify(taskArr)); //add the updated task array to the localStorage
updateForm();
}

//update the button and the placeHolder if necessary
function updateForm() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider renaming the function to make it more descriptive or even separate into 2 different functions as you always know what you actually need to do beforehand. 1 for hiding the empty state and other for showing it

pedingTaskText.innerHTML = "You have " + taskArr.length + " pending tasks"
if (taskArr.length === 0) { //if there are no task any more disable the clear and sort button
clearAllBtn.disabled = true;
sortAllBtn.disabled = true;
placeHolder.classList.remove("hidden");
}
else {
clearAllBtn.disabled = false;
sortAllBtn.disabled = false;
placeHolder.classList.add("hidden");
}
}

//function to insert the all tasks from the localStorage to the html list element
function insertAllTasks() {
taskArr.forEach((taskValue) => {
taskList.appendChild(createLi(taskValue));
});
updateForm();
}

//Function to create the li element and its childs and assign a click event to them
function createLi(taskValue) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as the css point, let's decouple this by changing to something more general like createTaskElement/createTaskNode

const li = document.createElement("li");
const span = document.createElement("span");
const i = document.createElement("i");
li.innerHTML = taskValue;
i.classList.add("fa", "fa-trash-o");
span.appendChild(i);
li.appendChild(span);
span.onclick = (e) => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prefer using the addEventListener instead of onclick directly

e.stopPropagation(); //stop the parent elemnt to listen to click event
removeTask(li, taskValue);
};
li.onclick = () => alert(taskValue);
li.classList.add('new-li');
return li;
}

//if there are some task in the localStorage insert them
function init() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice use of init, I would add the loading of the localStorage and initializing the tasksList here as well

if (taskArr.length != 0) insertAllTasks();
else placeHolder.classList.remove("hidden");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

code duplication, this could have been instead a call to showEmptyState()/ showEmptyStateIfNeeded()/toggleEmptyState() or something similar

}
163 changes: 163 additions & 0 deletions src/ex1/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
* {
font-family: Alef, Arial, Helvetica, sans-serif;
font-size: 20px;
margin: 0;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in general, it's usually a bad practice to use the wildcard selector *, as it applies to all elements, rather than inheriting the style from a parent element (it still could be html or body) which are much easier to override when needed.
You can read more on CSS precedence here - https://jenkov.com/tutorials/css/precedence.html

You also have this cool library that normalizes the base/default styles across different browsers - https://necolas.github.io/normalize.css/

padding: 0;
}

body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
width: 100%;
background: linear-gradient(to top, rgb(47, 255, 102) 0%, rgb(0, 200, 255) 100%);
}

h1 {
font-size: 35px;
}


.container {
background-color: white;
border-radius: 10px;
width: 100%;
max-width: 500px;
padding: 25px;
}

.btn[disabled] {
opacity: 0.3;
box-shadow: none;
border: none;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

duplicate? isn't it already in .btn?

}

.btn[disabled]:hover {
cursor: not-allowed;
box-shadow: none;
Copy link

@SergeiSafrigin SergeiSafrigin May 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

duplicate? isn't it already in .btn[disabled]? (move below .btn:hover)

}

.btn {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's a good practice to put all the different variants of a style after the base is defined so the variants will get a priority and could override the base class with ease and without the need for !important

height: 100%;
text-align: center;
color: white;
border: none;
margin-left: 10px;
border-radius: 8px;
cursor: pointer;
background-color: rgb(30, 75, 254);
}

.btn:hover {
background-color: rgb(0, 51, 255);
box-shadow: 0.5px 0.5px 10px 0.5px grey;
}


.placeHolder {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
color: greenyellow;
font-size: 100px;
opacity: 0.3;
padding: 60px;
border: 1px solid rgb(99, 99, 99);
border-radius: 8px;
}

.hidden {
display: none;
}

.placeHolder p {
margin-top: 5px;
color: black;
}

#addBtn {
width: 60px;
font-size: 30px;
}

#add-task {
display: flex;
width: 100%;
height: 50px;
margin: 30px 0;
}

#add-task input {
width: 90%;
height: 100%;
border: 1px solid #ccc;
border-radius: 8px;
padding-left: 15px;
outline: none;
}


#taskList {
max-height: 260px;
overflow-y: auto;
}


#taskList li {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using "li" here instead of a class makes it coupled to this specific solution. If you'll need to change li to a different element (ex: div) you'll have to make many changes in the code

list-style: none;
line-height: 45px;
margin-bottom: 8px;
background-color: rgb(237, 237, 237);
border-radius: 8px;
padding-left: 15px;
position: relative;
overflow: hidden;
}

#taskList li span {
Copy link

@SergeiSafrigin SergeiSafrigin May 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same goes for the span here better to use a class name. Also for readability, a descriptive classname will tell me on which element this style is targeting

position: absolute;
right: -45px;
background-color: red;
color: white;
width: 40px;
text-align: center;
border-radius: 0 8px 8px 0;
cursor: pointer;
transition: all 0.3s ease;
}

#taskList li:hover span {
right: 0;
}

#info {
display: flex;
justify-content: space-around;
width: 100%;
margin-top: 20px;
align-items: center;
}

#clearAllBtn,
#sortAllBtn {
padding: 10px;
}

@keyframes append-animate {
from {
transform: translateX(-100%);
opacity: 1;
}

to {
transform: translateX(0%);
opacity: 1;
}
}

/* animate new box */
.new-li {
animation: append-animate .4s linear;
}
29 changes: 29 additions & 0 deletions src/ex2/ItemManager.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
class ItemManager {
constructor() {
this.taskArr = JSON.parse(localStorage.getItem("tasks")) || [];
}

addNewTask(taskValue) {
this.taskArr.push(taskValue); //add the user value to the task array
this.updateLocalStorage(this.taskArr);
}

removeTask(taskValue) {
this.taskArr = this.taskArr.filter(task => task !== taskValue);
this.updateLocalStorage(this.taskArr);
}

sortArr() {
this.taskArr.sort();
this.updateLocalStorage(this.taskArr);
}

clearArr() {
this.taskArr.length = 0;
this.updateLocalStorage(this.taskArr);
}

updateLocalStorage(valueToUpdate) {
localStorage.setItem("tasks", JSON.stringify(valueToUpdate)); //add the updated task array to the localStorage
}
}
Loading