|
|
@ -1,11 +1,19 @@ |
|
|
|
import React, { useEffect, useState } from 'react'; |
|
|
|
import React, { useEffect, useState } from 'react'; |
|
|
|
import { |
|
|
|
import { |
|
|
|
Dialog, |
|
|
|
Dialog, |
|
|
|
DialogTitle, |
|
|
|
DialogTitle, |
|
|
|
DialogContent, |
|
|
|
DialogContent, |
|
|
|
DialogActions, |
|
|
|
DialogActions, |
|
|
|
Button, |
|
|
|
Button, |
|
|
|
Box, |
|
|
|
Box, |
|
|
|
|
|
|
|
List, |
|
|
|
|
|
|
|
ListItem, |
|
|
|
|
|
|
|
ListItemText, |
|
|
|
|
|
|
|
ListItemSecondaryAction, |
|
|
|
|
|
|
|
Typography, |
|
|
|
|
|
|
|
TextField, |
|
|
|
|
|
|
|
FormControlLabel, |
|
|
|
|
|
|
|
Checkbox, |
|
|
|
} from '@mui/material'; |
|
|
|
} from '@mui/material'; |
|
|
|
|
|
|
|
|
|
|
|
import { toBuyApi } from '../services/api'; |
|
|
|
import { toBuyApi } from '../services/api'; |
|
|
@ -13,112 +21,138 @@ import { recipeApi } from '../services/api'; |
|
|
|
|
|
|
|
|
|
|
|
import CloseIcon from '@mui/icons-material/Close'; |
|
|
|
import CloseIcon from '@mui/icons-material/Close'; |
|
|
|
import { RecipeDetailWithId, StuffNameAndAmount } from '../types/types'; |
|
|
|
import { RecipeDetailWithId, StuffNameAndAmount } from '../types/types'; |
|
|
|
|
|
|
|
import { GENERAL_ERRORS } from '../constants/errorMessages'; |
|
|
|
|
|
|
|
import { useNavigate } from 'react-router-dom'; |
|
|
|
|
|
|
|
import { useMessage } from './MessageContext'; |
|
|
|
|
|
|
|
|
|
|
|
const AddByRecipeDialog = ({ |
|
|
|
const AddByRecipeDialog = ({ |
|
|
|
openDialog, |
|
|
|
openDialog, |
|
|
|
setOpenDialog, |
|
|
|
setOpenDialog, |
|
|
|
recipeId, |
|
|
|
recipeId, |
|
|
|
numOfPeople, |
|
|
|
numOfPeople, |
|
|
|
setNumOfPeaple, |
|
|
|
setNumOfPeaple, |
|
|
|
checked, |
|
|
|
checked, |
|
|
|
setChecked |
|
|
|
setChecked |
|
|
|
}: { |
|
|
|
}: { |
|
|
|
openDialog: boolean, |
|
|
|
openDialog: boolean, |
|
|
|
setOpenDialog: (open: boolean) => void, |
|
|
|
setOpenDialog: (open: boolean) => void, |
|
|
|
recipeId: number, |
|
|
|
recipeId: number, |
|
|
|
numOfPeople: number, |
|
|
|
numOfPeople: number, |
|
|
|
setNumOfPeaple: (num: number) => void, |
|
|
|
setNumOfPeaple: (num: number) => void, |
|
|
|
checked: boolean, |
|
|
|
checked: boolean, |
|
|
|
setChecked: (checked: boolean) => void |
|
|
|
setChecked: (checked: boolean) => void |
|
|
|
}) => { |
|
|
|
}) => { |
|
|
|
const [recipe, setRecipe] = useState<RecipeDetailWithId>(); |
|
|
|
const [recipe, setRecipe] = useState<RecipeDetailWithId>(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
|
|
|
console.log("called AddByRecipeDialog useEffect recipeId: ", recipeId); |
|
|
|
|
|
|
|
if (recipeId) { |
|
|
|
|
|
|
|
const fetchRecipe = async () => { |
|
|
|
|
|
|
|
console.log("Fetching recipe with ID:", recipeId); |
|
|
|
|
|
|
|
setRecipe(await recipeApi.getById(recipeId)); |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
fetchRecipe(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}, [recipeId]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
|
|
|
recipe ?
|
|
|
|
|
|
|
|
<Dialog open={openDialog} onClose={() => setOpenDialog(false)} disableScrollLock={true} PaperProps={{ sx: { minWidth: '300px', maxHeight: '80vh' } }}> |
|
|
|
|
|
|
|
<DialogTitle sx={{ m: 0, p: 2, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
買うものリストへ追加 |
|
|
|
useEffect(() => { |
|
|
|
<CloseIcon |
|
|
|
console.log("called AddByRecipeDialog useEffect recipeId: ", recipeId); |
|
|
|
onClick={() => setOpenDialog(false)} |
|
|
|
if (recipeId) { |
|
|
|
sx={{ |
|
|
|
const fetchRecipe = async () => { |
|
|
|
cursor: 'pointer', |
|
|
|
console.log("Fetching recipe with ID:", recipeId); |
|
|
|
color: (theme) => theme.palette.grey[500], |
|
|
|
setRecipe(await recipeApi.getById(recipeId)); |
|
|
|
}} |
|
|
|
}; |
|
|
|
/> |
|
|
|
fetchRecipe(); |
|
|
|
</DialogTitle> |
|
|
|
} |
|
|
|
<DialogContent dividers sx={{ padding: 2 }}> |
|
|
|
}, [recipeId]); |
|
|
|
<div> |
|
|
|
|
|
|
|
<strong>レシピ名:</strong> {recipe.recipeName} |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
<div> |
|
|
|
|
|
|
|
({recipe.maxServings}人分在庫あり) |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
<div> |
|
|
|
|
|
|
|
<strong>材料(1人前):</strong> |
|
|
|
|
|
|
|
<ul> |
|
|
|
|
|
|
|
{recipe.stuffAndAmountArray.map((item, index) => ( |
|
|
|
|
|
|
|
<li key={index}> |
|
|
|
|
|
|
|
{item.stuffName} - {item.amount}個 |
|
|
|
|
|
|
|
</li> |
|
|
|
|
|
|
|
))} |
|
|
|
|
|
|
|
</ul> |
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{/* 在庫との差分を取るかのチェックボックス */} |
|
|
|
|
|
|
|
<div> |
|
|
|
|
|
|
|
<label> |
|
|
|
|
|
|
|
<input |
|
|
|
|
|
|
|
type="checkbox" |
|
|
|
|
|
|
|
checked={checked} |
|
|
|
|
|
|
|
onChange={(e) => setChecked(e.target.checked)} |
|
|
|
|
|
|
|
/> |
|
|
|
|
|
|
|
在庫との差分を取る |
|
|
|
|
|
|
|
</label> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{/* レシピを追加する人数分を入力 */} |
|
|
|
const navigate = useNavigate(); |
|
|
|
<div> |
|
|
|
|
|
|
|
<strong>人数:</strong> |
|
|
|
|
|
|
|
<input |
|
|
|
|
|
|
|
type="number" |
|
|
|
|
|
|
|
min="1" |
|
|
|
|
|
|
|
defaultValue={1} |
|
|
|
|
|
|
|
onChange={(e) => { |
|
|
|
|
|
|
|
setNumOfPeaple(parseInt(e.target.value, 10)); |
|
|
|
|
|
|
|
}} |
|
|
|
|
|
|
|
/> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{/* 買うものリストに追加するボタン */} |
|
|
|
// エラーメッセージ表示
|
|
|
|
<Box sx={{ mt: 2 }}> |
|
|
|
const { showErrorMessage, showSuccessMessage, showInfoMessage } = useMessage(); |
|
|
|
<Button |
|
|
|
|
|
|
|
variant="contained" |
|
|
|
|
|
|
|
color="primary" |
|
|
|
|
|
|
|
onClick={() => { |
|
|
|
|
|
|
|
toBuyApi.addByRecipe(recipe.recipeId, numOfPeople, checked); |
|
|
|
|
|
|
|
setOpenDialog(false); |
|
|
|
|
|
|
|
}} |
|
|
|
|
|
|
|
> |
|
|
|
|
|
|
|
</Button> |
|
|
|
|
|
|
|
</Box> |
|
|
|
|
|
|
|
</DialogContent> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</Dialog> |
|
|
|
return ( |
|
|
|
: <></> |
|
|
|
recipe ? |
|
|
|
); |
|
|
|
<Dialog open={openDialog} onClose={() => setOpenDialog(false)} disableScrollLock={true} PaperProps={{ sx: { minWidth: '80vw', maxHeight: '80vh' } }}> |
|
|
|
|
|
|
|
<DialogTitle sx={{ m: 0, p: 2, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
買うものリストへ追加 |
|
|
|
|
|
|
|
<CloseIcon |
|
|
|
|
|
|
|
onClick={() => setOpenDialog(false)} |
|
|
|
|
|
|
|
sx={{ |
|
|
|
|
|
|
|
cursor: 'pointer', |
|
|
|
|
|
|
|
color: (theme) => theme.palette.grey[500], |
|
|
|
|
|
|
|
}} |
|
|
|
|
|
|
|
/> |
|
|
|
|
|
|
|
</DialogTitle> |
|
|
|
|
|
|
|
<DialogContent dividers sx={{ padding: 2 }}> |
|
|
|
|
|
|
|
<Typography variant="h3"> |
|
|
|
|
|
|
|
{recipe.recipeName} |
|
|
|
|
|
|
|
</Typography> |
|
|
|
|
|
|
|
<Typography> |
|
|
|
|
|
|
|
({recipe.maxServings}人分在庫あり) |
|
|
|
|
|
|
|
</Typography> |
|
|
|
|
|
|
|
<div> |
|
|
|
|
|
|
|
<strong>材料(1人前):</strong> |
|
|
|
|
|
|
|
<List> |
|
|
|
|
|
|
|
{recipe.stuffAndAmountArray.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> |
|
|
|
|
|
|
|
</ListItemSecondaryAction> |
|
|
|
|
|
|
|
</ListItem> |
|
|
|
|
|
|
|
))} |
|
|
|
|
|
|
|
</List> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
<div> |
|
|
|
|
|
|
|
{/* 人数入力フィールド */} |
|
|
|
|
|
|
|
<TextField |
|
|
|
|
|
|
|
type="number" |
|
|
|
|
|
|
|
margin="dense" |
|
|
|
|
|
|
|
label="何人前" |
|
|
|
|
|
|
|
fullWidth |
|
|
|
|
|
|
|
// min={1}
|
|
|
|
|
|
|
|
defaultValue={1} |
|
|
|
|
|
|
|
value={numOfPeople} |
|
|
|
|
|
|
|
onChange={(e) => { |
|
|
|
|
|
|
|
setNumOfPeaple(parseInt(e.target.value, 10)); |
|
|
|
|
|
|
|
}} |
|
|
|
|
|
|
|
sx={{ minWidth: "8px", width: "100%" }} |
|
|
|
|
|
|
|
inputProps={{ inputMode: "numeric", pattern: "[0-9]*" }} // ここで整数のみ許可
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
<FormControlLabel |
|
|
|
|
|
|
|
control={<Checkbox checked={checked} onChange={(e) => setChecked(e.target.checked)} />} |
|
|
|
|
|
|
|
label={<Typography>足りない食材のみ登録</Typography>} |
|
|
|
|
|
|
|
/> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{/* 買うものリストに追加するボタン */} |
|
|
|
|
|
|
|
<Box sx={{ mt: 2, textAlign: 'right' }}> |
|
|
|
|
|
|
|
<Button |
|
|
|
|
|
|
|
variant="contained" |
|
|
|
|
|
|
|
color="primary" |
|
|
|
|
|
|
|
onClick={async () => { |
|
|
|
|
|
|
|
if (!numOfPeople || isNaN(numOfPeople)) { |
|
|
|
|
|
|
|
showErrorMessage('人数が正しく入力されていません。'); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
const finalAddResult = await toBuyApi.addByRecipe(recipe.recipeId, numOfPeople, checked); |
|
|
|
|
|
|
|
setOpenDialog(false); |
|
|
|
|
|
|
|
if (finalAddResult.data.length === 0) { |
|
|
|
|
|
|
|
showInfoMessage('必要な食材が在庫にあったのでリストには追加されませんでした!'); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
showSuccessMessage('レシピが保存されて買うものリストに追加されました!'); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
navigate('/tasks'); |
|
|
|
|
|
|
|
}} |
|
|
|
|
|
|
|
> |
|
|
|
|
|
|
|
追加 |
|
|
|
|
|
|
|
</Button> |
|
|
|
|
|
|
|
</Box> |
|
|
|
|
|
|
|
</DialogContent> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</Dialog> |
|
|
|
|
|
|
|
: <></> |
|
|
|
|
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
export default AddByRecipeDialog; |
|
|
|
export default AddByRecipeDialog; |