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

feat/todo #4

Merged
merged 36 commits into from
Aug 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
614e53c
Create Todos component to be reused 4 times
danifromecuador Aug 12, 2024
c7a786f
Add minimal style to Todo & Todos components
danifromecuador Aug 12, 2024
ae4f517
Create todoDailySlice and Render todos array
danifromecuador Aug 12, 2024
59bcfae
Store all data for each Todo component in the Zustand store
danifromecuador Aug 12, 2024
9990bef
Change names between Todos.jsx and Todo.jsx
danifromecuador Aug 12, 2024
3cc7de3
Add an item to the todos or dones array in Store
danifromecuador Aug 13, 2024
1c44eae
Remove commented code
danifromecuador Aug 13, 2024
6fdd521
Remove completed Tasks component from Daily, Weekly, Monthly componen…
danifromecuador Aug 13, 2024
9b51260
Separate logic from store.js to improve readability
danifromecuador Aug 13, 2024
eb8b933
Remove an item from Daily todos when clicking on it
danifromecuador Aug 13, 2024
3d389c4
Push removed completed todo into dones array
danifromecuador Aug 13, 2024
8ca494a
Change the text color of completed or done items
danifromecuador Aug 13, 2024
9b2001f
Mark an item as todo in daily todo array
danifromecuador Aug 13, 2024
5c88312
Sort todos and dones arrays by its id
danifromecuador Aug 13, 2024
49b6dee
Count completed or dones items to show completed percentage
danifromecuador Aug 13, 2024
8c29f07
Conditional rendering of completed span
danifromecuador Aug 13, 2024
0b262f1
Delete all completed goals
danifromecuador Aug 13, 2024
7cb29e4
Shrin code by using && operator in ternary operator
danifromecuador Aug 13, 2024
f706234
Fix classname typo between Todos and Todo
danifromecuador Aug 13, 2024
4bceb9f
Change cursor shape when overing an li tag
danifromecuador Aug 13, 2024
8d4515c
Conditional rendering of Delete All Completed Btn
danifromecuador Aug 14, 2024
6a93f59
Improve style of Todo component
danifromecuador Aug 14, 2024
0a8f603
Fix Stylelint error
danifromecuador Aug 14, 2024
1d4a4be
Install propTypes library and fix propType ESLint error
danifromecuador Aug 14, 2024
9d14578
Save in localStorage todos and dones items for Daily Goals component
danifromecuador Aug 14, 2024
8b8bcec
Create slices for weekly and monthly data on Store
danifromecuador Aug 15, 2024
c77ca07
Give an aditional prop to each function
danifromecuador Aug 15, 2024
2fdcb00
Render Daily Weekly and Monthly components with a new arg
danifromecuador Aug 15, 2024
be56270
Delete aditional prop from Todos components
danifromecuador Aug 15, 2024
1e4231e
Remove prop sliceID from Todo component
danifromecuador Aug 15, 2024
994d051
Replace the arg with a string when calling functions
danifromecuador Aug 15, 2024
d13b54c
Fix localStorage getting wrong data for dones array
danifromecuador Aug 15, 2024
226cf4d
Fix ESLint error
danifromecuador Aug 15, 2024
ac11b2c
Improve layout on small screens
danifromecuador Aug 15, 2024
46a252f
Fix ESLint errors
danifromecuador Aug 15, 2024
8d1cfe1
Log a specific action type for each `set` function
danifromecuador Aug 16, 2024
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
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
},
"dependencies": {
"axios": "^1.7.3",
"prop-types": "^15.8.1",
"react": "^18.3.1",
"react-countdown": "^2.3.5",
"react-dom": "^18.3.1",
Expand Down
14 changes: 12 additions & 2 deletions src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ button {
display: none;
}

li {
list-style: none;
}

.App {
width: 98vw;
height: 95vh;
Expand All @@ -16,7 +20,7 @@ button {
column-gap: 1%;
}

.Todo,
.Todos,
.Doing,
.Done {
width: 33%;
Expand All @@ -33,12 +37,18 @@ button {
row-gap: 1%;
}

.Todo,
.Todos,
.Doing,
.Done {
width: 100%;
}

.Todos {
overflow-y: visible;
flex-direction: column;
row-gap: 10px;
}

.clock {
font-size: 16vw;
}
Expand Down
28 changes: 10 additions & 18 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,12 @@
// import { Store } from './store/store.js'
import {Todo} from './todo/Todo.jsx'
import {Doing} from './doing/Doing.jsx'
import {Done} from './done/Done.jsx'
import { Todos } from './todo/Todos.jsx'
import { Doing } from './doing/Doing.jsx'
import { Done } from './done/Done.jsx'
import './App.css'

export const App = () => {
// const store = Store()
return (
<div className='App'>
{/* <h1>App Component</h1>
<div>Bears: {store.bears.amount}</div>
<div>Cows: {store.cows.amount}</div>
<button onClick={()=>store.bears.add()}>Add bear</button> */}
<Todo />
<Doing />
<Done />
</div>
)
}
export const App = () => (
<div className='App'>
<Todos />
<Doing />
<Done />
</div>
)
44 changes: 34 additions & 10 deletions src/store/store.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,42 @@
import { create } from "zustand"
import { devtools } from "zustand/middleware"
import { add, completed, markAsDone, markAsTodo, deleteDones } from "./todo_logic.js"

const createBearSlice = set => ({
amount: 42,
add: () => set(state => ({
bears: { ...state.bears, amount: state.bears.amount + 1 }
}))
const todoDailySlice = (set, get) => ({
title: "Daily Goals",
completed: () => completed(get, "daily"),
todos: JSON.parse(localStorage.getItem("Daily Goals Todos")) || [],
dones: JSON.parse(localStorage.getItem("Daily Goals Dones")) || [],
add: (input) => add(set, input, "daily"),
markAsDone: (item) => markAsDone(set, item, "daily"),
markAsTodo: (item) => markAsTodo(set, item, "daily"),
deleteDones: () => deleteDones(set, "daily")
})

const createCowSlice = () => ({
amount: 21
const todoWeeklySlice = (set, get) => ({
title: "Weekly Goals",
completed: () => completed(get, "weekly"),
todos: JSON.parse(localStorage.getItem("Weekly Goals Todos")) || [],
dones: JSON.parse(localStorage.getItem("Weekly Goals Dones")) || [],
add: (input) => add(set, input, "weekly"),
markAsDone: (item) => markAsDone(set, item, "weekly"),
markAsTodo: (item) => markAsTodo(set, item, "weekly"),
deleteDones: () => deleteDones(set, "weekly")
})

export const Store = create(devtools(set => ({
bears: createBearSlice(set),
cows: createCowSlice()
const todoMonthlySlice = (set, get) => ({
title: "Monthly Goals",
completed: () => completed(get, "monthly"),
todos: JSON.parse(localStorage.getItem("Monthly Goals Todos")) || [],
dones: JSON.parse(localStorage.getItem("Monthly Goals Dones")) || [],
add: (input) => add(set, input, "monthly"),
markAsDone: (item) => markAsDone(set, item, "monthly"),
markAsTodo: (item) => markAsTodo(set, item, "monthly"),
deleteDones: () => deleteDones(set, "monthly")
})

export const Store = create(devtools((set, get) => ({
daily: todoDailySlice(set, get),
weekly: todoWeeklySlice(set, get),
monthly: todoMonthlySlice(set, get)
})))
33 changes: 33 additions & 0 deletions src/store/todo_logic.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
export const add = (set, input, sliceID) => set((state) => ({
[sliceID]: {
...state[sliceID],
todos: [...state[sliceID].todos, { id: Date.now(), content: input }]
}
}), false, 'todo/add')

export const markAsDone = (set, item, sliceID) => set((state) => ({
[sliceID]: {
...state[sliceID],
todos: state[sliceID].todos.filter(i => i.id !== item.id),
dones: [...state[sliceID].dones, item].sort((a, b) => a.id - b.id)
}
}), false, 'todo/markAsDone')

export const markAsTodo = (set, item, sliceID) => set((state) => ({
[sliceID]: {
...state[sliceID],
todos: [...state[sliceID].todos, item].sort((a, b) => a.id - b.id),
dones: state[sliceID].dones.filter(i => i.id !== item.id)
}
}), false, 'todo/markAsTodo')

export const completed = (get, sliceID) => (
`${(Math.floor((get()[sliceID].dones.length / (get()[sliceID].todos.length + get()[sliceID].dones.length))*100)).toString()}%`
)

export const deleteDones = (set, sliceID) => set((state)=>({
[sliceID]: {
...state[sliceID],
dones: []
}
}), false, 'todo/deleteDones')
57 changes: 57 additions & 0 deletions src/todo/Todo.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,60 @@
.Todo {
width: 100%;
border: 1px solid red;
border-radius: 10px;
padding: 10px;
display: flex;
flex-direction: column;
row-gap: 12px;
}

.Todo header {
display: flex;
justify-content: space-between;
align-items: center;
}

.Todo header span span {
font-size: 24px;
font-weight: 700;
}

.Todo header h1 {
font-size: 22px;
}

.Todo ul {
width: 95%;
align-self: flex-end;
font-size: 12px;
}

.Todo ul li {
cursor: pointer;
padding: 5px 0;
}

.Todo ul .dones {
color: rgb(101, 101, 101);
}

.Todo footer {
display: flex;
column-gap: 12px;
}

.Todo footer button {
width: fit-content;
font-size: 14px;
white-space: nowrap;
}

.Todo footer input {
width: 100%;
padding: 5px;
border: 1px solid red;
border-radius: 5px;
outline: none;
color: white;
background-color: black;
}
35 changes: 32 additions & 3 deletions src/todo/Todo.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,38 @@
import { useState, useEffect } from 'react'
import PropTypes from 'prop-types'
import './Todo.css'

export const Todo = () => {
export const Todo = ({ store }) => {
const [input, setInput] = useState("")
const handleInputEnterKey = k => k.key === "Enter" && input.trim() != "" && (store.add(input), setInput(""))

useEffect(() => {
localStorage.setItem(`${store.title} Todos`, JSON.stringify(store.todos))
localStorage.setItem(`${store.title} Dones`, JSON.stringify(store.dones))
}, [store.todos, store.dones, store.title])

return (
<div className='Todo'>
<h1>Todo</h1>
<header>
<div><span className={store.completed() === "NaN%" ? 'hide' : ''}>Completed: <span>{store.completed()}</span></span></div>
<h1>{store.title}</h1>
</header>
<ul>
{store.todos.map(item => (<li key={item.id} onClick={() => store.markAsDone(item)}>{item.content}</li>))}
{store.dones.map(item => (<li key={item.id} className='dones' onClick={() => store.markAsTodo(item)}>{item.content}</li>))}
</ul>
<footer>
<button onClick={() => store.deleteDones()} className={`${store.dones.length === 0 ? 'hide' : ''}`}>Delete All Completed</button>
<input
type="text"
value={input}
placeholder="Type a goal and press Enter"
onChange={(e) => setInput(e.target.value)}
onKeyDown={(k) => handleInputEnterKey(k)}
/>
</footer>
</div>
)
}
}

Todo.propTypes = { store: PropTypes.object }
5 changes: 5 additions & 0 deletions src/todo/Todos.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.Todos {
display: flex;
row-gap: 1%;
overflow-y: auto;
}
15 changes: 15 additions & 0 deletions src/todo/Todos.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Store } from '../store/store.js'
import { Todo } from './Todo.jsx'
import './Todos.css'

export const Todos = () => {
const store = Store()
return (
<div className='Todos'>
<h1>Todo</h1>
<Todo store={store.daily} />
<Todo store={store.weekly} />
<Todo store={store.monthly} />
</div>
)
}
Loading