From 24e9883f68962ea9b8b48f5e79ac5ed1b01fbe9a Mon Sep 17 00:00:00 2001 From: Joakim Date: Thu, 19 Feb 2026 15:48:16 +0100 Subject: [PATCH] feat: integrate all Tier 1 features in page orchestrator Wire BottomSheet+TaskDetail, undo Toast, ConfirmDialog for delete, and start/stop handlers into +page.svelte. Co-Authored-By: Claude Opus 4.6 --- opal-web/src/routes/+page.svelte | 140 +++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/opal-web/src/routes/+page.svelte b/opal-web/src/routes/+page.svelte index e41ebb4..6b3415c 100644 --- a/opal-web/src/routes/+page.svelte +++ b/opal-web/src/routes/+page.svelte @@ -8,6 +8,10 @@ import Header from '$lib/components/Header.svelte'; import TaskList from '$lib/components/TaskList.svelte'; import InputBar from '$lib/components/InputBar.svelte'; + import BottomSheet from '$lib/components/BottomSheet.svelte'; + import TaskDetail from '$lib/components/TaskDetail.svelte'; + import Toast from '$lib/components/Toast.svelte'; + import ConfirmDialog from '$lib/components/ConfirmDialog.svelte'; let activeReport = 'list'; /** @type {import('$lib/api/types.js').Task[]} */ @@ -15,6 +19,21 @@ let loading = true; let inputError = ''; + // Bottom sheet state + /** @type {import('$lib/api/types.js').Task|null} */ + let selectedTask = null; + + // Undo toast state + /** @type {{ uuid: string, description: string }|null} */ + let undoToast = null; + + // Delete confirmation state + /** @type {{ uuid: string, description: string }|null} */ + let deleteTarget = null; + + /** @type {ConfirmDialog} */ + let confirmDialog; + // Subscribe to store const unsubscribe = tasksStore.subscribe(value => { tasks = value; @@ -124,12 +143,98 @@ * @param {string} uuid */ async function handleComplete(uuid) { + const task = tasks.find(t => t.uuid === uuid); + if (!task) return; + try { await tasksStore.complete(uuid); + // Show undo toast + undoToast = { uuid: task.uuid, description: task.description }; } catch (error) { console.error('Failed to complete task:', error); } } + + async function handleUndo() { + if (!undoToast) return; + const { uuid } = undoToast; + undoToast = null; + + try { + await tasksStore.updateTask(uuid, { status: 'P', end: null }); + await loadReport(activeReport); + } catch (error) { + console.error('Failed to undo completion:', error); + } + } + + /** + * @param {string} uuid + */ + async function handleStartStop(uuid) { + const task = tasks.find(t => t.uuid === uuid); + if (!task) return; + + try { + if (task.start) { + await tasksStore.stopTask(uuid); + } else { + await tasksStore.startTask(uuid); + } + // Update selectedTask if it's the same task + if (selectedTask?.uuid === uuid) { + const updated = tasks.find(t => t.uuid === uuid); + if (updated) selectedTask = updated; + } + } catch (error) { + console.error('Failed to start/stop task:', error); + } + } + + /** + * @param {string} uuid + * @param {Partial} updates + */ + async function handleUpdate(uuid, updates) { + try { + await tasksStore.updateTask(uuid, updates); + // Keep selectedTask fresh + if (selectedTask?.uuid === uuid) { + selectedTask = { ...selectedTask, ...updates }; + } + } catch (error) { + console.error('Failed to update task:', error); + } + } + + /** + * @param {string} uuid + */ + function handleDeleteRequest(uuid) { + const task = tasks.find(t => t.uuid === uuid) + ?? (selectedTask?.uuid === uuid ? selectedTask : null); + if (!task) return; + + deleteTarget = { uuid: task.uuid, description: task.description }; + confirmDialog.open(); + } + + async function handleDeleteConfirm() { + if (!deleteTarget) return; + const { uuid } = deleteTarget; + deleteTarget = null; + selectedTask = null; + + try { + await tasksStore.deleteTask(uuid); + } catch (error) { + console.error('Failed to delete task:', error); + } + } + + function handleDeleteCancel() { + deleteTarget = null; + }
@@ -139,9 +244,44 @@ {loading} {activeReport} onComplete={handleComplete} + onTap={(task) => selectedTask = task} + onStartStop={handleStartStop} /> + + selectedTask = null}> + {#if selectedTask} + handleStartStop(uuid)} + onStop={(uuid) => handleStartStop(uuid)} + onDelete={handleDeleteRequest} + onComplete={handleComplete} + onClose={() => selectedTask = null} + /> + {/if} + + +{#if undoToast} + undoToast = null} + /> +{/if} + +