|
|
/**
|
|
|
* テストページコンポーネント
|
|
|
* 白紙の状態で表示されるテスト用のページ
|
|
|
*/
|
|
|
import React, { useState, useEffect } from 'react';
|
|
|
import {
|
|
|
Container,
|
|
|
Typography,
|
|
|
Tooltip,
|
|
|
List,
|
|
|
ListItem,
|
|
|
ListItemText,
|
|
|
ListItemSecondaryAction,
|
|
|
IconButton,
|
|
|
Checkbox,
|
|
|
Fab,
|
|
|
Dialog,
|
|
|
DialogTitle,
|
|
|
DialogContent,
|
|
|
DialogActions,
|
|
|
TextField,
|
|
|
Button,
|
|
|
Box,
|
|
|
MenuItem,
|
|
|
Select,
|
|
|
FormControl,
|
|
|
InputLabel,
|
|
|
ListItemIcon
|
|
|
} from '@mui/material';
|
|
|
import {
|
|
|
Add as AddIcon, Delete as DeleteIcon, ShoppingBasket as ShoppingBasketIcon,
|
|
|
SoupKitchen as SoupKitchenIcon, Edit as EditIcon, Save as SaveIcon, ListAlt as ListAltIcon
|
|
|
} from '@mui/icons-material';
|
|
|
import AddStuffAmountDialog from '../components/AddStuffAmountDialog';
|
|
|
import { StuffAndCategoryAndAmount } from '../types/types';
|
|
|
import EditAmountDialog from '../components/EditAmountDialog';
|
|
|
import { recipeApi, toBuyApi } from '../services/api';
|
|
|
import { useNavigate, useParams } from 'react-router-dom';
|
|
|
|
|
|
const AddRecipe: React.FC = () => {
|
|
|
const { recipeId: recipeIdStr } = useParams();
|
|
|
const recipeId = recipeIdStr ? parseInt(recipeIdStr) : null
|
|
|
|
|
|
const navigate = useNavigate();
|
|
|
|
|
|
// 料理名,説明
|
|
|
const [recipeName, setRecipeName] = useState<string>('');
|
|
|
const [recipeSummary, setRecipeSummary] = useState<string>('');
|
|
|
// 材料リスト
|
|
|
const [items, setItems] = useState<StuffAndCategoryAndAmount[]>([]);
|
|
|
// 材料追加作成ダイアログの表示状態
|
|
|
const [openAddDialog, setOpenAddDialog] = useState(false);
|
|
|
// 材料追加作成ダイアログの表示状態
|
|
|
const [openAmountDialog, setOpenAmountDialog] = useState(false);
|
|
|
// 新規アイテムの入力内容
|
|
|
const emptyItem: StuffAndCategoryAndAmount = { stuffId: null, stuffName: '', category: '', amount: 1 }
|
|
|
const [newItem, setNewItem] = useState<StuffAndCategoryAndAmount>(emptyItem);
|
|
|
// 編集しているアイテム
|
|
|
const [editingItem, setEditingItem] = useState<StuffAndCategoryAndAmount>(emptyItem);
|
|
|
const [editingItemIdx, setEditingItemIdx] = useState(0);
|
|
|
//削除確認ダイアログの表示状態
|
|
|
const [openDeleteDialog, setOpenDeleteDialog] = useState(false);
|
|
|
|
|
|
const loadRecipe = async () => {
|
|
|
if (recipeId && !recipeName) {
|
|
|
const recipe = await recipeApi.getById(recipeId);
|
|
|
console.log('loaded recipe=', recipe)
|
|
|
setRecipeName(recipe.recipeName)
|
|
|
setRecipeSummary(recipe.summary)
|
|
|
setItems(recipe.stuffAndAmountArray)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
const handleSaveRecipe = async () => {
|
|
|
|
|
|
if (!recipeName) {
|
|
|
alert('レシピ名が入力されていません!')
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
if (!items.length) {
|
|
|
alert('材料が追加されていません!')
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
if (!recipeId) {
|
|
|
// 新規追加
|
|
|
const response = await recipeApi.addRecipe({
|
|
|
recipeName,
|
|
|
summary: recipeSummary,
|
|
|
stuffAndAmountArray: items,
|
|
|
})
|
|
|
return response.recipeId;
|
|
|
}
|
|
|
|
|
|
const response = await recipeApi.updateRecipe({
|
|
|
recipeId,
|
|
|
recipeName,
|
|
|
summary: recipeSummary,
|
|
|
stuffAndAmountArray: items,
|
|
|
})
|
|
|
|
|
|
return recipeId;
|
|
|
}
|
|
|
|
|
|
const handleSubmit = async () => {
|
|
|
const recipeId = await handleSaveRecipe();
|
|
|
// alert('レシピが保存されました!');
|
|
|
if (!recipeId) return;
|
|
|
navigate('/recipeList');
|
|
|
}
|
|
|
|
|
|
const handleSubmitAndAddToBuy = async () => {
|
|
|
const recipeId = await handleSaveRecipe();
|
|
|
if (!recipeId) return false;
|
|
|
await toBuyApi.addByRecipe(recipeId);
|
|
|
// alert('レシピが保存されて買うものリストに追加されました!');
|
|
|
navigate('/tasks');
|
|
|
}
|
|
|
|
|
|
// コンポーネントマウント時にタスク一覧を取得
|
|
|
useEffect(() => {
|
|
|
loadRecipe();
|
|
|
}, []);
|
|
|
|
|
|
return (
|
|
|
(recipeId && !recipeName)
|
|
|
? <p>読み込み中...</p>
|
|
|
:
|
|
|
<Box>
|
|
|
<div>
|
|
|
<h1>
|
|
|
<SoupKitchenIcon sx={{ marginRight: "0.5em" }} />
|
|
|
{!recipeId ? '料理の追加' : '料理の編集'}
|
|
|
</h1>
|
|
|
<TextField autoFocus margin="dense" label="料理名" fullWidth
|
|
|
value={recipeName} onChange={(e) => setRecipeName(e.target.value)}
|
|
|
/>
|
|
|
<TextField margin="dense" label="説明" fullWidth
|
|
|
value={recipeSummary} onChange={(e) => setRecipeSummary(e.target.value)}
|
|
|
/>
|
|
|
</div>
|
|
|
<h2 style={{ marginTop: "0.5em" }}>
|
|
|
材料リスト
|
|
|
</h2>
|
|
|
{/* すべての材料情報を表示 */}
|
|
|
{(!items || !items.length)
|
|
|
? (<p>+ボタンで材料を追加してください</p>)
|
|
|
: (<List>{items.map((item, index) => (
|
|
|
|
|
|
<ListItem
|
|
|
key={index}
|
|
|
sx={{
|
|
|
bgcolor: 'background.paper',
|
|
|
mb: 1,
|
|
|
borderRadius: 1,
|
|
|
boxShadow: 1,
|
|
|
}}
|
|
|
>
|
|
|
<ListItemText primary={item.stuffName} />
|
|
|
{/* 買い物リスト:食材情報記入ボタン */}
|
|
|
<ListItemSecondaryAction>
|
|
|
<Typography variant="body1" component="span" sx={{ marginRight: '1em' }}>
|
|
|
{`× ${item.amount}`}
|
|
|
</Typography>
|
|
|
{/* 買い物リスト:数量変更ボタン */}
|
|
|
<Tooltip title="数量変更">
|
|
|
<IconButton sx={{ marginRight: 0, marginLeft: 0 }} edge="end" aria-label="数量変更"
|
|
|
onClick={() => {
|
|
|
setOpenAmountDialog(true)
|
|
|
setEditingItemIdx(index)
|
|
|
setEditingItem(item)
|
|
|
}}
|
|
|
>
|
|
|
<EditIcon />
|
|
|
</IconButton>
|
|
|
</Tooltip>
|
|
|
{/* 買い物リスト:食材削除ボタン */}
|
|
|
<Tooltip title="項目を削除"
|
|
|
componentsProps={{
|
|
|
tooltip: { sx: { backgroundColor: "white", color: "red", fontSize: "0.8rem", padding: "6px", borderRadius: "6px" } },
|
|
|
}}>
|
|
|
<IconButton edge="end" sx={{ marginRight: 0, marginLeft: 0 }} aria-label="delete"
|
|
|
onClick={() => {
|
|
|
setOpenDeleteDialog(true)
|
|
|
setEditingItem(item)
|
|
|
setEditingItemIdx(index)
|
|
|
}}>
|
|
|
<DeleteIcon />
|
|
|
</IconButton>
|
|
|
</Tooltip>
|
|
|
|
|
|
</ListItemSecondaryAction>
|
|
|
|
|
|
</ListItem>
|
|
|
|
|
|
))}</List>)}
|
|
|
|
|
|
|
|
|
<div style={{ position: "fixed", left: "80%", transform: 'translateX(-50%)', bottom: "10%" }}>
|
|
|
<Box sx={{ textAlign: 'center' }}>
|
|
|
<Typography variant="caption">材料を追加</Typography>
|
|
|
</Box>
|
|
|
<Fab color="primary" onClick={() => setOpenAddDialog(true)}>
|
|
|
<AddIcon sx={{ fontSize: "1.5rem" }} />
|
|
|
</Fab>
|
|
|
</div>
|
|
|
|
|
|
<div style={{ position: "fixed", left: "50%", transform: 'translateX(-50%)', bottom: "2%", whiteSpace: 'nowrap' }}>
|
|
|
<Button variant='contained' color="primary" onClick={handleSubmit} sx={{ marginRight: "1rem" }}>
|
|
|
<SaveIcon sx={{ fontSize: "1.5rem", marginRight: "0.5rem" }} />
|
|
|
レシピを保存
|
|
|
</Button>
|
|
|
<Button variant='contained' color="primary" onClick={handleSubmitAndAddToBuy}>
|
|
|
<ListAltIcon sx={{ fontSize: "1.5rem", marginRight: "0.5rem" }} />
|
|
|
保存して買うものリストへ追加
|
|
|
</Button>
|
|
|
</div>
|
|
|
|
|
|
{/* 新規材料追加ダイアログ */}
|
|
|
<AddStuffAmountDialog openDialog={openAddDialog} setOpenDialog={setOpenAddDialog} newItem={newItem} setNewItem={setNewItem}
|
|
|
onSubmit={() => {
|
|
|
console.log('newItem:', newItem);
|
|
|
setItems([...items, newItem]);
|
|
|
setOpenAddDialog(false);
|
|
|
}} />
|
|
|
|
|
|
{/* 削除ダイアログ */}
|
|
|
<Dialog open={openDeleteDialog} onClose={() => setOpenDeleteDialog(false)} disableScrollLock={true}
|
|
|
fullWidth
|
|
|
maxWidth="sm"
|
|
|
sx={{ overflow: "hidden" }}
|
|
|
>
|
|
|
<DialogTitle>食材の削除</DialogTitle>
|
|
|
<DialogContent>
|
|
|
{editingItem && (
|
|
|
<>
|
|
|
<Typography variant="h4">{editingItem.stuffName}を削除します。</Typography>
|
|
|
<Typography variant="body1" color="error">⚠️ 注意: 削除すると復元できません。</Typography>
|
|
|
<Button onClick={() => setOpenDeleteDialog(false)} sx={{ mt: 3, mb: 2, left: '70%' }}>キャンセル</Button>
|
|
|
<Button variant="contained" color="error" onClick={() => {
|
|
|
setItems([...items.slice(0, editingItemIdx), ...items.slice(editingItemIdx + 1)])
|
|
|
setOpenDeleteDialog(false); // 削除処理後にダイアログを閉じる
|
|
|
}}
|
|
|
style={{ marginTop: "10px" }} sx={{ mt: 3, mb: 2, left: '72%' }}>削除</Button>
|
|
|
</>
|
|
|
)}
|
|
|
</DialogContent>
|
|
|
</Dialog>
|
|
|
|
|
|
{/* 数量変更ダイアログ */}
|
|
|
<EditAmountDialog openDialog={openAmountDialog} setOpenDialog={setOpenAmountDialog}
|
|
|
editingItem={editingItem}
|
|
|
setEditingItem={(v) => setEditingItem({ ...editingItem, ...v })}
|
|
|
onSubmit={() => {
|
|
|
setItems([...items.slice(0, editingItemIdx), editingItem, ...items.slice(editingItemIdx + 1)])
|
|
|
setOpenAmountDialog(false);
|
|
|
}} />
|
|
|
|
|
|
</Box>
|
|
|
);
|
|
|
};
|
|
|
|
|
|
export default AddRecipe; |