Skip to content

Commit

Permalink
Extract Todo.tsx from index.tsx in order to move index.test.tsx to co…
Browse files Browse the repository at this point in the history
  • Loading branch information
hisomura committed Jul 19, 2020
1 parent 9cf5513 commit fee18e7
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 131 deletions.
6 changes: 3 additions & 3 deletions pages/index.test.tsx → components/Todo.test.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import React from 'react'
import { render, screen, cleanup, fireEvent } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import Home from './index'
import Todo from './Todo'

afterEach(cleanup)

test('Add and close a task.', async () => {
render(<Home />)
render(<Todo />)

// Add a task.
expect(screen.queryByText(/Add Test/)).toBeNull()
Expand All @@ -23,7 +23,7 @@ test('Add and close a task.', async () => {
})

test('Add and close a task by drag and drop.', async () => {
render(<Home />)
render(<Todo />)

// Add a task.
expect(screen.queryByText(/Add Test/)).toBeNull()
Expand Down
130 changes: 130 additions & 0 deletions components/Todo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import React, { ChangeEventHandler, DragEventHandler, KeyboardEventHandler, MouseEvent, useState } from 'react'
import cn from 'classnames'
import { MdClearAll } from 'react-icons/md'
import { Task } from '../lib/task'
import { moved } from '../lib/array'
import ToggleExpandIcon from '../components/ToggleExpandIcon'
import OpenTaskItem from '../components/OpenTaskItem'
import ClosedTaskItem from '../components/ClosedTaskItem'

const preventDefault: DragEventHandler = (event) => event.preventDefault()

export default function Todo() {
const [tasks, setTasks] = useState<Task[]>([])
const [formText, setFormText] = useState('')
const [foldingClosedTasks, setFoldingClosedTasks] = useState(true)
const [draggedTaskNextIndex, setDraggedTaskNextIndex] = useState<number | null>(null)
const [draggedTaskId, setDraggedTaskId] = useState<number | null>(null)

const onChange: ChangeEventHandler<HTMLInputElement> = (event) => {
// https://developer.mozilla.org/ja/docs/Web/API/Event/currentTarget
setFormText(event.currentTarget.value)
}

const onKeyDown: KeyboardEventHandler<HTMLInputElement> = (event) => {
// https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode
// if (event.keyCode === 229) return
if (event.key !== 'Enter') return
if (formText === '') return
event.currentTarget.value = ''
setTasks([...tasks, Task.create(formText)])
setFormText('')
}

const closeTask = (taskId: number, closed = true) => {
const newTasks = tasks.map((task) => {
if (task.id !== taskId) return task
return { ...task, closed: closed }
})
setTasks(newTasks)
}

const toggleTask = (event: MouseEvent<HTMLInputElement>, target: Task) => {
const newTasks = tasks.map((task) => {
if (task.id !== target.id) return task
return { ...task, closed: event.currentTarget.checked }
})
setTasks(newTasks)
}

const clearTask = (_event: MouseEvent<HTMLElement>, target: Task) => {
setTasks(tasks.filter((task) => task.id !== target.id))
}

const moveTask = (taskId: number, targetIndex: number) => {
const taskIndex = tasks.findIndex((t) => t.id === taskId)
const result = moved(tasks, taskIndex, targetIndex)
console.log(result)
setTasks(result)
setDraggedTaskNextIndex(null)
setDraggedTaskId(null)
}

return (
<div className="max-w-xl mx-auto py-8">
<div className="shadow-xl rounded px-4 pb-4">
<div className="py-4">
<h1>Todo</h1>
</div>
<div
data-testid="open-task-area"
onDragOver={preventDefault}
onDrop={(e) => {
e.stopPropagation()
e.preventDefault()
if (draggedTaskId !== null && draggedTaskNextIndex !== null) moveTask(draggedTaskId, draggedTaskNextIndex)
}}
>
<ul>
<li className="py-2">
+ <input className="focus:outline-none ml-1" onKeyDown={onKeyDown} onChange={onChange} type="text" />
</li>
{tasks
.filter((task) => !task.closed)
.map((task, index) => (
<OpenTaskItem
key={task.id}
task={task}
index={index}
toggleTask={toggleTask}
isNext={index === draggedTaskNextIndex}
setDraggedTaskNextIndex={setDraggedTaskNextIndex}
setDraggedTaskId={setDraggedTaskId}
/>
))}
</ul>
</div>

<div
data-testid="closed-task-area"
onDragOver={(e) => e.preventDefault()}
onDrop={(e) => {
e.stopPropagation() // TODO why it's necessary
e.preventDefault() // TODO Remove
closeTask(draggedTaskId!)
setDraggedTaskId(null)
setDraggedTaskNextIndex(null)
}}
>
<div className="mt-2 py-1 flex justify-between">
<h2>closed</h2>
<div className="ml-auto mr-2" onClick={() => setTasks(tasks.filter((item) => !item.closed))}>
<MdClearAll />
</div>
<ToggleExpandIcon
expanded={foldingClosedTasks}
onClick={() => setFoldingClosedTasks(!foldingClosedTasks)}
/>
</div>
<ul className={cn({ 'divide-y': true, hidden: foldingClosedTasks })}>
{tasks
.filter((task) => task.closed)
.map((task) => (
<ClosedTaskItem key={task.id} task={task} toggleTask={toggleTask} clearTask={clearTask} />
))}
</ul>
</div>
</div>
</div>
)
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"dev": "next dev",
"build": "next build",
"start": "next start",
"test": "jest --maxWorkers=1"
"test": "jest --maxWorkers=1"
},
"dependencies": {
"classnames": "^2.2.6",
Expand Down
130 changes: 3 additions & 127 deletions pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,130 +1,6 @@
import React, { ChangeEventHandler, DragEventHandler, KeyboardEventHandler, MouseEvent, useState } from 'react'
import cn from 'classnames'
import { MdClearAll } from 'react-icons/md'
import { Task } from '../lib/task'
import { moved } from '../lib/array'
import ToggleExpandIcon from '../components/ToggleExpandIcon'
import OpenTaskItem from '../components/OpenTaskItem'
import ClosedTaskItem from '../components/ClosedTaskItem'

const preventDefault: DragEventHandler = (event) => event.preventDefault()
import React from 'react'
import Todo from '../components/Todo'

export default function Home() {
const [tasks, setTasks] = useState<Task[]>([])
const [formText, setFormText] = useState('')
const [foldingClosedTasks, setFoldingClosedTasks] = useState(true)
const [draggedTaskNextIndex, setDraggedTaskNextIndex] = useState<number | null>(null)
const [draggedTaskId, setDraggedTaskId] = useState<number | null>(null)

const onChange: ChangeEventHandler<HTMLInputElement> = (event) => {
// https://developer.mozilla.org/ja/docs/Web/API/Event/currentTarget
setFormText(event.currentTarget.value)
}

const onKeyDown: KeyboardEventHandler<HTMLInputElement> = (event) => {
// https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode
// if (event.keyCode === 229) return
if (event.key !== 'Enter') return
if (formText === '') return
event.currentTarget.value = ''
setTasks([...tasks, Task.create(formText)])
setFormText('')
}

const closeTask = (taskId: number, closed = true) => {
const newTasks = tasks.map((task) => {
if (task.id !== taskId) return task
return { ...task, closed: closed }
})
setTasks(newTasks)
}

const toggleTask = (event: MouseEvent<HTMLInputElement>, target: Task) => {
const newTasks = tasks.map((task) => {
if (task.id !== target.id) return task
return { ...task, closed: event.currentTarget.checked }
})
setTasks(newTasks)
}

const clearTask = (_event: MouseEvent<HTMLElement>, target: Task) => {
setTasks(tasks.filter((task) => task.id !== target.id))
}

const moveTask = (taskId: number, targetIndex: number) => {
const taskIndex = tasks.findIndex((t) => t.id === taskId)
const result = moved(tasks, taskIndex, targetIndex)
console.log(result)
setTasks(result)
setDraggedTaskNextIndex(null)
setDraggedTaskId(null)
}

return (
<div className="max-w-xl mx-auto py-8">
<div className="shadow-xl rounded px-4 pb-4">
<div className="py-4">
<h1>Todo</h1>
</div>
<div
data-testid="open-task-area"
onDragOver={preventDefault}
onDrop={(e) => {
e.stopPropagation()
e.preventDefault()
if (draggedTaskId !== null && draggedTaskNextIndex !== null) moveTask(draggedTaskId, draggedTaskNextIndex)
}}
>
<ul>
<li className="py-2">
+ <input className="focus:outline-none ml-1" onKeyDown={onKeyDown} onChange={onChange} type="text" />
</li>
{tasks
.filter((task) => !task.closed)
.map((task, index) => (
<OpenTaskItem
key={task.id}
task={task}
index={index}
toggleTask={toggleTask}
isNext={index === draggedTaskNextIndex}
setDraggedTaskNextIndex={setDraggedTaskNextIndex}
setDraggedTaskId={setDraggedTaskId}
/>
))}
</ul>
</div>

<div
data-testid="closed-task-area"
onDragOver={(e) => e.preventDefault()} // TODO why it's necessary
onDrop={(e) => {
e.stopPropagation() // TODO why it's necessary
e.preventDefault() // TODO Remove
closeTask(draggedTaskId!)
setDraggedTaskId(null)
setDraggedTaskNextIndex(null)
}}
>
<div className="mt-2 py-1 flex justify-between">
<h2>closed</h2>
<div className="ml-auto mr-2" onClick={() => setTasks(tasks.filter((item) => !item.closed))}>
<MdClearAll />
</div>
<ToggleExpandIcon
expanded={foldingClosedTasks}
onClick={() => setFoldingClosedTasks(!foldingClosedTasks)}
/>
</div>
<ul className={cn({ 'divide-y': true, hidden: foldingClosedTasks })}>
{tasks
.filter((task) => task.closed)
.map((task) => (
<ClosedTaskItem key={task.id} task={task} toggleTask={toggleTask} clearTask={clearTask} />
))}
</ul>
</div>
</div>
</div>
)
return <Todo />
}

1 comment on commit fee18e7

@vercel
Copy link

@vercel vercel bot commented on fee18e7 Jul 19, 2020

Choose a reason for hiding this comment

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

Please sign in to comment.