'use client'; import { useState, useEffect } from 'react'; import TodoList from '@/components/TodoList'; import FilterButtons from '@/components/FilterButtons'; // Todo型の定義 type Todo = { id: number; text: string; completed: boolean; }; type FilterType = 'all' | 'active' | 'completed'; export default function Home() { // Local Storage のキー const STORAGE_KEY = 'todo-app-data'; // Todoリスト本体の状態管理 const [todos, setTodos] = useState([]); // 入力欄の状態管理 const [inputValue, setInputValue] = useState(''); // 削除確認ダイアログの表示状態 const [showConfirm, setShowConfirm] = useState(false); // 削除対象のTodoのID const [targetId, setTargetId] = useState(null); // 空欄入力時の警告ダイアログ表示状態 const [showInputAlert, setShowInputAlert] = useState(false); // 編集機能のための状態管理 const [editingId, setEditingId] = useState(null); // 編集中のテキスト const [editText, setEditText] = useState(''); // フィルター状態の管理(全て、未完了、完了) const [filter, setFilter] = useState('all'); // フィルターに応じたTodoの数をカウント const activeCount = todos.filter(todo => !todo.completed).length; const completedCount = todos.filter(todo => todo.completed).length; const startEdit = (todo: Todo) => { setEditingId(todo.id); setEditText(todo.text); }; const saveEdit = () => { if (editText.trim() === '') { alert('TODOが空です'); return; } const updatedTodos = todos.map(todo => { if (todo.id === editingId) { return { ...todo, text: editText }; } return todo; }); setTodos(updatedTodos); setEditingId(null); setEditText(''); }; // 新しいTODOを追加する関数 const addTodo = () => { if (inputValue.trim() === '') { setShowInputAlert(true); return; } const newTodo: Todo = { id: Date.now(), text: inputValue, completed: false }; setTodos([...todos, newTodo]); setInputValue(''); }; const cancelEdit = () => { setEditingId(null); setEditText(''); }; // フォーム送信時の処理 const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); addTodo(); }; // Todoの完了状態をトグルする関数 const toggleTodo = (id: number) => { const updatedTodos = todos.map(todo => { if (todo.id === id) { return { ...todo, completed: !todo.completed }; } return todo; }); setTodos(updatedTodos); }; // 削除ボタンが押されたときの処理(確認ダイアログ表示) const handleDeleteClick = (id: number) => { setShowConfirm(true); setTargetId(id); }; // ダイアログで「はい」が押されたときの本削除処理 const confirmDelete = () => { if (targetId !== null) { setTodos(todos.filter(todo => todo.id !== targetId)); setShowConfirm(false); setTargetId(null); } }; // ダイアログで「いいえ」が押されたときの処理 const cancelDelete = () => { setShowConfirm(false); setTargetId(null); }; // 空欄入力時ダイアログを閉じる関数 const closeInputAlert = () => { setShowInputAlert(false); }; // 完了済みTODOをすべて削除 const clearCompleted = () => { setTodos(todos.filter(todo => !todo.completed)); }; // アプリ起動時にデータを読み込み useEffect(() => { const savedTodos = localStorage.getItem(STORAGE_KEY); if (savedTodos) { try { const parsedTodos = JSON.parse(savedTodos); setTodos(parsedTodos); } catch (error) { console.error('データの読み込みに失敗しました:', error); } } }, []); // TODOが変更されるたびに保存 useEffect(() => { localStorage.setItem(STORAGE_KEY, JSON.stringify(todos)); }, [todos]); // データのエクスポート機能 const exportData = () => { const dataStr = JSON.stringify(todos, null, 2); const dataBlob = new Blob([dataStr], { type: 'application/json' }); const url = URL.createObjectURL(dataBlob); const link = document.createElement('a'); link.href = url; link.download = 'todos.json'; link.click(); URL.revokeObjectURL(url); }; // データのインポート機能 const importData = (event: React.ChangeEvent) => { const file = event.target.files?.[0]; if (file) { const reader = new FileReader(); reader.onload = (e) => { try { const importedTodos = JSON.parse(e.target?.result as string); setTodos(importedTodos); } catch (error) { alert('ファイルの読み込みに失敗しました'); } }; reader.readAsText(file); } }; return (
{/* ヘッダー部分にエクスポート・インポート機能を追加 */}

TODOアプリ

{/* 入力フォーム */}
setInputValue(e.target.value)} placeholder="TODOを入力してEnterキー" className="w-full p-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" />
{/* フィルターボタン */} {/* TODOリスト */} {/* 確認ダイアログ */} {showConfirm && (

本当に削除しますか?

)} {/* 空欄入力時のカスタムダイアログ */} {showInputAlert && (

TODOを入力してください

)}
); }