Merge branch 'tasks-bork' into tasks
This commit is contained in:
commit
26d05e3cd4
5
db.ts
5
db.ts
|
@ -2,7 +2,7 @@ import {
|
||||||
createPentagon,
|
createPentagon,
|
||||||
TableDefinition,
|
TableDefinition,
|
||||||
} from 'https://deno.land/x/pentagon@v0.1.5/mod.ts'
|
} from 'https://deno.land/x/pentagon@v0.1.5/mod.ts'
|
||||||
import { TaskModel, TodoModel, UserModel } from '@homeman/models.ts'
|
import { TodoModel, UserModel } from '@homeman/models.ts'
|
||||||
|
|
||||||
export const kv = await Deno.openKv('homeman.db')
|
export const kv = await Deno.openKv('homeman.db')
|
||||||
|
|
||||||
|
@ -19,9 +19,6 @@ export const schema: Record<string, TableDefinition> = {
|
||||||
assignee: ['users', UserModel, 'assigneeUserId', 'id'],
|
assignee: ['users', UserModel, 'assigneeUserId', 'id'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
tasks: {
|
|
||||||
schema: TaskModel,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const db = createPentagon(kv, schema)
|
export const db = createPentagon(kv, schema)
|
||||||
|
|
|
@ -1,16 +1,9 @@
|
||||||
import {
|
import { DailyPhase, DailyPhaseModel, Task, toPhase } from '@homeman/models.ts'
|
||||||
DailyPhase,
|
|
||||||
DailyPhaseModel,
|
|
||||||
DoneTask,
|
|
||||||
Task,
|
|
||||||
toPhase,
|
|
||||||
} from '@homeman/models.ts'
|
|
||||||
import { useSignal } from '@preact/signals'
|
import { useSignal } from '@preact/signals'
|
||||||
import { excitement } from '@homeman/common.ts'
|
import { excitement } from '@homeman/common.ts'
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
tasks: Task[]
|
tasks: Task[]
|
||||||
done: DoneTask[]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TaskWithIndex extends Task {
|
interface TaskWithIndex extends Task {
|
||||||
|
@ -62,38 +55,37 @@ export function Routine(
|
||||||
<main class='flex flex-col overflow-x-scroll'>
|
<main class='flex flex-col overflow-x-scroll'>
|
||||||
<ul>
|
<ul>
|
||||||
{taskGroups[currentPhase.value].map((
|
{taskGroups[currentPhase.value].map((
|
||||||
{ emoji, id, doneAt, index }: TaskWithIndex,
|
task: TaskWithIndex,
|
||||||
) => (
|
) => {
|
||||||
<li
|
const { emoji, description, doneAt, index } = task
|
||||||
role='button'
|
return (
|
||||||
class={`text-lg cursor-pointer p-4 hover:bg-gray-500/20 ${
|
<li
|
||||||
doneAt ? 'line-through opacity-30 hover:bg-gray-500' : ''
|
role='button'
|
||||||
}`}
|
class={`text-lg cursor-pointer p-4 hover:bg-gray-500/20 ${
|
||||||
onClick={() => {
|
doneAt ? 'line-through opacity-30 hover:bg-gray-500' : ''
|
||||||
tasks.value[index].doneAt = tasks.value[index].doneAt
|
}`}
|
||||||
? null
|
onClick={async () => {
|
||||||
: new Date()
|
tasks.value[index].doneAt = tasks.value[index].doneAt
|
||||||
tasks.value = [...tasks.value]
|
? null
|
||||||
if (tasks.value[index].doneAt) {
|
: new Date()
|
||||||
fetch('/api/tasks', {
|
tasks.value = [...tasks.value]
|
||||||
method: 'POST',
|
if (tasks.value[index].doneAt) {
|
||||||
headers: { 'content-type': 'application/json' },
|
excitement()
|
||||||
body: JSON.stringify({ id: id }),
|
}
|
||||||
})
|
await (await fetch('/api/tasks', {
|
||||||
excitement()
|
method: 'PUT',
|
||||||
} else {
|
body: JSON.stringify({
|
||||||
fetch('/api/tasks', {
|
...task,
|
||||||
method: 'DELETE',
|
done: !!tasks.value[index].doneAt,
|
||||||
headers: { 'content-type': 'application/json' },
|
}),
|
||||||
body: JSON.stringify({ id: id }),
|
})).json()
|
||||||
})
|
}}
|
||||||
}
|
>
|
||||||
}}
|
{emoji ? `${emoji.trim()} ` : ''}
|
||||||
>
|
{description.trim()}
|
||||||
{emoji ? `${emoji.trim()} ` : ''}
|
</li>
|
||||||
{id.trim()}
|
)
|
||||||
</li>
|
})}
|
||||||
))}
|
|
||||||
</ul>
|
</ul>
|
||||||
</main>
|
</main>
|
||||||
</>
|
</>
|
||||||
|
|
13
main.ts
13
main.ts
|
@ -10,5 +10,18 @@ import '$std/dotenv/load.ts'
|
||||||
import { start } from '$fresh/server.ts'
|
import { start } from '$fresh/server.ts'
|
||||||
import manifest from './fresh.gen.ts'
|
import manifest from './fresh.gen.ts'
|
||||||
import config from './fresh.config.ts'
|
import config from './fresh.config.ts'
|
||||||
|
import { kv } from '@homeman/db.ts'
|
||||||
|
import { Task } from '@homeman/models.ts'
|
||||||
|
|
||||||
|
Deno.cron('Reset daily tasks', '0 4 * * *', async () => {
|
||||||
|
console.log('4am daily tasks reset')
|
||||||
|
const tasks = await Array.fromAsync(kv.list<Task>({ prefix: ['task'] }))
|
||||||
|
tasks.forEach(
|
||||||
|
async (t) => {
|
||||||
|
const nv = { ...t.value, doneAt: null }
|
||||||
|
await kv.set(t.key, nv)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
await start(manifest, config)
|
await start(manifest, config)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { DailyPhase, TaskModel } from '@homeman/models.ts'
|
import { DailyPhase, TaskModel } from '@homeman/models.ts'
|
||||||
import { db } from '@homeman/db.ts'
|
import { kv } from '@homeman/db.ts'
|
||||||
import { ulid } from 'https://deno.land/x/ulid@v0.3.0/mod.ts'
|
import { ulid } from 'https://deno.land/x/ulid@v0.3.0/mod.ts'
|
||||||
|
|
||||||
const hardcoded: Record<DailyPhase, [string, string][]> = {
|
const hardcoded: Record<DailyPhase, [string, string][]> = {
|
||||||
|
@ -41,6 +41,7 @@ const hardcoded: Record<DailyPhase, [string, string][]> = {
|
||||||
['👨⚖️', 'Sleep!'],
|
['👨⚖️', 'Sleep!'],
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
console.log({ kv })
|
||||||
Object.entries(hardcoded).forEach(async ([tphase, phaseTasks]) => {
|
Object.entries(hardcoded).forEach(async ([tphase, phaseTasks]) => {
|
||||||
const phase = tphase as DailyPhase
|
const phase = tphase as DailyPhase
|
||||||
for (const [emoji, description] of phaseTasks) {
|
for (const [emoji, description] of phaseTasks) {
|
||||||
|
@ -52,9 +53,10 @@ Object.entries(hardcoded).forEach(async ([tphase, phaseTasks]) => {
|
||||||
doneAt: null,
|
doneAt: null,
|
||||||
})
|
})
|
||||||
console.log(task)
|
console.log(task)
|
||||||
const result = await db.tasks.create({
|
try {
|
||||||
data: task,
|
await kv.set(['task', task.id], task)
|
||||||
})
|
} catch (e) {
|
||||||
console.log('after create:', result)
|
console.error('error creating:', e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,64 +1,40 @@
|
||||||
import { Handlers } from '$fresh/server.ts'
|
import { Handlers } from '$fresh/server.ts'
|
||||||
import { Task, TaskModel } from '@homeman/models.ts'
|
import { Task, TaskModel } from '@homeman/models.ts'
|
||||||
import { db, kv } from '@homeman/db.ts'
|
import { kv } from '@homeman/db.ts'
|
||||||
import { ulid } from 'https://deno.land/x/ulid@v0.3.0/mod.ts'
|
import { ulid } from 'https://deno.land/x/ulid@v0.3.0/mod.ts'
|
||||||
import { z } from 'https://deno.land/x/zod@v3.21.4/mod.ts'
|
import { z } from 'https://deno.land/x/zod@v3.21.4/mod.ts'
|
||||||
|
|
||||||
const TaskPayload = TaskModel.partial({ id: true })
|
const TaskPayload = TaskModel.omit({ doneAt: true }).partial({
|
||||||
|
id: true,
|
||||||
|
}).extend({
|
||||||
|
done: z.boolean().optional(),
|
||||||
|
})
|
||||||
type TaskPayload = z.infer<typeof TaskPayload>
|
type TaskPayload = z.infer<typeof TaskPayload>
|
||||||
|
|
||||||
async function createOrUpdate(task: TaskPayload) {
|
async function createOrUpdate(task: TaskPayload) {
|
||||||
if (!task.id || task.id === '') {
|
const newTask: Task = TaskModel.parse({
|
||||||
const newTask: Task = {
|
...task,
|
||||||
...task,
|
doneAt: task.done ? new Date() : null,
|
||||||
id: ulid(),
|
})
|
||||||
}
|
if (!newTask.id || newTask.id === '') {
|
||||||
const result = await db.tasks.create({ data: newTask })
|
newTask.id = ulid()
|
||||||
await kv.set(['last_task_updated'], newTask.id)
|
|
||||||
return result
|
|
||||||
} else {
|
|
||||||
const result = await db.tasks.update({ where: { id: task.id }, data: task })
|
|
||||||
await kv.set(['last_task_updated'], task.id)
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
const result = await kv.set(['task', newTask.id], newTask)
|
||||||
|
await kv.set(['last_task_updated'], newTask.id)
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
export const handler: Handlers<Task | null> = {
|
export const handler: Handlers<Task | null> = {
|
||||||
async POST(req, _ctx) {
|
async POST(req, _ctx) {
|
||||||
if (req.headers.get('content-type')?.includes('json')) {
|
const result = await createOrUpdate(
|
||||||
const result = await createOrUpdate(
|
TaskPayload.parse(await req.json()),
|
||||||
TaskPayload.parse(await req.json()),
|
)
|
||||||
)
|
return new Response(JSON.stringify(result))
|
||||||
return new Response(JSON.stringify(result))
|
},
|
||||||
} else {
|
async PUT(req, _ctx) {
|
||||||
const form = await req.formData()
|
const t = TaskPayload.parse(await req.json())
|
||||||
const id = form.get('id')?.toString() || undefined
|
const result = await createOrUpdate(t)
|
||||||
|
return new Response(JSON.stringify(result))
|
||||||
const doneAt = form.get('doneAt')
|
|
||||||
console.log('task POST doneAt:', doneAt)
|
|
||||||
|
|
||||||
const task = TaskPayload.parse({
|
|
||||||
id: id,
|
|
||||||
emoji: form.get('emoji')?.toString() || null,
|
|
||||||
doneAt: form.get('doneAt')?.toString() || null,
|
|
||||||
description: form.get('description')?.toString(),
|
|
||||||
assigneeUserId: form.get('assigneeUserId')?.toString() || null,
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!id) {
|
|
||||||
delete task.id
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!task.assigneeUserId) {
|
|
||||||
delete task.id
|
|
||||||
}
|
|
||||||
|
|
||||||
await createOrUpdate(task)
|
|
||||||
|
|
||||||
const url = new URL(req.url)
|
|
||||||
url.pathname = '/'
|
|
||||||
return Response.redirect(url, 303)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
async DELETE(req, _ctx) {
|
async DELETE(req, _ctx) {
|
||||||
// task: form or query params or json
|
// task: form or query params or json
|
||||||
|
@ -70,7 +46,7 @@ export const handler: Handlers<Task | null> = {
|
||||||
}
|
}
|
||||||
console.log('delete task data:', data)
|
console.log('delete task data:', data)
|
||||||
const taskData = TaskModel.pick({ id: true }).parse(data)
|
const taskData = TaskModel.pick({ id: true }).parse(data)
|
||||||
const result = await db.tasks.delete({ where: taskData })
|
const result = await kv.delete(['task', taskData.id])
|
||||||
await kv.set(['last_task_updated'], taskData.id)
|
await kv.set(['last_task_updated'], taskData.id)
|
||||||
return new Response(JSON.stringify(result))
|
return new Response(JSON.stringify(result))
|
||||||
},
|
},
|
||||||
|
@ -98,9 +74,7 @@ export const handler: Handlers<Task | null> = {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
const task = await db.tasks.findFirst({
|
const task = (await kv.get(['task', entry.value])).value
|
||||||
where: { id: entry.value },
|
|
||||||
})
|
|
||||||
const chunk = `data: ${
|
const chunk = `data: ${
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
id: entry.value,
|
id: entry.value,
|
||||||
|
@ -136,10 +110,12 @@ export const handler: Handlers<Task | null> = {
|
||||||
const taskData = TaskModel.pick({ id: true }).safeParse(data)
|
const taskData = TaskModel.pick({ id: true }).safeParse(data)
|
||||||
if (taskData.success) {
|
if (taskData.success) {
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify(await db.tasks.findFirst({ where: taskData.data })),
|
JSON.stringify((await kv.get(['task', taskData.data.id])).value),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
return new Response(JSON.stringify(await db.tasks.findMany({})))
|
return new Response(
|
||||||
|
JSON.stringify(Array.fromAsync(kv.list({ prefix: ['task'] }))),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Handlers, PageProps } from '$fresh/server.ts'
|
import { Handlers, PageProps } from '$fresh/server.ts'
|
||||||
import { Task } from '@homeman/models.ts'
|
import { Task } from '@homeman/models.ts'
|
||||||
import { Routine } from '@homeman/islands/Routine.tsx'
|
import { Routine } from '@homeman/islands/Routine.tsx'
|
||||||
import { db } from '@homeman/db.ts'
|
import { kv } from '@homeman/db.ts'
|
||||||
// import { db, kv, Todo, UserWithTodos } from '@homeman/models.ts'
|
// import { db, kv, Todo, UserWithTodos } from '@homeman/models.ts'
|
||||||
|
|
||||||
interface Data {
|
interface Data {
|
||||||
|
@ -10,7 +10,10 @@ interface Data {
|
||||||
|
|
||||||
export const handler: Handlers = {
|
export const handler: Handlers = {
|
||||||
async GET(_req, ctx) {
|
async GET(_req, ctx) {
|
||||||
const tasks = await db.tasks.findMany({})
|
const tasks = (await Array.fromAsync(kv.list({ prefix: ['task'] }))).map(
|
||||||
|
(r) => r.value
|
||||||
|
)
|
||||||
|
console.log({ tasks })
|
||||||
return ctx.render({ tasks })
|
return ctx.render({ tasks })
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue