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/done #5

Merged
merged 33 commits into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
9c0aecb
Create layout of Done.jsx component
danifromecuador Aug 20, 2024
6dd0c20
Create general styles for buttons and input fields
danifromecuador Aug 20, 2024
aedcfad
Use general styles on Done component
danifromecuador Aug 20, 2024
1b7a83a
Create more general style items
danifromecuador Aug 20, 2024
ed74ea5
Use general styles for sub component and counter stats
danifromecuador Aug 20, 2024
feb6cab
Remove repeated styles that are already included in App.css
danifromecuador Aug 20, 2024
e2644ee
Improve mobile layout
danifromecuador Aug 20, 2024
64ed858
Apply the same general style to Doing sub component
danifromecuador Aug 20, 2024
497e00d
Improve layout of Done.jsx component
danifromecuador Aug 20, 2024
9f24d4a
Apply the general styles to Done component
danifromecuador Aug 20, 2024
8e243ae
Fix Stylelint errors
danifromecuador Aug 20, 2024
8221775
Delete Todos.css reference as that file is not neccessary
danifromecuador Aug 20, 2024
b298308
Change font-size of all <li> elements to rem instead of px
danifromecuador Aug 20, 2024
69265e4
Avoid text wrapping on small screens
danifromecuador Aug 20, 2024
cc7e924
Create tasks slice on the Store
danifromecuador Aug 20, 2024
193e91e
Create input function and Show completed tasks from Store data
danifromecuador Aug 20, 2024
e895f82
Refine input function to avoid the user to enter null values
danifromecuador Aug 20, 2024
965c7ce
Save completed tasks data on local storage
danifromecuador Aug 20, 2024
cdbba86
Create the logic for tasks slice on a separated file
danifromecuador Aug 20, 2024
c3bb2df
Remove extra parenthesis
danifromecuador Aug 20, 2024
e2174d1
Fix fetching wrong data from Store
danifromecuador Aug 20, 2024
6ae9c3d
Create tasks slice on the Store
danifromecuador Aug 21, 2024
9f78652
Hard coded worked hours for last month and last week
danifromecuador Aug 21, 2024
0749ffb
Show or render worked hours counter from the Store on Done component
danifromecuador Aug 21, 2024
75204ca
Calculate worked hours counter for last 7 and 30 days
danifromecuador Aug 21, 2024
42e1b5a
Avoid long lines of code
danifromecuador Aug 22, 2024
52a738c
Save on local storage workedHoursHistory data
danifromecuador Aug 22, 2024
475dbe4
Fix class issues when display setted as flex but also as hide
danifromecuador Aug 22, 2024
8c62f23
Show a modal dialog to confirm the delete all completed tasks action
danifromecuador Aug 22, 2024
11a30b0
Fix Stylelint errors
danifromecuador Aug 23, 2024
065a048
Change array type from stack to queue for deleteAllCompletedTasks
danifromecuador Aug 27, 2024
fec1fa8
Fix typo error
danifromecuador Aug 27, 2024
8eef5d6
Merge branch 'develop' into feat/done
danifromecuador Aug 27, 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
59 changes: 54 additions & 5 deletions src/App.css
Original file line number Diff line number Diff line change
@@ -1,11 +1,56 @@
button {
padding: 0 2%;
font-size: 2vw;
border: 1px solid rgb(79, 79, 79);
border-radius: 5px;
padding: 1%;
white-space: nowrap;
cursor: pointer;
}

.bigBtn {
font-size: 2vw;
}

.midBtn {
font-size: 1.2vw;
}

.input {
width: 100%;
padding: 1%;
border: 1px solid red;
border-radius: 5px;
outline: none;
color: white;
background-color: black;
}

.sub-container {
width: 100%;
border: 1px solid red;
border-radius: 10px;
padding: 10px;
display: flex;
flex-direction: column;
row-gap: 12px;
}

.counter-stats {
font-size: 24px;
font-weight: 700;
}

.ul {
width: 95%;
align-self: flex-end;
}

.li {
padding: 5px 0;
font-size: 0.8rem;
}

.hide {
display: none;
display: none !important;
}

li {
Expand All @@ -23,12 +68,15 @@ li {
.Todos,
.Doing,
.Done {
width: 33%;
width: 100%;
border: 1px solid red;
border-radius: 15px;
border-radius: 20px;
padding: 5px;
display: flex;
flex-direction: column;
row-gap: 1%;
align-items: center;
overflow-y: auto;
}

@media (width <= 720px) {
Expand All @@ -41,6 +89,7 @@ li {
.Doing,
.Done {
width: 100%;
overflow-y: visible;
}

.Todos {
Expand Down
22 changes: 6 additions & 16 deletions src/doing/Doing.css
Original file line number Diff line number Diff line change
@@ -1,19 +1,9 @@
.Doing {
padding: 5px;
row-gap: 100px;
}

.pomodoro {
width: 100%;
padding: 5px;
display: flex;
flex-direction: column;
justify-content: center;
.Doing .pomodoro {
align-items: center;
row-gap: 50px;
}

.clock {
.Doing .clock {
width: fit-content;
border: 1px solid red;
border-radius: 20px;
Expand All @@ -23,24 +13,24 @@
font-family: 'CustomFont', monospace;
}

.controls {
.Doing .controls {
width: 100%;
justify-content: center;
display: flex;
column-gap: 10px;
}

.motivational {
.Doing .motivational {
cursor: pointer;
display: flex;
flex-direction: column;
row-gap: 10px;
}

.motivational p:first-of-type {
.Doing .motivational p:first-of-type {
font-style: italic;
}

.motivational p:last-of-type {
.Doing .motivational p:last-of-type {
font-size: 0.7rem;
}
8 changes: 4 additions & 4 deletions src/doing/Doing.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export const Doing = () => {
return (
<div className='Doing'>
<h1>Doing</h1>
<div className="pomodoro">
<div className="pomodoro sub-container">
<div className="clock">
<Countdown
ref={countdownRef}
Expand All @@ -81,9 +81,9 @@ export const Doing = () => {
/>
</div>
<div className="controls">
<button className={`${viewStartBtn} start`} onClick={handleStartClick}>{textStartBtn}</button>
<button className={`${viewPauseBtn} pause`} onClick={handlePauseClick}>PAUSE</button>
<button className={`${viewResetBtn} reset`} onClick={() => handleResetClick(true)}>RESET</button>
<button className={`${viewStartBtn} start bigBtn`} onClick={handleStartClick}>{textStartBtn}</button>
<button className={`${viewPauseBtn} pause bigBtn`} onClick={handlePauseClick}>PAUSE</button>
<button className={`${viewResetBtn} reset bigBtn`} onClick={() => handleResetClick(true)}>RESET</button>
</div>
<div className="motivational" onClick={catchNewQuote}>
<p>{quote}</p>
Expand Down
50 changes: 48 additions & 2 deletions src/done/Done.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,49 @@
.Done {
color: white;
.Done h2 {
text-align: right;
}

.Done .worked-hours .this {
width: 100%;
display: flex;
justify-content: space-evenly;
}

.Done .worked-hours .this .this-month,
.Done .worked-hours .this .this-week,
.Done .worked-hours .this .this-day {
display: flex;
flex-direction: column;
align-items: center;
}

.Done .worked-hours .this .this-month span:last-of-type,
.Done .worked-hours .this .this-week span:last-of-type,
.Done .worked-hours .this .this-day span:last-of-type {
white-space: nowrap;
font-size: 0.8rem;
}

.Done .completed-tasks.sub-container ul li.dones {
color: gray;
}

.Done .completed-tasks.sub-container .modal {
display: flex;
flex-direction: column;
row-gap: 10px;
}

.Done .completed-tasks.sub-container .modal p {
color: red;
}

.Done .completed-tasks.sub-container .options {
display: flex;
justify-content: space-around;
}

.Done .completed-tasks.sub-container footer {
width: 100%;
display: flex;
column-gap: 12px;
}
42 changes: 42 additions & 0 deletions src/done/Done.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,51 @@
import { useState, useEffect } from 'react'
import { Store } from '../store/store'
import './Done.css'

export const Done = () => {
const store = Store()
const [input, setInput] = useState("")
const [showModal, setShowModal] = useState("hide")
const [showFooter, setShowFooter] = useState("")
const handleInputEnterKey = k => k.key === "Enter" && input.trim() != "" && (store.tasks.add(input), setInput(""))
useEffect(() => localStorage.setItem("Completed Tasks", JSON.stringify(store.tasks.completed)), [store.tasks.completed])
useEffect(() => localStorage.setItem("Worked Hours History", JSON.stringify(store.tasks.workedHoursHistory)), [store.tasks.workedHoursHistory])

return (
<div className='Done'>
<h1>Done</h1>
<div className="worked-hours sub-container">
<h2>Worked Hours</h2>
<div className="this">
<div className="this-month"><span className='counter-stats'>{store.tasks.workedHours().month}</span><span>Last Month</span></div>
<div className="this-week"><span className='counter-stats'>{store.tasks.workedHours().week}</span><span>Last Week</span></div>
<div className="this-day"><span className='counter-stats'>{store.tasks.workedHours().day}</span><span>Today</span></div>
</div>
</div>
<div className="completed-tasks sub-container">
<h2>Completed Tasks</h2>
<ul className='ul'>
{store.tasks.completed.map(item => (<li key={item.id} className='li dones'>{item.content}</li>))}
</ul>
<div className={`${showModal} modal`}>
<p>Deleting all completed tasks will log today&apos;s work and start a new day. Are you sure?</p>
<div className="options">
<button className='midBtn' onClick={() => (setShowModal("hide"), setShowFooter(""))}>Cancel</button>
<button className='midBtn' onClick={() => (store.tasks.deleteCompleted(), setShowModal("hide"), setShowFooter(""))}>Yes, I want to start a new day</button>
</div>
</div>
<footer className={showFooter}>
<button className={`${store.tasks.completed.length === 0 ? 'hide' : 'midBtn'}`} onClick={() => (setShowFooter("hide"), setShowModal(""))}>Delete All</button>
<input
type="text"
className='input'
value={input}
placeholder='Type a completed task and press Enter'
onChange={e => setInput(e.target.value)}
onKeyDown={k => handleInputEnterKey(k)}
/>
</footer>
</div>
</div>
)
}
36 changes: 23 additions & 13 deletions src/store/store.js
Original file line number Diff line number Diff line change
@@ -1,42 +1,52 @@
import { create } from "zustand"
import { devtools } from "zustand/middleware"
import { add, completed, markAsDone, markAsTodo, deleteDones } from "./todo_logic.js"
import { addCompletedTask, deleteAllCompletedTasks, workedHours } from './tasks_logic.js'

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"),
completed: () => completed(get, "daily"),
add: input => add(set, input, "daily"),
markAsDone: item => markAsDone(set, item, "daily"),
markAsTodo: item => markAsTodo(set, item, "daily"),
deleteDones: () => deleteDones(set, "daily")
})

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"),
completed: () => completed(get, "weekly"),
add: input => add(set, input, "weekly"),
markAsDone: item => markAsDone(set, item, "weekly"),
markAsTodo: item => markAsTodo(set, item, "weekly"),
deleteDones: () => deleteDones(set, "weekly")
})

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"),
completed: () => completed(get, "monthly"),
add: input => add(set, input, "monthly"),
markAsDone: item => markAsDone(set, item, "monthly"),
markAsTodo: item => markAsTodo(set, item, "monthly"),
deleteDones: () => deleteDones(set, "monthly")
})

const tasksSlice = (set, get) => ({
completed: JSON.parse(localStorage.getItem("Completed Tasks")) || [],
workedHoursHistory: JSON.parse(localStorage.getItem("Worked Hours History")) || [],
add: input => addCompletedTask(set, input),
deleteCompleted: () => deleteAllCompletedTasks(set, get),
workedHours: () => workedHours(get),
})

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

export const deleteAllCompletedTasks = (set, get) => set(state => {
const workedHoursHistoryArray = [get().tasks.completed.length * 15 / 60, ...state.tasks.workedHoursHistory]
workedHoursHistoryArray.length > 30 && workedHoursHistoryArray.pop()
return ({
tasks: {
...state.tasks,
workedHoursHistory: workedHoursHistoryArray,
completed: []
}
})
}, false, 'tasks/deleteAllCompleted')

export const workedHours = get => {
const day = get().tasks.completed.length * 15 / 60
const week = get().tasks.workedHoursHistory.slice(0, 7).reduce((a, b) => a + b, 0)
const month = get().tasks.workedHoursHistory.reduce((a, b) => a + b, 0)
return ({ "day": day, "week": week, "month": month })
}
Loading
Loading