Merge remote-tracking branch 'origin/feature-frontend-top' into feature-frontend-styles

feature-frontend-styles
Masaharu.Kato 4 months ago
commit 026347f7e4
  1. 166
      frontend/src/pages/TaskListPage.tsx
  2. 21
      frontend/src/services/api.ts

@ -32,7 +32,7 @@ import {
} from '@mui/material'; } from '@mui/material';
import { 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, Edit as EditIcon
} from '@mui/icons-material'; } from '@mui/icons-material';
import { ToBuy, Stuff, /*Stock*/ } from '../types/types'; import { ToBuy, Stuff, /*Stock*/ } from '../types/types';
import { TOBUY_ERRORS } from '../constants/errorMessages'; import { TOBUY_ERRORS } from '../constants/errorMessages';
@ -64,9 +64,20 @@ const TaskListPage: React.FC = () => {
//在庫登録ダイアログの表示状態 //在庫登録ダイアログの表示状態
const [openInfoDialog, setOpenInfoDialog] = useState(false); const [openInfoDialog, setOpenInfoDialog] = useState(false);
//数量変更ダイアログの表示状態
const [openAmountDialog, setOpenAmountDialog] = useState(false);
const [selectedTask, setSelectedTask] = useState<ToBuy["tobuyId"]>(0); const [selectedTask, setSelectedTask] = useState<ToBuy["tobuyId"]>(0);
const [selectedEditingTask, setSelectedEditingTask] = useState<ToBuy>({
tobuyId: 0,
stuffId: 0,
stuffName: "",
amount: 0,
shop: undefined,
});
const [newToBuy, setNewToBuy] = useState(EMPTY_TOBUY); const [newToBuy, setNewToBuy] = useState(EMPTY_TOBUY);
const [stuffs, setStuffs] = useState<Stuff[]>([]); const [stuffs, setStuffs] = useState<Stuff[]>([]);
@ -88,6 +99,7 @@ const TaskListPage: React.FC = () => {
const fetchTasks = async () => { const fetchTasks = async () => {
try { try {
const tobuys = await toBuyApi.getToBuys(); const tobuys = await toBuyApi.getToBuys();
console.log(tobuys);
setToBuys(tobuys); setToBuys(tobuys);
} catch (error) { } catch (error) {
console.error(`${TOBUY_ERRORS.FETCH_FAILED}:`, error); console.error(`${TOBUY_ERRORS.FETCH_FAILED}:`, error);
@ -172,6 +184,38 @@ const TaskListPage: React.FC = () => {
} }
}; };
/**
*
* APIに送信して変更
*
*/
const handleUpdateTask = async () => {
try {
console.log(selectedEditingTask)
await toBuyApi.updateToBuy(selectedEditingTask);
setOpenAmountDialog(false); // ダイアログを閉じる
//setNewToBuy(EMPTY_TOBUY); // 入力内容をリセット
fetchTasks(); // 作成後のタスク一覧を再取得
} catch (error) {
console.error(`${TOBUY_ERRORS.CREATE_FAILED}:`, error);
}
};
// /**
// * クリックされたタスクの情報を取得するための関数
// * @param tobuyId
// * @returns tobuyIdが一致するtoBuy
// */
// const getToBuyDetails = (tobuyId: number): ToBuy => {
// console.log(tobuyId)
// const result = tobuys.find((toBuy) => toBuy.tobuyId === tobuyId);
// if(result === undefined){
// throw new Error(`tobuyId: ${tobuyId} に対応するデータが見つかりません`);
// }
// return result;
// };
return ( return (
<Container> <Container>
<Typography variant="h4" component="h1" gutterBottom> <Typography variant="h4" component="h1" gutterBottom>
@ -207,11 +251,25 @@ const TaskListPage: React.FC = () => {
<Typography variant="body1" component="span" sx={{ marginRight: '1em' }}> <Typography variant="body1" component="span" sx={{ marginRight: '1em' }}>
{`× ${tobuy.amount}`} {`× ${tobuy.amount}`}
</Typography> </Typography>
{/* 買い物リスト:数量変更ボタン */}
<Tooltip title="数量変更">
<IconButton
sx={{ marginRight: 0, marginLeft: 0 }}
edge="end"
aria-label="数量変更"
onClick={() => {
setOpenAmountDialog(true)
setSelectedEditingTask(tobuy)
}}
>
<EditIcon />
</IconButton>
</Tooltip>
{/* 買い物リスト:食材情報記入ボタン */}
<Tooltip title="購入情報を記入"> <Tooltip title="購入情報を記入">
{/* デフォルトの marginRightの設定(マイナス)を上書き */}
<IconButton <IconButton
color="primary" color="primary"
sx={{ marginRight: 0}} sx={{ marginRight: 0, marginLeft: 0 }}
edge="end" edge="end"
aria-label="購入情報を記入" aria-label="購入情報を記入"
onClick={() => { onClick={() => {
@ -223,6 +281,7 @@ const TaskListPage: React.FC = () => {
<ShoppingBasketIcon /> <ShoppingBasketIcon />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
{/* 買い物リスト:食材削除ボタン */} {/* 買い物リスト:食材削除ボタン */}
<Tooltip title="項目を削除" <Tooltip title="項目を削除"
componentsProps={{ componentsProps={{
@ -240,6 +299,7 @@ const TaskListPage: React.FC = () => {
<IconButton <IconButton
edge="end" edge="end"
sx={{ marginLeft: 3 }}
aria-label="delete" aria-label="delete"
onClick={() => handleDeleteTask(tobuy.tobuyId)} onClick={() => handleDeleteTask(tobuy.tobuyId)}
> >
@ -253,31 +313,37 @@ const TaskListPage: React.FC = () => {
</List> </List>
</div> </div>
{/* 新規材料作成ボタン - 画面下部に固定表示 */} {/* 新規材料作成ボタン - 画面下部に固定表示 */}
<Tooltip title="材料のみ追加"> <Box sx={{ textAlign: 'center', position: 'fixed', bottom: 76, left: '40%', transform: 'translateX(-50%)' }}>
<Fab <Typography variant="caption" color="textSecondary">
color="primary"
sx={{ position: 'fixed', bottom: 16, left: '40%', transform: 'translateX(-50%)' }} </Typography>
onClick={() => setOpenDialog(true)} </Box>
> <Fab
<AddIcon /> color="primary"
</Fab> sx={{ position: 'fixed', bottom: 16, left: '40%', transform: 'translateX(-50%)' }}
</Tooltip> onClick={() => setOpenDialog(true)}
{/*新規料理追加ボタン - 画面下部に固定表示 */} >
<Tooltip title="料理から追加"> <AddIcon />
<Fab </Fab>
color="primary"
sx={{ position: 'fixed', bottom: 16, left: '60%', transform: 'translateX(-50%)' }}
onClick={() => {
setOpenDialog(true);
//handleNavigate('/AddDishies1');
}}
//selected={isSelected('/test')}
{/*新規料理追加ボタン - 画面下部に固定表示 */}
<Box sx={{ textAlign: 'center', position: 'fixed', bottom: 76, left: '60%', transform: 'translateX(-50%)' }}>
<Typography variant="caption" color="textSecondary">
</Typography>
</Box>
<Fab
color="primary"
sx={{ position: 'fixed', bottom: 16, left: '60%', transform: 'translateX(-50%)' }}
onClick={() => {
setOpenDialog(true);
//handleNavigate('/AddDishies1');
}}
//selected={isSelected('/test')}
>
<SoupKitchenIcon />
</Fab>
>
<SoupKitchenIcon />
</Fab>
</Tooltip>
{/* 新規タスク作成ダイアログ */} {/* 新規タスク作成ダイアログ */}
<Dialog open={openDialog} onClose={() => setOpenDialog(false)} disableScrollLock={true}> <Dialog open={openDialog} onClose={() => setOpenDialog(false)} disableScrollLock={true}>
@ -345,7 +411,7 @@ const TaskListPage: React.FC = () => {
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) && parsedValue >= 0) { //負数除外
setNewToBuy({ ...newToBuy, amount: parsedValue }); // number型で保存 setNewToBuy({ ...newToBuy, amount: parsedValue }); // number型で保存
} }
}} }}
@ -423,6 +489,52 @@ const TaskListPage: React.FC = () => {
</Button> </Button>
</DialogActions> </DialogActions>
</Dialog> </Dialog>
{/* 数量変更ダイアログ */}
<Dialog open={openAmountDialog} onClose={() => setOpenAmountDialog(false)} disableScrollLock={true}>
<Box display="flex" alignItems="center">
<DialogTitle sx={{ flexGrow: 1 }}></DialogTitle>
</Box>
<DialogContent>
<Box sx={{ pt: 1 }}>
{/* 材料名表示 */}
<TextField
autoFocus
margin="dense"
label="材料名"
fullWidth
value={selectedEditingTask.stuffName}
disabled
sx={{ marginBottom: 2 }}
/>
{/* 数量入力フィールド */}
<TextField
margin="dense"
label="数量"
fullWidth
value={selectedEditingTask.amount}
onChange={(e) => {
const value = e.target.value;
const parsedValue = parseInt(value, 10); // 数値に変換
if (!isNaN(parsedValue) && parsedValue >= 0) { //負数除外
setSelectedEditingTask({ ...selectedEditingTask, amount: parsedValue }); // number型で保存
}
}}
sx={{ width: "20%" }}
type="number"
inputProps={{ inputMode: "numeric", pattern: "[0-9]*" }} // ここで整数のみ許可
/>
</Box>
</DialogContent>
<DialogActions>
<Button onClick={() => setOpenAmountDialog(false)}></Button>
<Button onClick={handleUpdateTask} variant="contained">
</Button>
</DialogActions>
</Dialog>
</Container> </Container>
); );

@ -109,7 +109,7 @@ export const toBuyApi = {
* @param tobuy * @param tobuy
* @returns * @returns
*/ */
addToBuy: async (tobuy: Omit<ToBuy, 'stuffId' | 'tobuyId'> & { stuffId: number | null, category: string }): Promise<any> => { addToBuy:async (tobuy: Omit<ToBuy, 'stuffId' | 'tobuyId'> & { stuffId: number | null, category: string }): Promise<any> => {
const response = await fetch(`${API_BASE_URL}/api/tobuy/add`, { const response = await fetch(`${API_BASE_URL}/api/tobuy/add`, {
method: 'POST', method: 'POST',
headers: getHeaders(), headers: getHeaders(),
@ -154,6 +154,25 @@ export const toBuyApi = {
// } // }
}, },
/**
*
* @param tobuy
* @returns
*/
updateToBuy: async (tobuy:ToBuy): Promise<any> => {
const response = await fetch(`${API_BASE_URL}/api/tobuy/update`, {
method: 'PUT',
headers: getHeaders(),
body: JSON.stringify(tobuy),
});
if (!response.ok) {
throw new Error(TOBUY_ERRORS.CREATE_FAILED);
}
return response.json();
},
/** /**
* *
*/ */

Loading…
Cancel
Save