import React, { ReactElement, useState, useRef, useEffect } from 'react'; function dateInputValueToTs(s: string): number { const [y, mo, day] = s.split('-').map(Number); return new Date(y, mo - 1, day).getTime(); } import { useLiveQuery } from 'dexie-react-hooks'; import { createTodo, fromDBPage, } from '../../db/pages'; import { db } from '../../db/db'; import { logger } from '../../utils/logger'; import { Button, Checkbox, Input, Sheet, Stack, Select, Option, Typography, } from '@mui/joy'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faPlus } from '@fortawesome/free-solid-svg-icons'; import PageRow from '../flexView/pagelists/pagerow/PageRow'; const TodoView = (): ReactElement => { const [showCompleted, setShowCompleted] = useState(false); const [addingNew, setAddingNew] = useState(false); const [newTitle, setNewTitle] = useState(''); const [newPriority, setNewPriority] = useState(null); const [newDueDate, setNewDueDate] = useState(''); const [addError, setAddError] = useState(null); const newTitleRef = useRef(null); const todos = useLiveQuery( () => showCompleted ? db.pages.where('completionStatus').anyOf(['pending', 'completed']).toArray() : db.pages.where('completionStatus').equals('pending').toArray(), [showCompleted] ); const sorted = (todos ?? []).slice().sort((a, b) => { const pa = a.priority ?? 999; const pb = b.priority ?? 999; if (pa !== pb) return pa - pb; const ca = a.creationDate ?? 0; const cb = b.creationDate ?? 0; return cb - ca; }); useEffect(() => { if (addingNew) { newTitleRef.current?.focus(); } }, [addingNew]); const handleAdd = async () => { const title = newTitle.trim(); if (!title) return; const dueDate = newDueDate ? dateInputValueToTs(newDueDate) : undefined; setAddError(null); try { await createTodo(title, newPriority ?? undefined, dueDate); setNewTitle(''); setNewPriority(null); setNewDueDate(''); setAddingNew(false); } catch (e: unknown) { logger.error('[TodoView] createTodo failed', e); setAddError(e instanceof Error ? e.message : 'Failed to create todo'); } }; const handleNewKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter') { void handleAdd(); } else if (e.key === 'Escape') { setAddingNew(false); setNewTitle(''); setNewPriority(null); setNewDueDate(''); setAddError(null); } }; return ( setShowCompleted(e.target.checked)} /> {addingNew && ( setNewTitle(e.target.value)} onKeyDown={handleNewKeyDown} slotProps={{ input: { ref: newTitleRef } }} sx={{ flex: 1 }} /> setNewDueDate(e.target.value)} sx={{ width: 140 }} /> )} {addError && ( {addError} )} {sorted.length === 0 && !addingNew && ( No todos yet. Click "Add Todo" to create one. )} {sorted.map((todo) => ( ))} ); }; export default TodoView;