I'm pretending to be liveview

This commit is contained in:
Daniel Flanagan 2024-01-16 16:15:10 -06:00
parent 78bd64f100
commit d2341cdc52
Signed by: lytedev
GPG key ID: 5B2020A0F9921EF4
6 changed files with 93 additions and 24 deletions

View file

@ -2,17 +2,17 @@
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1701718080,
"narHash": "sha256-6ovz0pG76dE0P170pmmZex1wWcQoeiomUZGggfH9XPs=",
"lastModified": 1705316053,
"narHash": "sha256-J2Ey5mPFT8gdfL2XC0JTZvKaBw/b2pnyudEXFvl+dQM=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "2c7f3c0fb7c08a0814627611d9d7d45ab6d75335",
"rev": "c3e128f3c0ecc1fb04aef9f72b3dcc2f6cecf370",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"rev": "2c7f3c0fb7c08a0814627611d9d7d45ab6d75335",
"type": "github"
}
},

View file

@ -1,5 +1,5 @@
{
inputs.nixpkgs.url = "github:NixOS/nixpkgs?rev=2c7f3c0fb7c08a0814627611d9d7d45ab6d75335";
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
outputs = {
self,
nixpkgs,

View file

@ -6,12 +6,15 @@ import { Avatar } from '@homeman/components/Avatar.tsx'
export interface Props {
user: UserWithTodos
onNewButtonClicked: JSX.MouseEventHandler<HTMLButtonElement>
onTodoDone: (id: string) => Promise<void>
}
export function TodoList(
{ onNewButtonClicked, user: { avatarUrl, assignedTodos, name, color } }:
{ onTodoDone, onNewButtonClicked, user: { avatarUrl, name, color, ...user } }:
Props,
) {
const doneTodos = user.assignedTodos.filter((t) => t.doneAt != null)
const inProgressTodos = user.assignedTodos.filter((t) => t.doneAt == null)
const todoItem = (
{ id, doneAt, className, description, hideDone }:
& Pick<Todo, 'description' | 'id' | 'doneAt'>
@ -22,26 +25,40 @@ export function TodoList(
) => (
<li
style={`border-color: #${color}`}
title={doneAt != null ? `Completed at ${doneAt}` : ''}
class={`${className || ''} ${
hideDone ? '' : 'border-l-4'
} p-4 rounded drop-shadow-lg bg-white dark:bg-stone-900 flex flex-col gap-2`}
} p-4 text-black cursor-auto dark:text-white 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 || doneAt != null) ? '' : (
<Button
onClick={async () => {
await fetch('/api/todo/done', {
method: 'POST',
method: 'PUT',
body: JSON.stringify({ id }),
})
// TODO: remove the todoitem?
// TODO: confetti
await onTodoDone(id)
}}
>
Done
</Button>
)}
{(!hideDone && doneAt != null)
? (
<Button
onClick={async () => {
await fetch('/api/todo/done', {
method: 'DELETE',
body: JSON.stringify({ id }),
})
await onTodoDone(id)
}}
>
Not Done
</Button>
)
: ''}
</li>
)
return (
@ -61,14 +78,28 @@ export function TodoList(
+ New
</button>
<ul class='flex flex-col gap-y-4'>
{assignedTodos.length < 1
{inProgressTodos.length < 1
? todoItem({
id: '',
doneAt: null,
description: 'All clear! 🎉',
className: 'text-center',
hideDone: true,
})
: assignedTodos.map(todoItem)}
: inProgressTodos.map(todoItem)}
</ul>
{doneTodos.length > 0
? (
<summary class='text-gray-500 mt-4'>
+{doneTodos.length} completed todos
<details class='cursor-pointer'>
<ul class='flex flex-col gap-y-4 mt-4'>
{doneTodos.map(todoItem)}
</ul>
</details>
</summary>
)
: ''}
</div>
)
}

View file

@ -1,8 +1,11 @@
import { z } from 'https://deno.land/x/zod@v3.21.4/mod.ts'
import { createPentagon } from 'https://deno.land/x/pentagon@v0.1.5/mod.ts'
import {
createPentagon,
TableDefinition,
} from 'https://deno.land/x/pentagon@v0.1.5/mod.ts'
// import { ulid } from 'https://deno.land/x/ulid@v0.3.0/mod.ts'
const kv = await Deno.openKv('homeman.db')
export const kv = await Deno.openKv('homeman.db')
// const todos = kv.list({ prefix: ['todos'] })
// const deleteme = []
@ -41,7 +44,7 @@ const Todo = z.object({
export const TodoModel = Todo
export type Todo = z.infer<typeof Todo>
export const db = createPentagon(kv, {
export const schema: Record<string, TableDefinition> = {
users: {
schema: User,
relations: {
@ -54,7 +57,9 @@ export const db = createPentagon(kv, {
assignee: ['users', User, 'assigneeUserId', 'id'],
},
},
})
}
export const db = createPentagon(kv, schema)
// const daddy: User = {
// id: ulid(),

View file

@ -3,12 +3,23 @@ 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())
async function markDone(id: string) {
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))
return await db.todos.update({ where: { id }, data: todo })
}
async function markNotDone(id: string) {
return await db.todos.update({ where: { id }, data: { doneAt: null } })
}
export const handler: Handlers = {
async PUT(req, _ctx) {
const { id } = Model.parse(await req.json())
return new Response(JSON.stringify(await markDone(id)))
},
async DELETE(req, _ctx) {
const { id } = Model.parse(await req.json())
return new Response(JSON.stringify(await markNotDone(id)))
},
}

View file

@ -1,12 +1,23 @@
import { Handlers, PageProps } from '$fresh/server.ts'
import { db, Todo, UserWithTodos } from '@homeman/models.ts'
import { db, kv, schema, Todo, UserWithTodos } from '@homeman/models.ts'
import Dashboard from '@homeman/islands/Dashboard.tsx'
import { useSignal } from '@preact/signals'
import { useEffect } from 'preact/hooks'
interface Data {
users: Record<string, UserWithTodos>
unassignedTodos: Todo[]
}
const allTableNames = Object.keys(schema).map((s) => [s])
async function watcher() {
console.log('watching:', allTableNames)
for await (const entry of kv.watch(allTableNames)) {
console.log('entry:', entry)
}
}
watcher()
export const handler: Handlers = {
async GET(_req, ctx) {
const users = Object.fromEntries(
@ -22,5 +33,16 @@ export const handler: Handlers = {
}
export default function Home({ data }: PageProps<Data>) {
return <Dashboard {...data} />
const rdata = useSignal(data)
useEffect(() => {
async function watcher() {
console.log('watcher watching...')
for await (const entry of kv.watch(allTableNames)) {
console.log('entry:', entry)
}
}
watcher().catch(console.error)
}, [rdata])
console.log('Home rendered')
return <Dashboard {...rdata.value} />
}