Done works
This commit is contained in:
parent
2ba678c4a3
commit
78bd64f100
|
@ -7,6 +7,7 @@ import * as $_app from './routes/_app.tsx'
|
|||
import * as $admin from './routes/admin.tsx'
|
||||
import * as $api_joke from './routes/api/joke.ts'
|
||||
import * as $api_todo from './routes/api/todo.ts'
|
||||
import * as $api_todo_done from './routes/api/todo/done.ts'
|
||||
import * as $api_user from './routes/api/user.ts'
|
||||
import * as $greet_name_ from './routes/greet/[name].tsx'
|
||||
import * as $index from './routes/index.tsx'
|
||||
|
@ -24,6 +25,7 @@ const manifest = {
|
|||
'./routes/admin.tsx': $admin,
|
||||
'./routes/api/joke.ts': $api_joke,
|
||||
'./routes/api/todo.ts': $api_todo,
|
||||
'./routes/api/todo/done.ts': $api_todo_done,
|
||||
'./routes/api/user.ts': $api_user,
|
||||
'./routes/greet/[name].tsx': $greet_name_,
|
||||
'./routes/index.tsx': $index,
|
||||
|
|
|
@ -21,12 +21,13 @@ const unassignedUserPlaceholder: User = {
|
|||
color: '888888',
|
||||
}
|
||||
|
||||
interface UserSelectButtonProps extends JSX.HTMLAttributes<HTMLLabelElement> {
|
||||
interface UserSelectButtonProps extends JSX.HTMLAttributes<HTMLInputElement> {
|
||||
user: User
|
||||
}
|
||||
|
||||
function UserSelectButton(
|
||||
{ user: { id, avatarUrl, color }, ...props }: UserSelectButtonProps,
|
||||
{ user: { id, name, avatarUrl, color }, tabindex, ...props }:
|
||||
UserSelectButtonProps,
|
||||
) {
|
||||
const eid = `assigneeUserId_${id}`
|
||||
return (
|
||||
|
@ -34,17 +35,18 @@ function UserSelectButton(
|
|||
<input
|
||||
aria-hidden='true'
|
||||
type='radio'
|
||||
class='hidden left-[99999px]'
|
||||
class='peer sr-only'
|
||||
id={eid}
|
||||
name='assigneeUserId'
|
||||
value={id}
|
||||
{...props}
|
||||
/>
|
||||
<Label
|
||||
{...props}
|
||||
for={eid}
|
||||
className='cursor-pointer hover:bg-gray-500/20 rounded p-2'
|
||||
style={`border-color: #${color};`}
|
||||
tabindex={tabindex}
|
||||
className='cursor-pointer peer-checked:border-t-2 peer-checked:bg-gray-500/20 hover:bg-gray-500/25 rounded p-2'
|
||||
role='button'
|
||||
aria-pressed='false'
|
||||
>
|
||||
<Avatar
|
||||
className='mb-2'
|
||||
|
@ -54,7 +56,7 @@ function UserSelectButton(
|
|||
style={`color: #${color};`}
|
||||
class='font-semibold text-center'
|
||||
>
|
||||
Shared
|
||||
{name}
|
||||
</span>
|
||||
</Label>
|
||||
</>
|
||||
|
@ -91,13 +93,20 @@ export default function Dashboard({ users, unassignedTodos }: Props) {
|
|||
Assignee
|
||||
<ul class='flex gap-2'>
|
||||
<li>
|
||||
<UserSelectButton tabindex={0} user={unassignedUser} />
|
||||
<UserSelectButton
|
||||
checked={todoAssignUserId.value == null}
|
||||
tabindex={0}
|
||||
user={unassignedUser}
|
||||
/>
|
||||
</li>
|
||||
{Object.values(users).map(
|
||||
(user, i) => {
|
||||
(user) => {
|
||||
return (
|
||||
<li>
|
||||
<UserSelectButton tabindex={i} user={user} />
|
||||
<UserSelectButton
|
||||
checked={todoAssignUserId.value == user.id}
|
||||
user={user}
|
||||
/>
|
||||
</li>
|
||||
)
|
||||
},
|
||||
|
|
|
@ -13,19 +13,35 @@ export function TodoList(
|
|||
Props,
|
||||
) {
|
||||
const todoItem = (
|
||||
{ className, description, hideDone }: Pick<Todo, 'description'> & {
|
||||
className?: string
|
||||
hideDone?: boolean
|
||||
},
|
||||
{ id, doneAt, className, description, hideDone }:
|
||||
& Pick<Todo, 'description' | 'id' | 'doneAt'>
|
||||
& {
|
||||
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`}
|
||||
} p-4 rounded drop-shadow-lg bg-white dark:bg-stone-900 flex flex-col gap-2`}
|
||||
>
|
||||
{JSON.stringify(doneAt)}
|
||||
<span class='text-xl'>{description}</span>
|
||||
{hideDone ? '' : <Button class='mt-2'>Done</Button>}
|
||||
{(hideDone || doneAt != null) ? '' : (
|
||||
<Button
|
||||
onClick={async () => {
|
||||
await fetch('/api/todo/done', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ id }),
|
||||
})
|
||||
// TODO: remove the todoitem?
|
||||
// TODO: confetti
|
||||
}}
|
||||
>
|
||||
Done
|
||||
</Button>
|
||||
)}
|
||||
</li>
|
||||
)
|
||||
return (
|
||||
|
|
|
@ -8,7 +8,11 @@ type TodoPayload = z.infer<typeof TodoPayload>
|
|||
|
||||
async function createOrUpdate(todo: TodoPayload) {
|
||||
if (!todo.id) {
|
||||
const newTodo: Todo = { ...todo, id: ulid(), createdAt: new Date() }
|
||||
const newTodo: Todo = {
|
||||
...todo,
|
||||
id: ulid(),
|
||||
createdAt: new Date(),
|
||||
}
|
||||
return await db.todos.create({ data: newTodo })
|
||||
} else {
|
||||
return await db.todos.update({ where: { id: todo.id }, data: todo })
|
||||
|
@ -18,7 +22,9 @@ async function createOrUpdate(todo: TodoPayload) {
|
|||
export const handler: Handlers<Todo | null> = {
|
||||
async POST(req, _ctx) {
|
||||
if (req.headers.get('content-type')?.includes('json')) {
|
||||
const result = await createOrUpdate(TodoPayload.parse(await req.json()))
|
||||
const result = await createOrUpdate(
|
||||
TodoPayload.parse(await req.json()),
|
||||
)
|
||||
return new Response(JSON.stringify(result))
|
||||
} else {
|
||||
const form = await req.formData()
|
||||
|
@ -29,7 +35,8 @@ export const handler: Handlers<Todo | null> = {
|
|||
|
||||
const todo = TodoPayload.parse({
|
||||
id: id,
|
||||
emoji: form.get('emoji')?.toString(),
|
||||
emoji: form.get('emoji')?.toString() || null,
|
||||
doneAt: form.get('doneAt')?.toString() || null,
|
||||
description: form.get('description')?.toString(),
|
||||
assigneeUserId: form.get('assigneeUserId')?.toString(),
|
||||
})
|
||||
|
@ -41,7 +48,7 @@ export const handler: Handlers<Todo | null> = {
|
|||
await createOrUpdate(todo)
|
||||
|
||||
const url = new URL(req.url)
|
||||
url.pathname = '/admin'
|
||||
url.pathname = '/'
|
||||
return Response.redirect(url, 303)
|
||||
}
|
||||
},
|
||||
|
|
14
routes/api/todo/done.ts
Normal file
14
routes/api/todo/done.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { Handlers } from '$fresh/server.ts'
|
||||
import { db, TodoModel } from '@homeman/models.ts'
|
||||
|
||||
const Model = TodoModel.pick({ id: true })
|
||||
|
||||
export const handler: Handlers = {
|
||||
async POST(req, _ctx) {
|
||||
const { id } = Model.parse(await req.json())
|
||||
const todo = await db.todos.findFirst({ where: { id } })
|
||||
todo.doneAt = new Date()
|
||||
const newTodo = await db.todos.update({ where: { id }, data: todo })
|
||||
return new Response(JSON.stringify(newTodo))
|
||||
},
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
import { Handlers, PageProps } from '$fresh/server.ts'
|
||||
import { db, Todo, User, UserWithTodos } from '@homeman/models.ts'
|
||||
import { db, Todo, UserWithTodos } from '@homeman/models.ts'
|
||||
import Dashboard from '@homeman/islands/Dashboard.tsx'
|
||||
|
||||
interface Data {
|
||||
|
|
Loading…
Reference in a new issue