mirror of
https://github.com/kou029w/_.git
synced 2025-01-31 06:18:07 +00:00
101 lines
2.9 KiB
TypeScript
101 lines
2.9 KiB
TypeScript
|
import Head from 'next/head'
|
||
|
import { useCallback, useState, FormEvent, ChangeEvent } from 'react'
|
||
|
import useAspidaSWR from '@aspida/swr'
|
||
|
import styles from '~/styles/Home.module.css'
|
||
|
import { apiClient } from '~/utils/apiClient'
|
||
|
import { Task } from '$/types'
|
||
|
import UserBanner from '~/components/UserBanner'
|
||
|
|
||
|
const Home = () => {
|
||
|
const { data: tasks, error, mutate: setTasks } = useAspidaSWR(apiClient.tasks)
|
||
|
const [label, setLabel] = useState('')
|
||
|
const inputLavel = useCallback(
|
||
|
(e: ChangeEvent<HTMLInputElement>) => setLabel(e.target.value),
|
||
|
[]
|
||
|
)
|
||
|
|
||
|
const createTask = useCallback(
|
||
|
async (e: FormEvent) => {
|
||
|
e.preventDefault()
|
||
|
if (!label) return
|
||
|
|
||
|
await apiClient.tasks.post({ body: { label } })
|
||
|
setLabel('')
|
||
|
setTasks(await apiClient.tasks.$get())
|
||
|
},
|
||
|
[label]
|
||
|
)
|
||
|
|
||
|
const toggleDone = useCallback(async (task: Task) => {
|
||
|
await apiClient.tasks._taskId(task.id).patch({ body: { done: !task.done } })
|
||
|
setTasks(await apiClient.tasks.$get())
|
||
|
}, [])
|
||
|
|
||
|
const deleteTask = useCallback(async (task: Task) => {
|
||
|
await apiClient.tasks._taskId(task.id).delete()
|
||
|
setTasks(await apiClient.tasks.$get())
|
||
|
}, [])
|
||
|
|
||
|
if (error) return <div>failed to load</div>
|
||
|
if (!tasks) return <div>loading...</div>
|
||
|
|
||
|
return (
|
||
|
<div className={styles.container}>
|
||
|
<Head>
|
||
|
<title>frourio-todo-app</title>
|
||
|
<link rel="icon" href="/favicon.ico" />
|
||
|
</Head>
|
||
|
|
||
|
<main className={styles.main}>
|
||
|
<UserBanner />
|
||
|
|
||
|
<h1 className={styles.title}>
|
||
|
Welcome to <a href="https://nextjs.org">Next.js!</a>
|
||
|
</h1>
|
||
|
|
||
|
<p className={styles.description}>frourio-todo-app</p>
|
||
|
|
||
|
<div>
|
||
|
<form style={{ textAlign: 'center' }} onSubmit={createTask}>
|
||
|
<input value={label} type="text" onChange={inputLavel} />
|
||
|
<input type="submit" value="ADD" />
|
||
|
</form>
|
||
|
<ul className={styles.tasks}>
|
||
|
{tasks.map((task) => (
|
||
|
<li key={task.id}>
|
||
|
<label>
|
||
|
<input
|
||
|
type="checkbox"
|
||
|
checked={task.done}
|
||
|
onChange={() => toggleDone(task)}
|
||
|
/>
|
||
|
<span>{task.label}</span>
|
||
|
</label>
|
||
|
<input
|
||
|
type="button"
|
||
|
value="DELETE"
|
||
|
style={{ float: 'right' }}
|
||
|
onClick={() => deleteTask(task)}
|
||
|
/>
|
||
|
</li>
|
||
|
))}
|
||
|
</ul>
|
||
|
</div>
|
||
|
</main>
|
||
|
|
||
|
<footer className={styles.footer}>
|
||
|
<a
|
||
|
href="https://vercel.com?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
|
||
|
target="_blank"
|
||
|
rel="noopener noreferrer"
|
||
|
>
|
||
|
Powered by{' '}
|
||
|
<img src="/vercel.svg" alt="Vercel Logo" className={styles.logo} />
|
||
|
</a>
|
||
|
</footer>
|
||
|
</div>
|
||
|
)
|
||
|
}
|
||
|
|
||
|
export default Home
|