diff --git a/islands/Dashboard.tsx b/islands/Dashboard.tsx index d00dc12..bc3bd7c 100644 --- a/islands/Dashboard.tsx +++ b/islands/Dashboard.tsx @@ -127,22 +127,42 @@ function UserSelectButton( } export default function Dashboard( - { todos, users, unassignedTodos, lastTodoIdUpdated, lastUserIdUpdated }: - Props, + props: Props, ) { - console.log('lasttodo:', lastTodoIdUpdated) - console.log('lastuser:', lastUserIdUpdated) const todoAssignUserId: Signal = useSignal(null) const showAddTodoDialog = useSignal(false) + const data = useSignal(props) + + const { + // todos, + users, + unassignedTodos, + // lastTodoIdUpdated, + // lastUserIdUpdated, + } = data.value + + const reload = async () => { + console.log('reloading...') + const newData = await (await fetch(location.href, { + headers: { accept: 'application/json' }, + })).json() + data.value = newData + console.log('new data:', newData) + } + useEffect(() => { let es = new EventSource('/api/user') - es.addEventListener('message', (e) => { - console.log('user event from server:', e) + es.addEventListener('message', async (e) => { + console.log('user event stream message:', e) + await reload() + excitement() }) - es.addEventListener('error', async () => { + es.addEventListener('error', async (e) => { + // try and reconnect + console.log('Streaming user events error:', e) es.close() const backoff = 10000 + Math.random() * 5000 await new Promise((resolve) => setTimeout(resolve, backoff)) @@ -150,47 +170,17 @@ export default function Dashboard( }) }, []) - useEffect(excitement) - useEffect(() => { let es = new EventSource('/api/todo') console.log('Streaming todo events...') es.addEventListener('message', (e) => { console.log('todo event from server:', e) - const payload = JSON.parse(e.data) - const { id: id } = payload - - if ( - payload.versionstamp === lastTodoIdUpdated.versionstamp && - payload.id === lastTodoIdUpdated.value - ) { - console.log('skipping...') - // skip, we hydrated with it - return - } - - if (!payload.value) { - // deleted, so reload - location.reload() - } else { - const { description, doneAt, assigneeUserId, emoji } = payload.value - const t = todos[id] - if ( - !t || - id != t.id || - description != t.description || - doneAt != t.doneAt || - assigneeUserId != t.assigneeUserId || - emoji != t.emoji - ) { - console.log('Should reload!') - location.reload() - } - } + reload().then(excitement) }) es.addEventListener('error', async (e) => { + // try and reconnect console.log('Streaming todo events error:', e) es.close() const backoff = 10000 + Math.random() * 5000 diff --git a/routes/api/todo.ts b/routes/api/todo.ts index e532ebb..830a1fb 100644 --- a/routes/api/todo.ts +++ b/routes/api/todo.ts @@ -80,6 +80,8 @@ export const handler: Handlers = { // TODO: json or query params const accept = req.headers.get('accept') if (accept === 'text/event-stream') { + console.log('Request for todo event stream') + let skipFirst = true const stream = kv.watch([['last_todo_updated']]).getReader() const body = new ReadableStream({ async start(controller) { @@ -89,12 +91,12 @@ export const handler: Handlers = { while (true) { try { const entries = await stream.read() - console.log('streaming todo entries:', entries) for (const entry of entries.value || []) { - console.log('streaming todo entry:', entry) - + if (skipFirst) { + skipFirst = false + continue + } if (typeof entry.value !== 'string') { - console.error('Invalid last_todo_updated entry:', entry) continue } @@ -108,6 +110,7 @@ export const handler: Handlers = { value: todo, }) }\n\n` + console.log('todo event chunk:', chunk) controller.enqueue(new TextEncoder().encode(chunk)) } if (entries.done) { diff --git a/routes/api/user.ts b/routes/api/user.ts index 2e8f07f..5f3bab2 100644 --- a/routes/api/user.ts +++ b/routes/api/user.ts @@ -100,7 +100,6 @@ export const handler: Handlers = { } if (typeof entry.value !== 'string') { - console.error('Invalid last_user_updated:', entry.value) continue } diff --git a/routes/index.tsx b/routes/index.tsx index bccdfb5..277a7ff 100644 --- a/routes/index.tsx +++ b/routes/index.tsx @@ -11,7 +11,13 @@ interface Data { } export const handler: Handlers = { - async GET(_req, ctx) { + async GET(req, ctx) { + const accept = req.headers.get('accept') + if (accept === 'text/event-stream') { + console.log('requested index event stream -- not implemented') + return new Response(JSON.stringify({ message: 'not implemented' })) + } + const users = Object.fromEntries( (await db.users.findMany({ include: { assignedTodos: true } })).map( (u) => [u.id, u], @@ -29,13 +35,17 @@ export const handler: Handlers = { 'last_user_updated', ], ['last_todo_updated']], { consistency: 'eventual' }) console.log({ lastTodoIdUpdated, lastUserIdUpdated }) - return ctx.render({ + const props = { users, todos, unassignedTodos, lastUserIdUpdated, lastTodoIdUpdated, - }) + } + if (accept === 'application/json') { + return new Response(JSON.stringify(props)) + } + return ctx.render(props) }, }