homeman-deno/islands/TodoList.tsx

131 lines
3.5 KiB
TypeScript
Raw Normal View History

2024-01-11 16:23:09 -06:00
import { Todo, UserWithTodos } from '@homeman/models.ts'
import { JSX } from 'preact'
2024-01-09 23:06:44 -06:00
import { Button } from '@homeman/components/Button.tsx'
import { Avatar } from '@homeman/components/Avatar.tsx'
2024-01-17 21:30:41 -06:00
import {
CheckBadgeSolid,
CheckCircleMiniSolid,
CheckCircleSolid,
CheckMiniSolid,
ChevronDownMiniSolid,
TrashSolid,
} from 'preact-heroicons'
2024-01-09 23:06:44 -06:00
export interface Props {
user: UserWithTodos
2024-01-11 16:23:09 -06:00
onNewButtonClicked: JSX.MouseEventHandler<HTMLButtonElement>
2024-01-09 23:06:44 -06:00
}
export function TodoList(
2024-01-17 15:10:28 -06:00
{ onNewButtonClicked, user: { avatarUrl, name, color, ...user } }: Props,
2024-01-09 23:06:44 -06:00
) {
2024-01-16 16:15:10 -06:00
const doneTodos = user.assignedTodos.filter((t) => t.doneAt != null)
const inProgressTodos = user.assignedTodos.filter((t) => t.doneAt == null)
2024-01-09 23:06:44 -06:00
const todoItem = (
2024-01-16 16:45:51 -06:00
{ id, doneAt, className, description, virtual }:
2024-01-11 18:57:29 -06:00
& Pick<Todo, 'description' | 'id' | 'doneAt'>
& {
className?: string
2024-01-16 16:45:51 -06:00
virtual?: boolean
2024-01-11 18:57:29 -06:00
},
2024-01-09 23:06:44 -06:00
) => (
<li
style={`border-color: #${color}`}
2024-01-16 16:15:10 -06:00
title={doneAt != null ? `Completed at ${doneAt}` : ''}
2024-01-09 23:06:44 -06:00
class={`${className || ''} ${
2024-01-16 16:45:51 -06:00
virtual ? '' : 'border-l-4'
2024-01-16 16:15:10 -06:00
} p-4 text-black cursor-auto dark:text-white rounded drop-shadow-lg bg-white dark:bg-stone-900 flex flex-col gap-2`}
2024-01-09 23:06:44 -06:00
>
<span class='text-xl'>{description}</span>
2024-01-16 16:45:51 -06:00
<footer class='flex gap-2'>
{(virtual || doneAt != null) ? '' : (
2024-01-16 16:15:10 -06:00
<Button
2024-01-17 21:30:41 -06:00
className='bg-emerald-500/50 grow'
2024-01-16 16:15:10 -06:00
onClick={async () => {
await fetch('/api/todo/done', {
2024-01-16 16:45:51 -06:00
method: 'PUT',
2024-01-16 16:15:10 -06:00
body: JSON.stringify({ id }),
})
}}
>
2024-01-17 21:30:41 -06:00
<CheckMiniSolid class='w-5 h-5' /> Done
2024-01-16 16:15:10 -06:00
</Button>
2024-01-16 16:45:51 -06:00
)}
{(!virtual && doneAt != null)
? (
<Button
className='grow'
onClick={async () => {
await fetch('/api/todo/done', {
method: 'DELETE',
body: JSON.stringify({ id }),
})
}}
>
Not Done
</Button>
)
: ''}
{virtual ? '' : (
<Button
className='hover:bg-rose-500'
onClick={async () => {
if (confirm(`Are you sure you want to delete '${description}'`)) {
await fetch('/api/todo', {
method: 'DELETE',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ id }),
})
}
}}
>
<TrashSolid className='w-6 h-6' />
</Button>
)}
</footer>
2024-01-09 23:06:44 -06:00
</li>
)
return (
<div class='p-2 w-1/4 min-w-[15rem] relative flex flex-col grow-0'>
<Avatar
className='mb-2'
src={avatarUrl != null ? avatarUrl : 'https://placehold.co/512x512'}
title={`${name}'s avatar`}
/>
<span style={`color: #${color};`} class='font-semibold text-center'>
{name}
</span>
<button
class='mt-4 mb-4 text-left w-full px-2 py-1 rounded-lg border-[1px] text-stone-500 border-stone-500 opacity-50 hover:opacity-100'
2024-01-11 16:23:09 -06:00
onClick={onNewButtonClicked}
2024-01-09 23:06:44 -06:00
>
+ New
</button>
<ul class='flex flex-col gap-y-4'>
2024-01-16 16:15:10 -06:00
{inProgressTodos.length < 1
2024-01-09 23:06:44 -06:00
? todoItem({
2024-01-16 16:15:10 -06:00
id: '',
doneAt: null,
2024-01-09 23:06:44 -06:00
description: 'All clear! 🎉',
className: 'text-center',
2024-01-16 16:45:51 -06:00
virtual: true,
2024-01-09 23:06:44 -06:00
})
2024-01-16 16:15:10 -06:00
: inProgressTodos.map(todoItem)}
2024-01-09 23:06:44 -06:00
</ul>
2024-01-16 16:15:10 -06:00
{doneTodos.length > 0
? (
2024-01-17 11:55:46 -06:00
<details class='text-gray-500 [&>summary>svg]:open:-rotate-180'>
2024-01-17 11:52:37 -06:00
<summary class='cursor-pointer marker:content-[""] flex justify-between hover:bg-gray-500/20 p-4 rounded mt-4'>
<span>+{doneTodos.length} completed todos</span>
<ChevronDownMiniSolid className='w-6 h-6' />
</summary>
<ul class='flex flex-col gap-y-4 mt-2'>
{doneTodos.map(todoItem)}
</ul>
</details>
2024-01-16 16:15:10 -06:00
)
: ''}
2024-01-09 23:06:44 -06:00
</div>
)
}