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:
@@ -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<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>
|
||||
|
||||
<Header {activeReport} onReportChange={handleReportChange} />
|
||||
@@ -139,9 +244,44 @@
|
||||
{loading}
|
||||
{activeReport}
|
||||
onComplete={handleComplete}
|
||||
onTap={(task) => selectedTask = task}
|
||||
onStartStop={handleStartStop}
|
||||
/>
|
||||
|
||||
<InputBar
|
||||
onSubmit={handleSubmit}
|
||||
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}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user