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 <noreply@anthropic.com>
This commit is contained in:
2026-02-19 15:48:16 +01:00
parent aa2ca9aec3
commit 24e9883f68
+140
View File
@@ -8,6 +8,10 @@
import Header from '$lib/components/Header.svelte'; import Header from '$lib/components/Header.svelte';
import TaskList from '$lib/components/TaskList.svelte'; import TaskList from '$lib/components/TaskList.svelte';
import InputBar from '$lib/components/InputBar.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'; let activeReport = 'list';
/** @type {import('$lib/api/types.js').Task[]} */ /** @type {import('$lib/api/types.js').Task[]} */
@@ -15,6 +19,21 @@
let loading = true; let loading = true;
let inputError = ''; 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 // Subscribe to store
const unsubscribe = tasksStore.subscribe(value => { const unsubscribe = tasksStore.subscribe(value => {
tasks = value; tasks = value;
@@ -124,12 +143,98 @@
* @param {string} uuid * @param {string} uuid
*/ */
async function handleComplete(uuid) { async function handleComplete(uuid) {
const task = tasks.find(t => t.uuid === uuid);
if (!task) return;
try { try {
await tasksStore.complete(uuid); await tasksStore.complete(uuid);
// Show undo toast
undoToast = { uuid: task.uuid, description: task.description };
} catch (error) { } catch (error) {
console.error('Failed to complete task:', 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<import('$lib/api/types.js').Task>} 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;
}
</script> </script>
<Header {activeReport} onReportChange={handleReportChange} /> <Header {activeReport} onReportChange={handleReportChange} />
@@ -139,9 +244,44 @@
{loading} {loading}
{activeReport} {activeReport}
onComplete={handleComplete} onComplete={handleComplete}
onTap={(task) => selectedTask = task}
onStartStop={handleStartStop}
/> />
<InputBar <InputBar
onSubmit={handleSubmit} onSubmit={handleSubmit}
error={inputError} error={inputError}
/> />
<BottomSheet open={selectedTask !== null} onClose={() => selectedTask = null}>
{#if selectedTask}
<TaskDetail
task={selectedTask}
onUpdate={handleUpdate}
onStart={(uuid) => handleStartStop(uuid)}
onStop={(uuid) => handleStartStop(uuid)}
onDelete={handleDeleteRequest}
onComplete={handleComplete}
onClose={() => selectedTask = null}
/>
{/if}
</BottomSheet>
{#if undoToast}
<Toast
message={'Completed "' + undoToast.description + '"'}
action={{ label: 'Undo', handler: handleUndo }}
onDismiss={() => undoToast = null}
/>
{/if}
<ConfirmDialog
bind:this={confirmDialog}
title="Delete task?"
message={deleteTarget?.description ?? ''}
detail="This cannot be undone."
confirmLabel="Delete"
confirmVariant="danger"
onConfirm={handleDeleteConfirm}
onCancel={handleDeleteCancel}
/>