From ec4669c92b5bb9b35c5c738428e606debdf9fb2f Mon Sep 17 00:00:00 2001 From: "masato.fujita" Date: Wed, 4 Jun 2025 11:04:31 +0900 Subject: [PATCH 1/5] =?UTF-8?q?=E3=83=86=E3=82=B9=E3=83=88=E3=83=9A?= =?UTF-8?q?=E3=83=BC=E3=82=B8=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/pages/TestPage.tsx | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 frontend/src/pages/TestPage.tsx 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 From 13cefbc829fd0c630d31f026a752d0ab0c7d6717 Mon Sep 17 00:00:00 2001 From: "masato.fujita" Date: Thu, 5 Jun 2025 09:53:26 +0900 Subject: [PATCH 2/5] =?UTF-8?q?=E6=96=99=E7=90=86=E5=90=8D=E3=82=92?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0=E3=81=99=E3=82=8B=E6=A9=9F=E8=83=BD(?= =?UTF-8?q?=E4=BA=88=E5=AE=9A)=E3=81=AE=E5=AE=9F=E8=A3=85=E3=80=81?= =?UTF-8?q?=E3=81=9D=E3=82=8C=E3=81=AB=E5=AF=BE=E3=81=99=E3=82=8B=E3=83=AB?= =?UTF-8?q?=E3=83=BC=E3=83=88=E3=81=A8=E3=83=AC=E3=82=A4=E3=82=A2=E3=82=A6?= =?UTF-8?q?=E3=83=88=E3=81=AE=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/App.tsx | 20 ++++++++ frontend/src/components/Layout.tsx | 9 ++++ frontend/src/pages/AddDishes1.tsx | 81 ++++++++++++++++++++++++++++++ frontend/src/pages/AddDishes2.tsx | 16 ++++++ 4 files changed, 126 insertions(+) create mode 100644 frontend/src/pages/AddDishes1.tsx create mode 100644 frontend/src/pages/AddDishes2.tsx diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 7141e87..1d803fa 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -10,6 +10,9 @@ import LoginPage from './pages/LoginPage'; import RegisterPage from './pages/RegisterPage'; import TaskListPage from './pages/TaskListPage'; import './App.css'; +// 必要なインポートを追加 +import AddDishes1 from './pages/AddDishes1'; +import AddDishes2 from './pages/AddDishes2'; /** * アプリケーション全体のMaterial UIテーマを定義 @@ -92,6 +95,23 @@ const App: React.FC = () => { } /> + {/* テストページへのルートを追加 */} + + + + } + /> + + + + } + /> diff --git a/frontend/src/components/Layout.tsx b/frontend/src/components/Layout.tsx index e8696a9..6854702 100644 --- a/frontend/src/components/Layout.tsx +++ b/frontend/src/components/Layout.tsx @@ -21,6 +21,7 @@ import { import { Menu as MenuIcon, ListAlt as ListAltIcon, + Science as ScienceIcon, // テストページ用のアイコン } from '@mui/icons-material'; import { useNavigate, Outlet, useLocation } from 'react-router-dom'; @@ -98,6 +99,14 @@ const Layout: React.FC = () => { + {/* テストページへのリンクを追加 */} + handleNavigate('/add1')} + selected={isSelected('/add1')} + > + + + diff --git a/frontend/src/pages/AddDishes1.tsx b/frontend/src/pages/AddDishes1.tsx new file mode 100644 index 0000000..6cee3ab --- /dev/null +++ b/frontend/src/pages/AddDishes1.tsx @@ -0,0 +1,81 @@ +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()) { + setError(true); + } else { + alert("送信成功!"); + navigate('/add2'); // タスク一覧ページにリダイレクト + } + }; + + 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..ed12aa4 --- /dev/null +++ b/frontend/src/pages/AddDishes2.tsx @@ -0,0 +1,16 @@ +/** + * テストページコンポーネント + * 白紙の状態で表示されるテスト用のページ + */ +import React from 'react'; +import { Box } from '@mui/material'; + +const AddDishes2: React.FC = () => { + return ( + + {/* 白紙のページ - 何も表示しない */} + + ); +}; + +export default AddDishes2; \ No newline at end of file From 7e9759b3769c0a7ccef78ae1d27264800480be24 Mon Sep 17 00:00:00 2001 From: "masato.fujita" Date: Thu, 5 Jun 2025 10:58:00 +0900 Subject: [PATCH 3/5] =?UTF-8?q?=E3=83=9A=E3=83=BC=E3=82=B8=E9=81=B7?= =?UTF-8?q?=E7=A7=BB=E6=99=82=E3=81=AB=E5=85=A5=E5=8A=9B=E3=81=95=E3=82=8C?= =?UTF-8?q?=E3=81=9F=E6=96=99=E7=90=86=E5=90=8D=E3=82=92=E8=A1=A8=E7=A4=BA?= =?UTF-8?q?=E3=81=99=E3=82=8B=E3=82=88=E3=81=86=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/pages/AddDishes1.tsx | 5 +++-- frontend/src/pages/AddDishes2.tsx | 30 ++++++++++++++++++++++++++---- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/frontend/src/pages/AddDishes1.tsx b/frontend/src/pages/AddDishes1.tsx index 6cee3ab..3175670 100644 --- a/frontend/src/pages/AddDishes1.tsx +++ b/frontend/src/pages/AddDishes1.tsx @@ -39,7 +39,8 @@ const AddDishes1: React.FC = () => { setError(true); } else { alert("送信成功!"); - navigate('/add2'); // タスク一覧ページにリダイレクト + localStorage.setItem("dishName", dish); + navigate('/add2', { state: dish }); // タスク一覧ページにリダイレクト } }; @@ -59,7 +60,7 @@ const AddDishes1: React.FC = () => { InputLabelProps={{ style: { fontSize: "40px" }}} style={{width: "80%" }} InputProps={{ style: { fontSize: "40px"} }} - // name="username" + name="dish_name" // autoComplete="username" autoFocus value={dish} diff --git a/frontend/src/pages/AddDishes2.tsx b/frontend/src/pages/AddDishes2.tsx index ed12aa4..394b76b 100644 --- a/frontend/src/pages/AddDishes2.tsx +++ b/frontend/src/pages/AddDishes2.tsx @@ -3,13 +3,35 @@ * 白紙の状態で表示されるテスト用のページ */ import React from 'react'; -import { Box } from '@mui/material'; +import { useLocation } 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'; const AddDishes2: React.FC = () => { + const receivedData = localStorage.getItem("dishName"); return ( - - {/* 白紙のページ - 何も表示しない */} - +
+

