|
|
|
@ -25,7 +25,8 @@ import { |
|
|
|
|
Select, |
|
|
|
|
FormControl, |
|
|
|
|
InputLabel, |
|
|
|
|
ListItemIcon |
|
|
|
|
ListItemIcon, |
|
|
|
|
AlertColor |
|
|
|
|
} from '@mui/material'; |
|
|
|
|
import { |
|
|
|
|
Add as AddIcon, Delete as DeleteIcon, ShoppingBasket as ShoppingBasketIcon, |
|
|
|
@ -36,6 +37,8 @@ import { StuffAndCategoryAndAmount } from '../types/types'; |
|
|
|
|
import EditAmountDialog from '../components/EditAmountDialog'; |
|
|
|
|
import { recipeApi, toBuyApi } from '../services/api'; |
|
|
|
|
import { useNavigate, useParams } from 'react-router-dom'; |
|
|
|
|
import MessageAlert from '../components/MessageAlert'; |
|
|
|
|
import { useMessage } from '../components/MessageContext'; |
|
|
|
|
|
|
|
|
|
const AddRecipe: React.FC = () => { |
|
|
|
|
const { recipeId: recipeIdStr } = useParams(); |
|
|
|
@ -43,6 +46,8 @@ const AddRecipe: React.FC = () => { |
|
|
|
|
|
|
|
|
|
const navigate = useNavigate(); |
|
|
|
|
|
|
|
|
|
// 編集時,既存情報を読み込んだかどうか
|
|
|
|
|
const [recipeLoaded, setRecipeLoaded] = useState(false); |
|
|
|
|
// 料理名,説明
|
|
|
|
|
const [recipeName, setRecipeName] = useState<string>(''); |
|
|
|
|
const [recipeSummary, setRecipeSummary] = useState<string>(''); |
|
|
|
@ -58,53 +63,64 @@ const AddRecipe: React.FC = () => { |
|
|
|
|
// 編集しているアイテム
|
|
|
|
|
const [editingItem, setEditingItem] = useState<StuffAndCategoryAndAmount>(emptyItem); |
|
|
|
|
const [editingItemIdx, setEditingItemIdx] = useState(0); |
|
|
|
|
//削除確認ダイアログの表示状態
|
|
|
|
|
const [openDeleteDialog, setOpenDeleteDialog] = useState(false); |
|
|
|
|
|
|
|
|
|
// エラーメッセージ表示
|
|
|
|
|
const { showErrorMessage, showSuccessMessage } = useMessage(); |
|
|
|
|
|
|
|
|
|
const loadRecipe = async () => { |
|
|
|
|
if (recipeId && !recipeName) { |
|
|
|
|
if (recipeId && !recipeLoaded) { |
|
|
|
|
const recipe = await recipeApi.getById(recipeId); |
|
|
|
|
console.log('loaded recipe=', recipe) |
|
|
|
|
setRecipeName(recipe.recipeName) |
|
|
|
|
setRecipeSummary(recipe.summary) |
|
|
|
|
setItems(recipe.stuffAndAmountArray) |
|
|
|
|
setRecipeLoaded(true) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const handleSaveRecipe = async () => { |
|
|
|
|
|
|
|
|
|
if (!recipeName) { |
|
|
|
|
alert('レシピ名が入力されていません!') |
|
|
|
|
showErrorMessage('レシピ名が入力されていません!') |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!items.length) { |
|
|
|
|
alert('材料が追加されていません!') |
|
|
|
|
showErrorMessage('材料が追加されていません!') |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!recipeId) { |
|
|
|
|
// 新規追加
|
|
|
|
|
const response = await recipeApi.addRecipe({ |
|
|
|
|
try { |
|
|
|
|
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 response.recipeId; |
|
|
|
|
} catch { |
|
|
|
|
showErrorMessage('レシピの送信に失敗しました。同じ料理名が存在する可能性があります。'); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const response = await recipeApi.updateRecipe({ |
|
|
|
|
recipeId, |
|
|
|
|
recipeName, |
|
|
|
|
summary: recipeSummary, |
|
|
|
|
stuffAndAmountArray: items, |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
return recipeId; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const handleSubmit = async () => { |
|
|
|
|
const recipeId = await handleSaveRecipe(); |
|
|
|
|
// alert('レシピが保存されました!');
|
|
|
|
|
if (!recipeId) return; |
|
|
|
|
showSuccessMessage('レシピが保存されました!'); |
|
|
|
|
navigate('/recipeList'); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -112,7 +128,7 @@ const AddRecipe: React.FC = () => { |
|
|
|
|
const recipeId = await handleSaveRecipe(); |
|
|
|
|
if (!recipeId) return false; |
|
|
|
|
await toBuyApi.addByRecipe(recipeId); |
|
|
|
|
// alert('レシピが保存されて買うものリストに追加されました!');
|
|
|
|
|
showSuccessMessage('レシピが保存されて買うものリストに追加されました!'); |
|
|
|
|
navigate('/tasks'); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -122,7 +138,8 @@ const AddRecipe: React.FC = () => { |
|
|
|
|
}, []); |
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
(recipeId && !recipeName) |
|
|
|
|
<> |
|
|
|
|
{(recipeId && !recipeLoaded) |
|
|
|
|
? <p>読み込み中...</p> |
|
|
|
|
: |
|
|
|
|
<Box> |
|
|
|
@ -138,7 +155,7 @@ const AddRecipe: React.FC = () => { |
|
|
|
|
value={recipeSummary} onChange={(e) => setRecipeSummary(e.target.value)} |
|
|
|
|
/> |
|
|
|
|
</div> |
|
|
|
|
<h2 style={{marginTop: "0.5em" }}> |
|
|
|
|
<h2 style={{ marginTop: "0.5em" }}> |
|
|
|
|
材料リスト |
|
|
|
|
</h2> |
|
|
|
|
{/* すべての材料情報を表示 */} |
|
|
|
@ -179,7 +196,11 @@ const AddRecipe: React.FC = () => { |
|
|
|
|
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={() => setItems([...items.slice(0, index), ...items.slice(index + 1)])}> |
|
|
|
|
onClick={() => { |
|
|
|
|
setOpenDeleteDialog(true) |
|
|
|
|
setEditingItem(item) |
|
|
|
|
setEditingItemIdx(index) |
|
|
|
|
}}> |
|
|
|
|
<DeleteIcon /> |
|
|
|
|
</IconButton> |
|
|
|
|
</Tooltip> |
|
|
|
@ -200,7 +221,7 @@ const AddRecipe: React.FC = () => { |
|
|
|
|
</Fab> |
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
<div style={{ position: "fixed", left: "50%", transform: 'translateX(-50%)', bottom: "2%", whiteSpace: 'nowrap' }}> |
|
|
|
|
<div style={{ position: "fixed", left: "50%", transform: 'translateX(-50%)', bottom: "64px", whiteSpace: 'nowrap' }}> |
|
|
|
|
<Button variant='contained' color="primary" onClick={handleSubmit} sx={{ marginRight: "1rem" }}> |
|
|
|
|
<SaveIcon sx={{ fontSize: "1.5rem", marginRight: "0.5rem" }} /> |
|
|
|
|
レシピを保存 |
|
|
|
@ -219,6 +240,29 @@ const AddRecipe: React.FC = () => { |
|
|
|
|
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} |
|
|
|
@ -229,6 +273,8 @@ const AddRecipe: React.FC = () => { |
|
|
|
|
}} /> |
|
|
|
|
|
|
|
|
|
</Box> |
|
|
|
|
} |
|
|
|
|
</> |
|
|
|
|
); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|