diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 82bce23..2f0c096 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -11,6 +11,9 @@ import RegisterPage from './pages/RegisterPage'; import TaskListPage from './pages/TaskListPage'; import StockPage from './pages/StockPage'; import './App.css'; +// 必要なインポートを追加 +import AddDishes1 from './pages/AddDishes1'; +import AddDishes2 from './pages/AddDishes2'; /** * アプリケーション全体のMaterial UIテーマを定義 @@ -94,6 +97,23 @@ const App: React.FC = () => { } /> + {/* テストページへのルートを追加 */} + + + + } + /> + + + + } + /> }> {/* ルートパスへのアクセスはタスク一覧にリダイレクト */} diff --git a/frontend/src/components/Layout.tsx b/frontend/src/components/Layout.tsx index 4ac785b..c4a8739 100644 --- a/frontend/src/components/Layout.tsx +++ b/frontend/src/components/Layout.tsx @@ -103,6 +103,13 @@ const Layout: React.FC = () => { {/* テストページへのリンクを追加 */} {/* 在庫リストへのリンクを追加 */} + handleNavigate('/add1')} + selected={isSelected('/add1')} + > + + + handleNavigate('/stock')} selected={isSelected('/stock')} diff --git a/frontend/src/pages/AddDishes1.tsx b/frontend/src/pages/AddDishes1.tsx new file mode 100644 index 0000000..d003ebd --- /dev/null +++ b/frontend/src/pages/AddDishes1.tsx @@ -0,0 +1,82 @@ +import React, { useState } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { + AppBar, + Toolbar, + Typography, + Container, + Box, + Button, + Drawer, + List, + ListItemText, + ListItemIcon, + ListItemButton, + Divider, + IconButton, + TextField, + Paper, + Alert, + Link, + Grid, + } from '@mui/material'; + import { LoginCredentials } from '../types/types'; +import { authApi } from '../services/api'; +import { GENERAL_ERRORS } from '../constants/errorMessages'; + +const AddDishes1: React.FC = () => { + const navigate = useNavigate(); + const [dish, setDish] = useState(""); + // エラーメッセージの状態管理 + const [error, setError] = useState(false); + + const handleChange = (event: React.ChangeEvent) => { + setDish(event.target.value); + }; + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); // フォームのデフォルト送信動作を防止 + if (!dish.trim()) { + alert("エラー"); + setError(true); + } else { + alert("送信成功!"); + localStorage.setItem("dishName", dish); // ローカルストレージにフォームに入力された料理名を保存 + navigate('/add2', { state: dish }); // 料理名から材料名追加ページにリダイレクト + } + }; + + return ( +
+ + 料理の追加・編集 + + +
+ +
+
+ +
+
+
+ ); +}; + +export default AddDishes1; \ No newline at end of file diff --git a/frontend/src/pages/AddDishes2.tsx b/frontend/src/pages/AddDishes2.tsx new file mode 100644 index 0000000..2e319d9 --- /dev/null +++ b/frontend/src/pages/AddDishes2.tsx @@ -0,0 +1,278 @@ +/** + * テストページコンポーネント + * 白紙の状態で表示されるテスト用のページ + */ +import React, { useState, useEffect } from 'react'; +import { taskApi } from '../services/api'; +import { + Container, + Typography, + Tooltip, + List, + ListItem, + ListItemText, + ListItemSecondaryAction, + IconButton, + Checkbox, + Fab, + Dialog, + DialogTitle, + DialogContent, + DialogActions, + TextField, + Button, + Box, + MenuItem, + Select, + FormControl, + InputLabel +} from '@mui/material'; +import { + Add as AddIcon, Delete as DeleteIcon, ShoppingBasket as ShoppingBasketIcon, + SoupKitchen as SoupKitchenIcon +} from '@mui/icons-material'; +import { Task } from '../types/types'; +import { TASK_ERRORS } from '../constants/errorMessages'; +import { GENERAL_ERRORS } from '../constants/errorMessages'; +import CategoryDropDown from "../components/CategoryDropDown"; + +// 新規タスクの初期状態(画面表示用) +const EMPTY_TASK = { id: 0, title: '', amount: 0, completed: false }; + +// 新規タスクの初期状態(データベース登録用) +const EMPTY_TASK_DATA_BASE = { id: 0, title: '', amount: 0, completed: false }; + +interface Empty_Task { + title: string; // 食材名 + amount: number; // 食材の個数 + completed: boolean; // +} + +const AddDishes2: React.FC = () => { + const receivedData = localStorage.getItem("dishName"); + // タスク一覧の状態管理 + const [tasks, setTasks] = useState([]); + + const [addtasks, setAddTasks] = useState([]); + // エラーメッセージの状態管理 + const [error, setError] = useState(false); + // 新規タスク作成ダイアログの表示状態 + const [openDialog, setOpenDialog] = useState(false); + // 新規タスクの入力内容 + const [newTask, setNewTask] = useState(EMPTY_TASK); + + // コンポーネントマウント時にタスク一覧を取得 + useEffect(() => { + fetchTasks(); + }, []); + + /** + * APIからタスク一覧を取得する関数 + * 取得したタスクをstate(tasks)に設定 + */ + const fetchTasks = async () => { + try { + const tasks = await taskApi.getTasks(); + setTasks(tasks); + } catch (error) { + console.error(`${TASK_ERRORS.FETCH_FAILED}:`, error); + } + }; + /** + * タスクを削除するハンドラー + * 指定されたIDのタスクをAPIを通じて削除 + */ + const handleDeleteTask = async (index: number) => { + try { + let newAddTasks = [...addtasks]; // 配列をコピー + newAddTasks.splice(index, 1); + setAddTasks(newAddTasks); + // fetchTasks(); // 削除後のタスク一覧を再取得 + } catch (error) { + console.error(`${TASK_ERRORS.DELETE_FAILED}:`, error); + } + }; + + /** + * 新規タスクを作成するハンドラー + * 入力されたタスク情報をAPIに送信して新規作成 + * 作成後はダイアログを閉じ、入力内容をリセット + */ + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); // フォームのデフォルト送信動作を防止 + if (addtasks[0] == null) { + setError(true); + alert("食材を追加してください"); + } else { + alert("送信成功!"); + handleCreateTask_DataBase(); + // localStorage.setItem("dishName", dish); // ローカルストレージにフォームに入力された料理名を保存 + // navigate('/add2', { state: dish }); // 料理名から材料名追加ページにリダイレクト + } + }; + const handleCreateTask_Temp = async () => { + try { + // await taskApi.createTask(newTask); + let newAddTasks = [...addtasks]; // 配列をコピー + newAddTasks.push(newTask); + setAddTasks(newAddTasks); + setOpenDialog(false); // ダイアログを閉じる + setNewTask(EMPTY_TASK); // 入力内容をリセット + // fetchTasks(); // 作成後のタスク一覧を再取得 + } catch (error) { + console.error(`${TASK_ERRORS.CREATE_FAILED}:`, error); + } + }; + + const handleCreateTask_DataBase = async () => { + try { + for (let i = 0; i < addtasks.length; i++) { + await taskApi.createTask(addtasks[i]); + } + setOpenDialog(false); // ダイアログを閉じる + setNewTask(EMPTY_TASK); // 入力内容をリセット + // fetchTasks(); // 作成後のタスク一覧を再取得 + } catch (error) { + console.error(`${TASK_ERRORS.CREATE_FAILED}:`, error); + } + }; + + return ( + +
+

