Merge remote-tracking branch 'origin/dev-frontend-with-api' into dev-frontend-top

dev-frontend-stock
Haru.Kusano 5 months ago
commit e121a7c7d5
  1. 77
      frontend/src/pages/TaskListPage.tsx
  2. 93
      frontend/src/services/api.ts
  3. 12
      frontend/src/types/types.ts

@ -3,7 +3,7 @@
* *
*/ */
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { taskApi } from '../services/api'; import { toBuyApi } from '../services/api';
import { import {
Container, Container,
Typography, Typography,
@ -29,7 +29,7 @@ import {
Add as AddIcon, Delete as DeleteIcon, ShoppingBasket as ShoppingBasketIcon, Add as AddIcon, Delete as DeleteIcon, ShoppingBasket as ShoppingBasketIcon,
SoupKitchen as SoupKitchenIcon SoupKitchen as SoupKitchenIcon
} from '@mui/icons-material'; } from '@mui/icons-material';
import { Task } from '../types/types'; import { ToBuy } from '../types/types';
import { TASK_ERRORS } from '../constants/errorMessages'; import { TASK_ERRORS } from '../constants/errorMessages';
//import { FaCarrot } from "react-icons/fa6"; //エラー起きる いったん保留 //import { FaCarrot } from "react-icons/fa6"; //エラー起きる いったん保留
import CategoryDropDown from "../components/CategoryDropDown"; import CategoryDropDown from "../components/CategoryDropDown";
@ -38,11 +38,17 @@ import CategoryDropDown from "../components/CategoryDropDown";
// 新規タスクの初期状態 // 新規タスクの初期状態
const EMPTY_TASK = { id: 0, stuff_id: 0, stuff_name: '', amount: 0, price: 0, buyDate: new Date('2000-06-22'), expirationDate: new Date('2020-06-22'), newAddition: false, completed: false }; const EMPTY_TASK: Omit<ToBuy, 'tobuy_id'> & {category: string} = {
stuff_id: 0,
stuff_name: '',
amount: 0,
shop: '',
category: '',
}
const TaskListPage: React.FC = () => { const TaskListPage: React.FC = () => {
// タスク一覧の状態管理 // タスク一覧の状態管理
const [tasks, setTasks] = useState<Task[]>([]); const [tobuys, setToBuys] = useState<ToBuy[]>([]);
// 新規タスク作成ダイアログの表示状態 // 新規タスク作成ダイアログの表示状態
const [openDialog, setOpenDialog] = useState(false); const [openDialog, setOpenDialog] = useState(false);
// 新規タスクの入力内容 // 新規タスクの入力内容
@ -53,6 +59,7 @@ const TaskListPage: React.FC = () => {
const [selectedTask, setSelectedTask] = useState<Task>(); const [selectedTask, setSelectedTask] = useState<Task>();
const [newToBuy, setNewToBuy] = useState(EMPTY_TASK);
// コンポーネントマウント時にタスク一覧を取得 // コンポーネントマウント時にタスク一覧を取得
useEffect(() => { useEffect(() => {
@ -65,36 +72,36 @@ const TaskListPage: React.FC = () => {
*/ */
const fetchTasks = async () => { const fetchTasks = async () => {
try { try {
const tasks = await taskApi.getTasks(); const tobuys = await toBuyApi.getToBuys();
setTasks(tasks); setToBuys(tobuys.tobuy_array);
} catch (error) { } catch (error) {
console.error(`${TASK_ERRORS.FETCH_FAILED}:`, error); console.error(`${TASK_ERRORS.FETCH_FAILED}:`, error);
} }
}; };
/** // /**
* // * タスクの完了状態を切り替えるハンドラー
* APIに更新を要求 // * 対象タスクの完了状態を反転させてAPIに更新を要求
*/ // */
const handleToggleComplete = async (taskId: number) => { // const handleToggleComplete = async (taskId: number) => {
try { // try {
const task = tasks.find(t => t.id === taskId); // const task = tasks.find(t => t.id === taskId);
if (!task) return; // if (!task) return;
await taskApi.updateTask(taskId, { ...task, completed: !task.completed }); // await toBuyApi.updateTask(taskId, { ...task, completed: !task.completed });
fetchTasks(); // 更新後のタスク一覧を再取得 // fetchTasks(); // 更新後のタスク一覧を再取得
} catch (error) { // } catch (error) {
console.error(`${TASK_ERRORS.UPDATE_FAILED}:`, error); // console.error(`${TASK_ERRORS.UPDATE_FAILED}:`, error);
} // }
}; // };
/** /**
* *
* IDのタスクをAPIを通じて削除 * IDのタスクをAPIを通じて削除
*/ */
const handleDeleteTask = async (taskId: number) => { const handleDeleteTask = async (toBuyId: number) => {
try { try {
await taskApi.deleteTask(taskId); await toBuyApi.deleteToBuy(toBuyId);
fetchTasks(); // 削除後のタスク一覧を再取得 fetchTasks(); // 削除後のタスク一覧を再取得
} catch (error) { } catch (error) {
console.error(`${TASK_ERRORS.DELETE_FAILED}:`, error); console.error(`${TASK_ERRORS.DELETE_FAILED}:`, error);
@ -108,9 +115,9 @@ const TaskListPage: React.FC = () => {
*/ */
const handleCreateTask = async () => { const handleCreateTask = async () => {
try { try {
await taskApi.addStuff(newTask); await toBuyApi.addToBuy(newToBuy);
setOpenDialog(false); // ダイアログを閉じる setOpenDialog(false); // ダイアログを閉じる
setNewTask(EMPTY_TASK); // 入力内容をリセット setNewToBuy(EMPTY_TASK); // 入力内容をリセット
fetchTasks(); // 作成後のタスク一覧を再取得 fetchTasks(); // 作成後のタスク一覧を再取得
} catch (error) { } catch (error) {
console.error(`${TASK_ERRORS.CREATE_FAILED}:`, error); console.error(`${TASK_ERRORS.CREATE_FAILED}:`, error);
@ -126,9 +133,9 @@ const TaskListPage: React.FC = () => {
<div style={{ border: '3px solid black', borderRadius: '8px', backgroundColor: '#add8e6', height: 'auto', padding: '20px' }}> <div style={{ border: '3px solid black', borderRadius: '8px', backgroundColor: '#add8e6', height: 'auto', padding: '20px' }}>
<List> <List>
{/* タスク一覧をマップして各タスクをリストアイテムとして表示 */} {/* タスク一覧をマップして各タスクをリストアイテムとして表示 */}
{tasks.map((task) => ( {tobuys.map((tobuy) => (
<ListItem <ListItem
key={task.id} key={tobuy.tobuy_id}
sx={{ sx={{
bgcolor: 'background.paper', bgcolor: 'background.paper',
mb: 1, mb: 1,
@ -137,16 +144,18 @@ const TaskListPage: React.FC = () => {
}} }}
> >
{/* タスク完了状態を切り替えるチェックボックス */} {/* タスク完了状態を切り替えるチェックボックス */}
{/*}
<Checkbox <Checkbox
checked={task.completed} checked={task.completed}
onChange={() => handleToggleComplete(task.id)} onChange={() => handleToggleComplete(task.id)}
/> />
*/}
{/* タスクのタイトルと説明 - 完了状態に応じて取り消し線を表示 */} {/* タスクのタイトルと説明 - 完了状態に応じて取り消し線を表示 */}
<ListItemText <ListItemText
primary={task.stuff_name} primary={tobuy.stuff_name}
secondary={task.amount} secondary={tobuy.amount}
sx={{ sx={{
textDecoration: task.completed ? 'line-through' : 'none', textDecoration: false ? 'line-through' : 'none',
}} }}
/> />
{/* 買い物リスト:食材情報記入ボタン */} {/* 買い物リスト:食材情報記入ボタン */}
@ -178,7 +187,7 @@ const TaskListPage: React.FC = () => {
<IconButton <IconButton
edge="end" edge="end"
aria-label="delete" aria-label="delete"
onClick={() => handleDeleteTask(task.id)} onClick={() => handleDeleteTask(tobuy.tobuy_id)}
> >
<DeleteIcon /> <DeleteIcon />
</IconButton> </IconButton>
@ -232,8 +241,8 @@ const TaskListPage: React.FC = () => {
margin="dense" margin="dense"
label="材料名" label="材料名"
fullWidth fullWidth
value={newTask.stuff_name} value={newToBuy.stuff_name}
onChange={(e) => setNewTask({ ...newTask, stuff_name: e.target.value })} onChange={(e) => setNewToBuy({ ...newToBuy, stuff_name: e.target.value })}
sx={{ marginBottom: 2 }} sx={{ marginBottom: 2 }}
/> />
{/* 数量入力フィールド */} {/* 数量入力フィールド */}
@ -241,12 +250,12 @@ const TaskListPage: React.FC = () => {
margin="dense" margin="dense"
label="数量" label="数量"
fullWidth fullWidth
value={newTask.amount} value={newToBuy.amount}
onChange={(e) => { onChange={(e) => {
const value = e.target.value; const value = e.target.value;
const parsedValue = parseInt(value, 10); // 数値に変換 const parsedValue = parseInt(value, 10); // 数値に変換
if (!isNaN(parsedValue)) { if (!isNaN(parsedValue)) {
setNewTask({ ...newTask, amount: parsedValue }); // number型で保存 setNewToBuy({ ...newToBuy, amount: parsedValue }); // number型で保存
} }
}} }}
sx={{ width: "20%" }} sx={{ width: "20%" }}

@ -3,7 +3,7 @@
* APIとの通信を担当するモジュール * APIとの通信を担当するモジュール
* *
*/ */
import { LoginCredentials, RegisterCredentials, AuthResponse, Task } from '../types/types'; import { LoginCredentials, RegisterCredentials, AuthResponse, Task, ToBuy } from '../types/types';
import { AUTH_ERRORS, TASK_ERRORS } from '../constants/errorMessages'; import { AUTH_ERRORS, TASK_ERRORS } from '../constants/errorMessages';
// APIのベースURL - 環境変数から取得するか、デフォルト値を使用 // APIのベースURL - 環境変数から取得するか、デフォルト値を使用
@ -82,7 +82,98 @@ export const authApi = {
}, },
}; };
/**
* API機能を提供するオブジェクト
*
*/
export const toBuyApi = {
/**
*
* @returns
*/
getToBuys: async (): Promise<{ "tobuy_array": ToBuy[] }> => {
// const response = await fetch(`${API_BASE_URL}/api/tobuy/get`, {
// headers: getHeaders(), // 認証トークンを含むヘッダー
// });
// if (!response.ok) {
// throw new Error(TASK_ERRORS.FETCH_FAILED);
// }
// return response.json();
return {
"tobuy_array": [
{
"tobuy_id": 1,
"stuff_id": 2,
"stuff_name": "じゃがいも",
"amount": 3,
"shop": "shopXXX"
},
{
"tobuy_id": 2,
"stuff_id": 5,
"stuff_name": "にんじん",
"amount": 1
}
]
}
},
/**
*
* @param tobuy
* @returns
*/
addToBuy: async (tobuy: Omit<ToBuy, 'tobuy_id'> & { category: string }): Promise<any> => {
// const response = await fetch(`${API_BASE_URL}/api/tasks`, {
// method: 'POST',
// headers: getHeaders(),
// body: JSON.stringify(tobuy),
// });
// if (!response.ok) {
// throw new Error(TASK_ERRORS.CREATE_FAILED);
// }
// return response.json();
return {
"result": true,
"tobuy_id": 1,
"stuff_id": 6,
"message": "追加に成功しました",
}
},
/**
*
* @param id ID
*/
deleteToBuy: async (tobuy_id: number): Promise<{ result: boolean }> => {
// const response = await fetch(`${API_BASE_URL}/api/tobuy/delete`, {
// method: 'DELETE',
// headers: getHeaders(),
// body: JSON.stringify({tobuy_id}),
// });
// if (!response.ok) {
// throw new Error(TASK_ERRORS.DELETE_FAILED);
// }
return {
"result": true
}
},
}
/** /**
* ()
* API機能を提供するオブジェクト * API機能を提供するオブジェクト
* *
*/ */

@ -17,6 +17,18 @@ export interface Task {
//updatedAt: string; // タスク更新日時 //updatedAt: string; // タスク更新日時
} }
/**
*
*
*/
export interface ToBuy {
tobuy_id: number,
stuff_id: number,
stuff_name: string,
amount: number,
shop?: string,
}
/** /**
* *
* *

Loading…
Cancel
Save