/** * タスク一覧を表示・管理するページコンポーネント * タスクの表示、作成、完了状態の切り替え、削除などの機能を提供 */ import React, { useState, useEffect } from 'react'; import { stockApi, toBuyApi } from '../services/api'; import { Container, Typography, Tooltip, List, ListItem, ListItemText, ListItemSecondaryAction, IconButton, Fab, Box, Dialog, DialogTitle, DialogContent, Button, } from '@mui/material'; import { Add as AddIcon, Delete as DeleteIcon, ShoppingBasket as ShoppingBasketIcon, SoupKitchen as SoupKitchenIcon, Edit as EditIcon } from '@mui/icons-material'; import { ToBuy, Stuff, NewToBuy, NewStock, StuffAndCategoryAndAmount, StuffNameAndAmount, StockHistory, /*Stock*/ } from '../types/types'; import { GENERAL_ERRORS, TOBUY_ERRORS } from '../constants/errorMessages'; import EditAmountDialog from '../components/EditAmountDialog'; import AddStuffAmountDialog from '../components/AddStuffAmountDialog'; import BuyDialog from '../components/BuyDialog'; import { useNavigate } from 'react-router-dom'; import DatePicker from 'react-datepicker'; import { useMessage } from '../components/MessageContext'; import StuffHistoryDialog from '../components/StuffHistoryDialog'; //import { FaCarrot } from "react-icons/fa6"; //エラー起きる いったん保留 // 新規タスクの初期状態 const EMPTY_TOBUY: NewToBuy = { stuffId: null, stuffName: '', amount: 1, shop: '', category: '', } const TaskListPage: React.FC = () => { const navigate = useNavigate(); // タスク一覧の状態管理 const [tobuys, setToBuys] = useState([]); // 買うものリストへの食材追加ダイアログの表示状態 const [openAddToBuyDialog, setOpenAddToBuyDialog] = useState(false); //在庫登録ダイアログの表示状態 const [openInfoDialog, setOpenInfoDialog] = useState(false); //数量変更ダイアログの表示状態 const [openAmountDialog, setOpenAmountDialog] = useState(false); const [selectedToBuyId, setSelectedToBuyId] = useState(0); const [newStock, setNewStock] = useState({ amount: '', // 購入数量(ここではstring) price: '', // ここではstring shop: '', buyDate: new Date().toISOString(), expDate: '', }); //削除確認ダイアログの表示状態 const [openDeleteDialog, setOpenDeleteDialog] = useState(false); const [selectedTask, setSelectedTask] = useState(0); // 編集対象の項目 const [editingItem, setEditingItem] = useState({ tobuyId: 0, stuffId: 0, stuffName: "", amount: 0, shop: undefined, }); const [newToBuy, setNewToBuy] = useState(EMPTY_TOBUY); const [selectedDeleteTask, setSelectedDeleteTask] = useState({ tobuyId: 0, stuffId: 0, stuffName: "", amount: 0, shop: undefined, }); const { showErrorMessage } = useMessage(); // コンポーネントマウント時にタスク一覧を取得 useEffect(() => { fetchTasks(); }, []); /** * APIからタスク一覧を取得する関数 * 取得したタスクをstate(tasks)に設定 */ const fetchTasks = async () => { try { const tobuys = await toBuyApi.getToBuys(); console.log(tobuys); setToBuys(tobuys); } catch (error) { console.error(`${TOBUY_ERRORS.FETCH_FAILED}:`, error); } }; // /** // * タスクの完了状態を切り替えるハンドラー // * 対象タスクの完了状態を反転させてAPIに更新を要求 // */ // const handleToggleComplete = async (taskId: number) => { // try { // const task = tasks.find(t => t.id === taskId); // if (!task) return; // await toBuyApi.updateTask(taskId, { ...task, completed: !task.completed }); // fetchTasks(); // 更新後のタスク一覧を再取得 // } catch (error) { // console.error(`${TASK_ERRORS.UPDATE_FAILED}:`, error); // } // }; /** * 買うものを削除するハンドラー * 指定されたIDのタスクをAPIを通じて削除 */ const handleDeleteToBuy = async (toBuyId: number) => { try { await toBuyApi.deleteToBuy(toBuyId); fetchTasks(); // 削除後の買うもの一覧を再取得 } catch (error) { console.error(`${TOBUY_ERRORS.DELETE_FAILED}:`, error); } }; /** * 買うものリストへの材料追加を行う * 入力された買うもの情報をAPIに送信して新規作成 * 作成後はダイアログを閉じ、入力内容をリセット */ const handleAddNewToBuy = async () => { try { if (isNaN(newToBuy.amount)) { showErrorMessage(GENERAL_ERRORS.INVALID_AMOUNT); return; } newToBuy.stuffName = newToBuy.stuffName.trim(); // 材料名の前後の空白を削除 if (!newToBuy.stuffName) { showErrorMessage(GENERAL_ERRORS.INVALID_STUFF_NAME); return; } console.log(newToBuy) await toBuyApi.addToBuy(newToBuy); setOpenAddToBuyDialog(false); // ダイアログを閉じる setNewToBuy(EMPTY_TOBUY); // 入力内容をリセット fetchTasks(); // 作成後のタスク一覧を再取得 } catch (error) { console.error(`${TOBUY_ERRORS.CREATE_FAILED}:`, error); } }; /** * 買い物リストの数量を変更するハンドラー * 入力されたタスク情報をAPIに送信して変更 * 作成後はダイアログを閉じ、入力内容をリセット */ const handleUpdateNewToBuy = async () => { try { if (isNaN(editingItem.amount)) { showErrorMessage(GENERAL_ERRORS.INVALID_AMOUNT); return; } console.log(editingItem) await toBuyApi.updateToBuy(editingItem); setOpenAmountDialog(false); // ダイアログを閉じる //setNewToBuy(EMPTY_TOBUY); // 入力内容をリセット fetchTasks(); // 作成後のタスク一覧を再取得 } catch (error) { console.error(`${TOBUY_ERRORS.CREATE_FAILED}:`, error); } }; /** * 買うものリストの在庫登録(購入処理)を行うハンドラー */ const handleBuy = async () => { try { const today = new Date().toISOString().substring(0, 10); const parsedPrice = parseInt(newStock.price, 10); console.log("newPrice:", newStock.price) console.log("parsedPrice: ", parsedPrice) if (isNaN(parsedPrice)) { showErrorMessage(GENERAL_ERRORS.INVALID_PRICE) return //setNewStock({ ...newStock, price: parsedPrice }); } const amount = parseInt(newStock.amount, 10); if (isNaN(amount)) { showErrorMessage('購入数量が正しく入力されていません。') return } await toBuyApi.buy({ tobuyId: selectedToBuyId, ...newStock, amount, price: parsedPrice, lastUpdate: today }); //データベースに送信 setOpenInfoDialog(false); fetchTasks(); // 変更後後の買うもの一覧を再取得 } catch (error) { console.error(`${TOBUY_ERRORS.BUY_FAILED}:`, error); } }; //履歴表示ダイアログ const [openHistoryDialog, setOpenHistoryDialog] = useState(false); const [historyTobuy, setHistoryTobuy] = useState(null); const [stockHistories, setStockHistories] = useState(null); const handleShowHistories = async (tobuy: ToBuy) => { console.log('handleShowHistories:', tobuy); try { setHistoryTobuy(tobuy); setStockHistories(await stockApi.getHistories(tobuy.stuffId)); setOpenHistoryDialog(true); } catch { showErrorMessage("履歴の読み込みに失敗しました。"); } } return ( 買うものリスト {/* タスク一覧表示エリア - 青い背景のコンテナ */}
{/* タスク一覧をマップして各タスクをリストアイテムとして表示 */} {tobuys && tobuys.map((tobuy) => ( {/* 食材名 */} handleShowHistories(tobuy)} /> {/* 買い物リスト:食材情報記入ボタン */} {`× ${tobuy.amount}`} {/* 買い物リスト:数量変更ボタン */} { setOpenAmountDialog(true) setEditingItem(tobuy) }} > {/* 買い物リスト:食材情報記入ボタン */} { setOpenInfoDialog(true) setEditingItem(tobuy) setNewStock({ ...newStock, amount: String(tobuy.amount) }); setSelectedToBuyId(tobuy.tobuyId) // handleDeleteTask(tobuy.tobuyId) }}> {/* 買い物リスト:食材削除ボタン */} {//handleDeleteTask(tobuy.tobuyId) setSelectedDeleteTask(tobuy) setOpenDeleteDialog(true) } } > ))}
{/* 新規材料作成ボタン - 画面下部に固定表示 */} 材料の追加 setOpenAddToBuyDialog(true)} > {/*新規料理追加ボタン - 画面下部に固定表示 */} {/* 料理から追加 { // setOpenAddToBuyDialog(true); navigate('/RecipeList'); }} //selected={isSelected('/test')} > */} {/* 買うものリストへの材料追加ダイアログ */} {/* 購入処理(在庫登録)のための数値入力ダイアログ */} {/* 数量変更ダイアログ */} setEditingItem({ ...editingItem, ...v })} onSubmit={handleUpdateNewToBuy} /> {/* 削除ダイアログ */} setOpenDeleteDialog(false)} disableScrollLock={true} fullWidth maxWidth="sm" sx={{ overflow: "hidden" }} > 食材の削除 {selectedDeleteTask && ( <> {selectedDeleteTask.stuffName}を削除します。 ⚠️ 注意: 削除すると復元できません。 )} {/* 履歴表示ダイアログ */} { (historyTobuy !== null && stockHistories !== null) && }
); }; export default TaskListPage;