追加する料理名

+

{receivedData}

+
+ + {/* タスク一覧をマップして各タスクをリストアイテムとして表示 */} + {addtasks.map((task, index) => ( + + {/* タスク完了状態を切り替えるチェックボックス + handleToggleComplete(task.id)} + /> */} + {/* タスクのタイトルと説明 - 完了状態に応じて取り消し線を表示 */} + + {/* 食材の個数を表示 */} + 個数
+ {task.amount} + + } + // secondary={task.description} + primaryTypographyProps={{ align: "right", marginRight: "20%", fontSize: "20px" }} + /> + {/* 買い物リスト:食材情報記入ボタン */} + + + handleDeleteTask(task.id)} + > + + + + {/* 買い物リスト:食材削除ボタン */} + + + handleDeleteTask(index)} + > + + + + + +
+ ))} +
+
+ +
+
+ +
+ {/* 新規タスク作成ダイアログ */} + setOpenDialog(false)} disableScrollLock={true}> + 材料の追加 + + + {/*材料カテゴリ選択 */} + + {/* タスクタイトル入力フィールド */} + setNewTask({ ...newTask, title: e.target.value })} + sx={{ marginBottom: 2 }} + /> + {/* 数量入力フィールド */} + { + const value = e.target.value; + const parsedValue = parseInt(value, 10); // 数値に変換 + if (!isNaN(parsedValue)) { + setNewTask({ ...newTask, amount: parsedValue }); // number型で保存 + } + }} + sx={{ width: "20%" }} + type="number" + inputProps={{ inputMode: "numeric", pattern: "[0-9]*" }} // ここで整数のみ許可 + /> + + + + + + + +
+ ); +}; + +export default AddDishes2; \ No newline at end of file diff --git a/frontend/src/pages/TestPage.tsx b/frontend/src/pages/TestPage.tsx new file mode 100644 index 0000000..f6d70be --- /dev/null +++ b/frontend/src/pages/TestPage.tsx @@ -0,0 +1,12 @@ +import React from 'react'; +import { Box } from '@mui/material'; + +const TestPage: React.FC = () => { + return ( + + {/* 白紙のページ - 何も表示しない */} + + ); +}; + +export default TestPage; \ No newline at end of file