homeman-deno/islands/TodoList.tsx

140 lines
3.6 KiB
TypeScript
Raw Normal View History

2024-01-09 23:06:44 -06:00
import { Todo, User, UserWithTodos } from '@homeman/models.ts'
import { Button } from '@homeman/components/Button.tsx'
import { Dialog } from '@homeman/components/Dialog.tsx'
import { Avatar } from '@homeman/components/Avatar.tsx'
import { Signal, useSignal } from '@preact/signals'
import { Input } from '@homeman/components/Input.tsx'
import { Label } from '@homeman/components/Label.tsx'
export interface Props {
user: UserWithTodos
users: Record<string, User>
}
export function TodoList(
{ users, user: { id, avatarUrl, assignedTodos, name, color } }: Props,
) {
const todoAssignUserId: Signal<string | null> = useSignal(null)
const showAddTodoDialog = useSignal(false)
const todoItem = (
{ className, description, hideDone }: Pick<Todo, 'description'> & {
className?: string
hideDone?: boolean
},
) => (
<li
style={`border-color: #${color}`}
class={`${className || ''} ${
hideDone ? '' : 'border-l-4'
} p-4 rounded drop-shadow-lg bg-white dark:bg-stone-900 flex flex-col`}
>
<span class='text-xl'>{description}</span>
{hideDone ? '' : <Button class='mt-2'>Done</Button>}
</li>
)
return (
<div class='p-2 w-1/4 min-w-[15rem] relative flex flex-col grow-0'>
<Dialog
headerTitle='Add todo'
show={showAddTodoDialog.value}
onClose={() => showAddTodoDialog.value = false}
>
<form
class='p-4 gap-4 flex flex-col'
action='/api/todo'
method='post'
encType='multipart/form-data'
>
<Label for='description'>
Description
<Input autofocus name='description' />
</Label>
<span>
Assignee
<ul class='flex gap-2'>
<li>
<input
type='radio'
id='assigneeUserId_unassigned'
name='assigneeUserId'
value=''
/>
<Label for='assigneeUserId_unassigned'>
<Avatar
className='mb-2'
src='http://placekitten.com/512/512'
/>
<span
style={`color: #888888;`}
class='font-semibold text-center'
>
Shared
</span>
</Label>
</li>
{Object.entries(users).map(([id, { avatarUrl, color }]) => {
const eid = `assigneeUserId_${id}`
return (
<li>
<input
type='radio'
id={eid}
name='assigneeUserId'
value={id}
/>
<Label for={eid}>
<Avatar className='mb-2' src={avatarUrl} />
<span
style={`color: #${color};`}
class='font-semibold text-center'
>
{name}
</span>
</Label>
</li>
)
})}
</ul>
</span>
<footer class='flex justify-end gap-2'>
<Button
type='button'
onClick={() => showAddTodoDialog.value = false}
>
Cancel
</Button>
<Input type='submit' value='Save' />
</footer>
</form>
</Dialog>
<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'
onClick={() => {
showAddTodoDialog.value = true
todoAssignUserId.value = id
}}
>
+ New
</button>
<ul class='flex flex-col gap-y-4'>
{assignedTodos.length < 1
? todoItem({
description: 'All clear! 🎉',
className: 'text-center',
hideDone: true,
})
: assignedTodos.map(todoItem)}
</ul>
</div>
)
}