追加する料理名

+

{receivedData}

+
); }; From fbc186bcc017573508068257b2aaa2ef1d8962c4 Mon Sep 17 00:00:00 2001 From: "masato.fujita" Date: Fri, 6 Jun 2025 09:43:36 +0900 Subject: [PATCH 4/5] =?UTF-8?q?=E5=85=A5=E5=8A=9B=E3=81=97=E3=81=9F?= =?UTF-8?q?=E6=96=99=E7=90=86=E3=81=AB=E5=BF=85=E8=A6=81=E3=81=AA=E6=9D=90?= =?UTF-8?q?=E6=96=99=E3=82=92=E5=85=A5=E5=8A=9B=E3=81=97=E3=80=81=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0=E3=83=9C=E3=82=BF=E3=83=B3=E3=82=92=E6=8A=BC=E3=81=99?= =?UTF-8?q?=E3=81=93=E3=81=A8=E3=81=A7=E7=94=BB=E9=9D=A2=E3=81=AB=E3=81=9D?= =?UTF-8?q?=E3=81=AE=E5=86=85=E5=AE=B9=E3=81=8C=E8=A1=A8=E7=A4=BA=E3=81=95?= =?UTF-8?q?=E3=82=8C=E3=82=8B=E3=82=88=E3=81=86=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/pages/AddDishes1.tsx | 8 +- frontend/src/pages/AddDishes2.tsx | 257 +++++++++++++++++++++++++++--- 2 files changed, 241 insertions(+), 24 deletions(-) diff --git a/frontend/src/pages/AddDishes1.tsx b/frontend/src/pages/AddDishes1.tsx index 3175670..3d9f699 100644 --- a/frontend/src/pages/AddDishes1.tsx +++ b/frontend/src/pages/AddDishes1.tsx @@ -36,11 +36,12 @@ const AddDishes1: React.FC = () => { const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); // フォームのデフォルト送信動作を防止 if (!dish.trim()) { + alert("エラー"); setError(true); } else { alert("送信成功!"); - localStorage.setItem("dishName", dish); - navigate('/add2', { state: dish }); // タスク一覧ページにリダイレクト + localStorage.setItem("dishName", dish); // ローカルストレージにフォームに入力された料理名を保存 + navigate('/add2', { state: dish }); // 料理名から材料名追加ページにリダイレクト } }; @@ -55,7 +56,6 @@ const AddDishes1: React.FC = () => { required // id="username" label="追加・編集したい料理名を入力" - placeholder='ここに料理名を入力' variant="outlined" InputLabelProps={{ style: { fontSize: "40px" }}} style={{width: "80%" }} @@ -71,7 +71,7 @@ const AddDishes1: React.FC = () => {
diff --git a/frontend/src/pages/AddDishes2.tsx b/frontend/src/pages/AddDishes2.tsx index 394b76b..1885317 100644 --- a/frontend/src/pages/AddDishes2.tsx +++ b/frontend/src/pages/AddDishes2.tsx @@ -2,36 +2,253 @@ * テストページコンポーネント * 白紙の状態で表示されるテスト用のページ */ -import React from 'react'; -import { useLocation } from "react-router-dom"; +import React, { useState, useEffect } from 'react'; +import { taskApi } from '../services/api'; import { - AppBar, - Toolbar, - Typography, - Container, - Box, - Button, - Drawer, + Container, + Typography, + Tooltip, List, + ListItem, ListItemText, - ListItemIcon, - ListItemButton, - Divider, + ListItemSecondaryAction, IconButton, + Checkbox, + Fab, + Dialog, + DialogTitle, + DialogContent, + DialogActions, TextField, - Paper, - Alert, - Link, - Grid, + 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 = { 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); + + // const fetchTasks = async () => { + // try { + // const tasks = await taskApi.getTasks(); + // setTasks(tasks); + // } catch (error) { + // console.error(`${TASK_ERRORS.FETCH_FAILED}:`, error); + // } + // }; + + // コンポーネントマウント時にタスク一覧を取得 + // useEffect(() => { + // fetchTasks(); + // }, []); + /** + * タスクを削除するハンドラー + * 指定された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("送信成功!"); + // localStorage.setItem("dishName", dish); // ローカルストレージにフォームに入力された料理名を保存 + // navigate('/add2', { state: dish }); // 料理名から材料名追加ページにリダイレクト + } + }; + const handleCreateTask = 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); + } + }; return ( -
-

追加する料理名

-

{receivedData}

-
+ +
+

追加する料理名

+

{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]*" }} // ここで整数のみ許可 + /> + + + + + + + +
); }; From 43d69e2f8e80364411e1ab74c9a08de1f942dced Mon Sep 17 00:00:00 2001 From: "masato.fujita" Date: Fri, 6 Jun 2025 10:51:01 +0900 Subject: [PATCH 5/5] =?UTF-8?q?=E6=96=99=E7=90=86=E3=81=AB=E5=BF=85?= =?UTF-8?q?=E8=A6=81=E3=81=AA=E9=A3=9F=E6=9D=90=E3=82=92=E3=82=BF=E3=82=B9?= =?UTF-8?q?=E3=82=AF=E4=B8=80=E8=A6=A7=E3=81=AB=E8=A1=A8=E7=A4=BA=E3=81=95?= =?UTF-8?q?=E3=82=8C=E3=82=8B=E3=82=88=E3=81=86=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/pages/AddDishes1.tsx | 20 +++++------ frontend/src/pages/AddDishes2.tsx | 57 ++++++++++++++++++++++--------- 2 files changed, 50 insertions(+), 27 deletions(-) diff --git a/frontend/src/pages/AddDishes1.tsx b/frontend/src/pages/AddDishes1.tsx index 3d9f699..d003ebd 100644 --- a/frontend/src/pages/AddDishes1.tsx +++ b/frontend/src/pages/AddDishes1.tsx @@ -34,16 +34,16 @@ const AddDishes1: React.FC = () => { 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 }); // 料理名から材料名追加ページにリダイレクト - } - }; + e.preventDefault(); // フォームのデフォルト送信動作を防止 + if (!dish.trim()) { + alert("エラー"); + setError(true); + } else { + alert("送信成功!"); + localStorage.setItem("dishName", dish); // ローカルストレージにフォームに入力された料理名を保存 + navigate('/add2', { state: dish }); // 料理名から材料名追加ページにリダイレクト + } + }; return (
diff --git a/frontend/src/pages/AddDishes2.tsx b/frontend/src/pages/AddDishes2.tsx index 1885317..2e319d9 100644 --- a/frontend/src/pages/AddDishes2.tsx +++ b/frontend/src/pages/AddDishes2.tsx @@ -36,8 +36,11 @@ import { TASK_ERRORS } from '../constants/errorMessages'; import { GENERAL_ERRORS } from '../constants/errorMessages'; import CategoryDropDown from "../components/CategoryDropDown"; -// 新規タスクの初期状態 -const EMPTY_TASK = { title: '', amount: 0, completed: false }; +// 新規タスクの初期状態(画面表示用) +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; // 食材名 @@ -49,6 +52,7 @@ const AddDishes2: React.FC = () => { const receivedData = localStorage.getItem("dishName"); // タスク一覧の状態管理 const [tasks, setTasks] = useState([]); + const [addtasks, setAddTasks] = useState([]); // エラーメッセージの状態管理 const [error, setError] = useState(false); @@ -57,19 +61,23 @@ const AddDishes2: React.FC = () => { // 新規タスクの入力内容 const [newTask, setNewTask] = useState(EMPTY_TASK); - // const fetchTasks = async () => { - // try { - // const tasks = await taskApi.getTasks(); - // setTasks(tasks); - // } catch (error) { - // console.error(`${TASK_ERRORS.FETCH_FAILED}:`, error); - // } - // }; - // コンポーネントマウント時にタスク一覧を取得 - // useEffect(() => { - // fetchTasks(); - // }, []); + 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を通じて削除 @@ -94,14 +102,15 @@ const AddDishes2: React.FC = () => { e.preventDefault(); // フォームのデフォルト送信動作を防止 if (addtasks[0] == null) { setError(true); - alert("食材を追加してください") + alert("食材を追加してください"); } else { alert("送信成功!"); + handleCreateTask_DataBase(); // localStorage.setItem("dishName", dish); // ローカルストレージにフォームに入力された料理名を保存 // navigate('/add2', { state: dish }); // 料理名から材料名追加ページにリダイレクト } }; - const handleCreateTask = async () => { + const handleCreateTask_Temp = async () => { try { // await taskApi.createTask(newTask); let newAddTasks = [...addtasks]; // 配列をコピー @@ -114,6 +123,20 @@ const AddDishes2: React.FC = () => { 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 (
@@ -243,7 +266,7 @@ const AddDishes2: React.FC = () => { -