Refactor task management, UI interactions, and theme support

- Added task editing functionality with `EditForm` and integrated it with `TodoItemTouch`.
- Switched `dueDate` fields to `due_date` for consistency with API.
- Updated `useTasks` to handle dynamic task updates, deletions, and periodic refresh.
- Enhanced `useApi` with a dedicated delete method.
- Improved UI responsiveness and styling with multi-theme support in DaisyUI.
- Simplified modal handling for task interactions (`EditForm`, `CreateForm`).
- Improved `useSettings` with a `theme` field to support theme switching.
- Extended task commands for tagging, text, and due date updates.
- Optimized `parser` for extended edit command parsing.
- Updated helpers and actions to use `luxon` for date manipulations.
- Streamlined task and view logic for improved usability and extensibility.
This commit is contained in:
2026-03-08 19:54:30 +01:00
parent 25fd10a325
commit 09b4af9a6e
17 changed files with 469 additions and 104 deletions

View File

@@ -19,12 +19,13 @@ import { useSettings } from './useSettings.ts'
import { useTasks } from './useTasks.ts'
export default function useActions() {
const { tasks: tasksOriginal, createTask, updateTask } = useTasks()
const { tasks: tasksOriginal, createTask, updateTask, deleteTask, fetchTasks } = useTasks()
const { settings } = useSettings()
const run = async (value: string) => {
const cmd = parseCommand(value)
let tasksToUpdate: Task[] = []
let taskToCreate: Pick<Task, 'tag' | 'title' | 'dueDate'> | null = null
let tasksToUpdate: Task[] | null = null
let tasksToDelete: Task[] | null = null
let taskToCreate: Pick<Task, 'tag' | 'title' | 'due_date'> | null = null
const tasks = JSON.parse(JSON.stringify(tasksOriginal.value)) as Task[]
if (cmd) {
const ids = cmd.id
@@ -45,7 +46,7 @@ export default function useActions() {
break
case 'd':
case 'delete':
tasksToUpdate = deleteCommand(ids, cmd, tasks)
tasksToDelete = deleteCommand(ids, cmd, tasks)
break
case 'fl':
case 'flag':
@@ -98,12 +99,16 @@ export default function useActions() {
// break
}
}
if (tasksToDelete) {
await deleteTask(tasksToDelete)
}
if (tasksToUpdate) {
await updateTask(tasksToUpdate)
}
if (taskToCreate) {
await createTask(taskToCreate)
}
await fetchTasks(true)
}
return { run }
}

View File

@@ -60,10 +60,14 @@ export function useApi() {
const patch = (endpoint: string, body: unknown, options: RequestInit = {}) =>
apiFetch(endpoint, { ...options, method: 'PATCH', body: JSON.stringify(body) })
const delete_ = (endpoint: string, body: unknown, options: RequestInit = {}) =>
apiFetch(endpoint, { ...options, method: 'DELETE', body: JSON.stringify(body) })
return {
get,
post,
patch,
delete: delete_,
fetch: apiFetch,
}
}

View File

@@ -5,11 +5,13 @@ import { useStore } from './useStore.ts'
export interface Settings {
accessKey: string
todayShown: boolean
theme: string
}
const settingsDefault: Settings = {
accessKey: '',
todayShown: false,
theme: 'default',
}
const settings = ref<Settings>({ ...settingsDefault })

View File

@@ -7,6 +7,7 @@ const tasks = ref<Task[]>([])
const isLoading = ref(false)
const error = ref<string | null>(null)
const endpoint = '/items/pomodays'
const refreshInterval = ref<number>()
export function useTasks() {
const api = useApi()
@@ -18,7 +19,7 @@ export function useTasks() {
error.value = null
try {
const data = await api.get(`${endpoint}?limit=-1`).then(res => res.json())
tasks.value = data.tasks ?? []
tasks.value = data.data ?? []
}
catch (e: any) {
error.value = e.message || 'Failed to fetch tasks'
@@ -29,12 +30,15 @@ export function useTasks() {
}
}
if (refreshInterval.value === undefined) {
refreshInterval.value = setInterval(() => fetchTasks(true), 1000 * 60)
}
const createTask = async (taskData: Pick<Task, 'title' | 'due_date' | 'tag'>) => {
isLoading.value = true
error.value = null
try {
await api.post(endpoint, { ...taskData }).then(res => res.json())
await fetchTasks()
}
catch (e: any) {
error.value = e.message || 'Failed to create task'
@@ -46,12 +50,14 @@ export function useTasks() {
}
}
const updateTask = async (task: Task) => {
const updateTask = async (tasks: Task | Task[]) => {
isLoading.value = true
error.value = null
const tasksToUpdate = Array.isArray(tasks) ? tasks : [tasks]
try {
await api.patch(`${endpoint}/${task.id}`, task).then(res => res.json())
await fetchTasks()
for (const task of tasksToUpdate) {
await api.patch(`${endpoint}/${task.id}`, task)
}
}
catch (e: any) {
error.value = e.message || 'Failed to update task'
@@ -63,12 +69,12 @@ export function useTasks() {
}
}
const updateTasks = async (data: Partial<Task>, keys: Task['id'][]) => {
const deleteTask = async (tasks: Task | Task[]) => {
isLoading.value = true
error.value = null
const taskIdsToDelete = (Array.isArray(tasks) ? tasks : [tasks]).map(task => task.id)
try {
await api.patch(`${endpoint}`, { data, keys }).then(res => res.json())
await fetchTasks()
await api.delete(endpoint, taskIdsToDelete)
}
catch (e: any) {
error.value = e.message || 'Failed to update task'
@@ -89,7 +95,7 @@ export function useTasks() {
fetchTasks,
createTask,
updateTask,
updateTasks,
deleteTask,
categories,
}
}