Skip to content

Adding in progress state to the todo app #1007

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

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 4 additions & 1 deletion src/App/NewTodoInput/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,14 @@ const NewTodoTextInput: React.FC = () => {
const todo: Todo = {
bodyText: textInput.current.value,
completed: false,
inProgress: false,
id: UUID(),
}

// add new TODO to entire TodoList
setAppState({ todoList: [todo, ...appState.todoList] })
setAppState({
todoList: [todo, ...appState.todoList],
})

// reset text input UI value
textInput.current.value = ''
Expand Down
39 changes: 35 additions & 4 deletions src/App/TodoList/Item/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ const Item: React.FC<Props> = ({ todo }) => {
// search clicked item by id...
if (t.id === id) {
// change complated status only clicked item
return { ...t, completed: !t.completed }
return { ...t, completed: !t.completed, inProgress: false }
// return other item without any changes
} else {
return t
Expand All @@ -80,7 +80,19 @@ const Item: React.FC<Props> = ({ todo }) => {
setAppState({ todoList: removed })
}

const handleTodoTextEdit = (e: React.ChangeEvent<HTMLInputElement>, onEdit: Todo['id']): void => { /* eslint-disable-line prettier/prettier */
const setInprogress = (id: Todo['id']) => {
let temp: TodoListType = appState.todoList.map((t) =>
t.inProgress ? { ...t, inProgress: false } : t
)
temp = temp.map((t) => (t.id === id ? { ...t, inProgress: true } : t))
setAppState({ todoList: temp })
}

const handleTodoTextEdit = (
e: React.ChangeEvent<HTMLInputElement>,
onEdit: Todo['id']
): void => {
/* eslint-disable-line prettier/prettier */
const edited = appState.todoList.map((t: Todo): Todo => {
if (t.id === onEdit) {
return { ...t, bodyText: e.target.value }
Expand Down Expand Up @@ -112,13 +124,28 @@ const Item: React.FC<Props> = ({ todo }) => {
/>

{/* eslint-disable jsx-a11y/no-noninteractive-element-interactions, jsx-a11y/click-events-have-key-events */}

<label
onClick={onClick}
data-cy="todo-body-text"
data-testid="todo-body-text"
>
{todo.bodyText}
</label>
{!todo.completed && todo.inProgress && (
<span className="inProgressActiveBadeg">In Progress</span>
)}
{!todo.completed && !todo.inProgress && (
<span
className="inProgressBadeg"
onClick={() => setInprogress(todo.id)}
>
Backlog
</span>
)}
{todo.completed && !todo.inProgress && (
<span className="completedBadeg">Completed</span>
)}
{/* eslint-enable jsx-a11y/no-noninteractive-element-interactions, jsx-a11y/click-events-have-key-events */}
<button
className="destroy"
Expand All @@ -132,8 +159,12 @@ const Item: React.FC<Props> = ({ todo }) => {
onBlur={(e: React.FocusEvent<HTMLInputElement>) => onBlurEdit(e)}
className="edit"
value={todo.bodyText}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => handleTodoTextEdit(e, todo.id)} /* eslint-disable-line prettier/prettier */
onKeyDown={(e: React.KeyboardEvent<HTMLInputElement>) => submitEditText(e)} /* eslint-disable-line prettier/prettier */
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
handleTodoTextEdit(e, todo.id)
} /* eslint-disable-line prettier/prettier */
onKeyDown={(e: React.KeyboardEvent<HTMLInputElement>) =>
submitEditText(e)
} /* eslint-disable-line prettier/prettier */
data-cy="todo-edit-input"
data-testid="todo-edit-input"
/>
Expand Down
39 changes: 39 additions & 0 deletions src/App/TodoList/Item/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ export const Layout = styled.div`
margin: 0 0 0 43px;
}

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

.editing .view {
display: none;
}
Expand Down Expand Up @@ -111,4 +117,37 @@ export const Layout = styled.div`
.editing:last-child {
margin-bottom: -1px;
}

.inProgressActiveBadeg {
padding: 3px 5px;
border-radius: 3px;
font-size: 0.5em;
background-color: #f39c12;
color: white;
font-weight: 600;
margin-right: 70px;
cursor: pointer;
}

.inProgressBadeg {
padding: 3px 5px;
border-radius: 3px;
font-size: 0.5em;
background-color: #bdc3c7;
color: white;
font-weight: 600;
margin-right: 70px;
cursor: pointer;
}

.completedBadeg {
padding: 3px 5px;
border-radius: 3px;
font-size: 0.5em;
background-color: #2ecc71;
color: white;
font-weight: 600;
margin-right: 70px;
cursor: pointer;
}
`
17 changes: 12 additions & 5 deletions src/App/TodoList/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ReactElement } from 'react'
import { ReactElement, useEffect } from 'react'
import React from 'react'
import { useLocation } from 'react-router-dom'
import { useRecoilState } from 'recoil'
Expand All @@ -13,9 +13,14 @@ const TodoList: React.FC = () => {
const { pathname } = useLocation()
const [appState, setAppState] = useRecoilState<AppState>(recoilState)

function toggleAllCheckbox(e: React.ChangeEvent<HTMLInputElement>): void { /* eslint-disable-line prettier/prettier */
function toggleAllCheckbox(e: React.ChangeEvent<HTMLInputElement>): void {
/* eslint-disable-line prettier/prettier */
// reverse all todo.completed: boolean flag
setAppState({ todoList: appState.todoList.map((t: Todo): Todo => ({ ...t, completed: e.target.checked })) }) /* eslint-disable-line prettier/prettier */
setAppState({
todoList: appState.todoList.map(
(t: Todo): Todo => ({ ...t, completed: e.target.checked })
),
}) /* eslint-disable-line prettier/prettier */
}

return (
Expand All @@ -36,8 +41,10 @@ const TodoList: React.FC = () => {
switch (pathname) {
case '/':
return true
case '/active':
return t.completed === false
case '/backlog':
return t.completed === false && t.inProgress === false
case '/in-progress':
return t.inProgress === true
case '/completed':
return t.completed === true
default:
Expand Down
15 changes: 12 additions & 3 deletions src/App/UnderBar/FilterLink/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,19 @@ const FilterLink: React.FC = () => {
<li>
<Link
data-cy="active-filter"
className={pathname === '/active' ? 'selected' : ''}
to="/active"
className={pathname === '/backlog' ? 'selected' : ''}
to="/backlog"
>
Active
Backlog
</Link>
</li>
<li>
<Link
data-cy="active-filter"
className={pathname === '/in-progress' ? 'selected' : ''}
to="/in-progress"
>
In progress
</Link>
</li>
<li>
Expand Down
8 changes: 6 additions & 2 deletions src/App/UnderBar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@ import { Layout } from './style'

const UnderBar: React.FC = () => {
const [appState, setAppState] = useRecoilState<AppState>(recoilState)
const completed: number = appState.todoList.filter(t => t.completed === true).length /* eslint-disable-line prettier/prettier */
const backlog: number = appState.todoList.filter(t => t.completed === false).length /* eslint-disable-line prettier/prettier */
const completed: number = appState.todoList.filter(
(t) => t.completed
).length /* eslint-disable-line prettier/prettier */
const backlog: number = appState.todoList.filter(
(t) => t.completed === false
).length /* eslint-disable-line prettier/prettier */

function clearCompleted(): void {
setAppState({
Expand Down
3 changes: 2 additions & 1 deletion src/App/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ const App: React.FC = () => (
<RecoilRoot>
<Routes>
<Route path="/" element={<TodoMVC />} />
<Route path="/active" element={<TodoMVC />} />
<Route path="/backlog" element={<TodoMVC />} />
<Route path="/completed" element={<TodoMVC />} />
<Route path="/in-progress" element={<TodoMVC />} />
<Route path="*" element={<NotFound />} />
</Routes>
</RecoilRoot>
Expand Down
1 change: 1 addition & 0 deletions src/dataStructure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export interface Todo {
id: string
bodyText: string
completed: boolean
inProgress: boolean
}

export type TodoListType = Todo[]
Expand Down