forked from semi-23e/nextjs-todo-tutorial
編集機能追加
This commit is contained in:
109
src/app/page.tsx
109
src/app/page.tsx
@@ -25,6 +25,36 @@ export default function Home() {
|
||||
// 空欄入力時の警告ダイアログ表示状態
|
||||
const [showInputAlert, setShowInputAlert] = useState(false); // 空欄警告フラグ
|
||||
|
||||
// 編集機能のための状態管理
|
||||
const [editingId, setEditingId] = useState<number | null>(null);
|
||||
|
||||
// 編集中のテキスト
|
||||
const [editText, setEditText] = useState('');
|
||||
|
||||
|
||||
const startEdit = (todo: Todo) => { // 編集開始関数
|
||||
setEditingId(todo.id); // 編集対象のIDをセット
|
||||
setEditText(todo.text); // 編集用のテキストをセット
|
||||
};
|
||||
|
||||
const saveEdit = () => { // 編集内容を保存する関数
|
||||
if (editText.trim() === '') { // 編集内容が空欄だったら警告ダイアログ表示
|
||||
alert('TODOが空です'); // 簡易的なアラート表示
|
||||
return; // 空欄の場合は保存しない
|
||||
}
|
||||
|
||||
const updatedTodos = todos.map(todo => { // Todoリストを更新
|
||||
if (todo.id === editingId) { // 編集対象のTodoを見つけたら
|
||||
return { ...todo, text: editText }; // 編集内容で更新
|
||||
}
|
||||
return todo; // 他のTodoはそのまま返す
|
||||
});
|
||||
|
||||
setTodos(updatedTodos); // 更新されたTodoリストをセット
|
||||
setEditingId(null); // 編集モードを終了
|
||||
setEditText(''); // 編集用テキストをクリア
|
||||
};
|
||||
|
||||
// 新しいTODOを追加する関数
|
||||
const addTodo = () => {
|
||||
// 入力が空欄だったら警告ダイアログ表示
|
||||
@@ -42,6 +72,11 @@ export default function Home() {
|
||||
setInputValue(''); // 入力欄をクリア
|
||||
};
|
||||
|
||||
const cancelEdit = () => { // 編集キャンセル関数
|
||||
setEditingId(null); // 編集モードを終了
|
||||
setEditText(''); // 編集用テキストをクリア
|
||||
};
|
||||
|
||||
// フォーム送信時の処理
|
||||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => { // フォーム送信イベント
|
||||
e.preventDefault(); // ページリロード防止
|
||||
@@ -107,26 +142,74 @@ export default function Home() {
|
||||
追加
|
||||
</button>
|
||||
</form>
|
||||
|
||||
{/* TODOリスト */}
|
||||
<div className="space-y-2">
|
||||
{todos.map((todo) => (
|
||||
<div key={todo.id} className="flex items-center p-3 bg-gray-50 rounded-lg hover:bg-gray-100 transition-colors">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={todo.completed} // 完了状態を反映
|
||||
onChange={() => toggleTodo(todo.id)} // チェックボックス変更時に完了状態をトグル
|
||||
checked={todo.completed}
|
||||
onChange={() => toggleTodo(todo.id)}
|
||||
className="mr-3 h-5 w-5 cursor-pointer"
|
||||
/>
|
||||
<span className={`flex-1 ${todo.completed ? 'line-through text-gray-500' : 'text-gray-800'}`}>
|
||||
{todo.text}
|
||||
</span>
|
||||
<button
|
||||
onClick={() => handleDeleteClick(todo.id)} // 削除ボタン押下時に確認ダイアログ表示
|
||||
className="text-red-500 hover:text-red-700 ml-2 px-2 py-1 rounded transition-colors"
|
||||
>
|
||||
削除
|
||||
</button>
|
||||
|
||||
{editingId === todo.id ? (
|
||||
// 編集モード
|
||||
<input
|
||||
type="text"
|
||||
value={editText}
|
||||
onChange={(e) => setEditText(e.target.value)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') saveEdit();
|
||||
if (e.key === 'Escape') cancelEdit();
|
||||
}}
|
||||
className="flex-1 border border-blue-500 p-2 rounded focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
autoFocus
|
||||
/>
|
||||
) : (
|
||||
// 通常モード
|
||||
<span
|
||||
onClick={() => startEdit(todo)}
|
||||
className={`flex-1 cursor-pointer p-2 rounded hover:bg-gray-200 transition-colors ${
|
||||
todo.completed ? 'line-through text-gray-500' : 'text-gray-800'
|
||||
}`}
|
||||
>
|
||||
{todo.text}
|
||||
</span>
|
||||
)}
|
||||
|
||||
{editingId === todo.id ? (
|
||||
// 編集モードのボタン
|
||||
<div className="flex gap-2 ml-2">
|
||||
<button
|
||||
onClick={saveEdit}
|
||||
className="text-green-600 hover:text-green-800 px-2 py-1 rounded transition-colors"
|
||||
>
|
||||
保存
|
||||
</button>
|
||||
<button
|
||||
onClick={cancelEdit}
|
||||
className="text-gray-600 hover:text-gray-800 px-2 py-1 rounded transition-colors"
|
||||
>
|
||||
キャンセル
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
// 通常モードのボタン
|
||||
<div className="flex gap-2 ml-2">
|
||||
<button
|
||||
onClick={() => startEdit(todo)}
|
||||
className="text-blue-500 hover:text-blue-700 px-2 py-1 rounded transition-colors"
|
||||
>
|
||||
編集
|
||||
</button>
|
||||
<button
|
||||
onClick={() => handleDeleteClick(todo.id)} // ←ここをdeleteTodoからhandleDeleteClickに修正
|
||||
className="text-red-500 hover:text-red-700 px-2 py-1 rounded transition-colors"
|
||||
>
|
||||
削除
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user