diff --git a/team_product/src/public/app.js b/team_product/src/public/app.js index 91e0dfb..528c567 100644 --- a/team_product/src/public/app.js +++ b/team_product/src/public/app.js @@ -4,7 +4,7 @@ * このコードはブラウザ上で動作します。 * ログはブラウザのF12(開発者ツール)に表示されます。 * - * 現在の機能: Create(追加)、Read(一覧表示) + * 現在の機能: Create(追加)、Read(一覧表示)、Update(編集) */ // ===================================================== @@ -52,27 +52,27 @@ async function loadItems() { * アイテムを追加 * * IPO: - * - Input: テキストボックスのタイトル + * - Input: テキストボックスのname * - Process: サーバーにPOSTリクエスト → DB保存 * - Output: 一覧を再読み込み */ async function addItem() { - const title = titleInput.value.trim() + const name = titleInput.value.trim() // 入力チェック(Client側のバリデーション) - if (!title) { - alert('タイトルを入力してください') + if (!name) { + alert('nameを入力してください') return } - console.log('[CLIENT] アイテムを追加:', title) + console.log('[CLIENT] アイテムを追加:', name) try { // サーバーにPOSTリクエスト const response = await fetch('/api/items', { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ title }) + body: JSON.stringify({ title: name }) }) if (!response.ok) { @@ -94,9 +94,47 @@ async function addItem() { } // ===================================================== -// ここに新しい機能(Delete, Updateなど)を追加していこう! +// Update機能 // ===================================================== +/** + * アイテム名(name)を更新 + * + * IPO: + * - Input: 編集ボタン押下後に入力されたname + * - Process: PUTリクエストでServerへ編集要求 → DB更新 + * - Output: 更新後一覧を再描画 + */ +async function updateItem(id, nameInput) { + const name = nameInput.value.trim() + + if (!name) { + alert('nameを入力してください') + return + } + + console.log('[CLIENT] アイテムを更新:', id, name) + + try { + const response = await fetch(`/api/items/${id}`, { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ name }) + }) + + if (!response.ok) { + const error = await response.json() + throw new Error(error.error) + } + + await loadItems() + console.log('[CLIENT] 更新完了') + } catch (error) { + console.error('[CLIENT] エラー:', error) + alert('更新に失敗しました: ' + error.message) + } +} + // ===================================================== // 画面描画関数 // ===================================================== @@ -115,22 +153,43 @@ function renderItems(items) { items.forEach(item => { const li = document.createElement('li') li.className = 'item' - li.innerHTML = ` - ${escapeHtml(item.title)} - ` + + const nameText = document.createElement('span') + nameText.className = 'item-title' + nameText.textContent = item.title + + const actions = document.createElement('div') + actions.className = 'item-actions' + + const editButton = document.createElement('button') + editButton.className = 'item-button edit-button' + editButton.textContent = '編集' + editButton.addEventListener('click', () => { + const nameInput = document.createElement('input') + nameInput.type = 'text' + nameInput.className = 'edit-input' + nameInput.value = item.title + + const doneButton = document.createElement('button') + doneButton.className = 'item-button done-button' + doneButton.textContent = '完了' + doneButton.addEventListener('click', () => { + updateItem(item.id, nameInput) + }) + + actions.innerHTML = '' + li.replaceChild(nameInput, nameText) + actions.appendChild(doneButton) + nameInput.focus() + }) + + actions.appendChild(editButton) + li.appendChild(nameText) + li.appendChild(actions) itemList.appendChild(li) }) } -/** - * HTMLエスケープ(XSS対策) - */ -function escapeHtml(text) { - const div = document.createElement('div') - div.textContent = text - return div.innerHTML -} - // ===================================================== // イベントリスナー // ===================================================== diff --git a/team_product/src/public/index.html b/team_product/src/public/index.html index 5b52dc6..358c487 100644 --- a/team_product/src/public/index.html +++ b/team_product/src/public/index.html @@ -19,7 +19,7 @@