|
|
|
@ -27,6 +27,7 @@ import { |
|
|
|
|
MenuItem, |
|
|
|
|
} from '@mui/material'; |
|
|
|
|
import { GENERAL_ERRORS, STOCK_ERRORS } from '../constants/errorMessages'; |
|
|
|
|
import { Add as AddIcon } from '@mui/icons-material'; |
|
|
|
|
import DatePicker, { registerLocale } from 'react-datepicker'; |
|
|
|
|
import { ja } from 'date-fns/locale/ja'; // date-fnsの日本語ロケールをインポート
|
|
|
|
|
import { useMessage } from '../components/MessageContext'; |
|
|
|
@ -115,6 +116,27 @@ const StockPage: React.FC = () => { |
|
|
|
|
newStock.shop = newStock.shop || null; |
|
|
|
|
|
|
|
|
|
console.log(newStock) |
|
|
|
|
|
|
|
|
|
// 購入日と消費・賞味期限の整合性チェック
|
|
|
|
|
const buy = new Date(newStock.buyDate); |
|
|
|
|
const exp = new Date(newStock.expDate); |
|
|
|
|
// 時間をリセットして純粋な“日付のみ”のタイムスタンプを取得
|
|
|
|
|
const buyDateOnly = new Date(buy); |
|
|
|
|
buyDateOnly.setHours(0, 0, 0, 0); |
|
|
|
|
const expDateOnly = new Date(exp); |
|
|
|
|
expDateOnly.setHours(0, 0, 0, 0); |
|
|
|
|
|
|
|
|
|
// console.log("新規作成buy:", buy);
|
|
|
|
|
// console.log("新規作成exp:", exp);
|
|
|
|
|
// console.log("新規作成buyDateOnly:", buyDateOnly);
|
|
|
|
|
// console.log("新規作成expDateOnly:", expDateOnly);
|
|
|
|
|
|
|
|
|
|
if (buyDateOnly.getTime() > expDateOnly.getTime()) { |
|
|
|
|
// alert("購入日は消費・賞味期限より前の日付を設定してください。");
|
|
|
|
|
showErrorMessage('購入日は消費・賞味期限より前の日付を設定してください.'); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const today = new Date().toISOString().substring(0, 10); |
|
|
|
|
|
|
|
|
|
const updatedStock = { ...newStock, lastUpdate: today }; // lastUpdate に today を設定
|
|
|
|
@ -197,37 +219,42 @@ const StockPage: React.FC = () => { |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* セルを選択する関数. 再度クリックで選択解除 → 行選択ではなくチェックボックスにしたため不要 |
|
|
|
|
* セルを選択して編集画面 |
|
|
|
|
*/ |
|
|
|
|
// const handleRowClick = (stock: Stock) => {
|
|
|
|
|
// setSelectedRow(prev => (prev?.stockId === stock.stockId ? null : stock));
|
|
|
|
|
// };
|
|
|
|
|
// チェックボックス切り替え
|
|
|
|
|
const handleCheckboxChange = (stock: Stock) => { |
|
|
|
|
setSelectedRow(prev => (prev?.stockId === stock.stockId ? null : stock)); |
|
|
|
|
const handleRowClick = (stock: Stock) => { |
|
|
|
|
setSelectedRow(stock); // 行選択
|
|
|
|
|
setEditStock({ ...stock }); // 編集対象にセット
|
|
|
|
|
setIsEditOpen(true); // 編集ダイアログを開く
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** 編集ボタンを押したときにダイアログを開く */ |
|
|
|
|
// ダイアログを開く際に `selectedRow` の値を `editStock` にセット
|
|
|
|
|
const handleOpenEdit = () => { |
|
|
|
|
if (selectedRow) { |
|
|
|
|
setEditStock({ ...selectedRow }); |
|
|
|
|
setIsEditOpen(true); |
|
|
|
|
} else { |
|
|
|
|
showWarningMessage("編集する食材を選択してください。"); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
// 変更を適用. 数量に0を入力したとき、削除ダイアログに飛ぶ機能を追加
|
|
|
|
|
const handleApplyChanges = async () => { |
|
|
|
|
if (!editStock) return; |
|
|
|
|
|
|
|
|
|
const {stockId, amount, buyAmount, price, shop, buyDate, expDate, lastUpdate} = editStock; |
|
|
|
|
// 購入日が消費・賞味期限より未来の場合はエラー表示
|
|
|
|
|
const buy = new Date(buyDate); |
|
|
|
|
const exp = new Date(expDate); |
|
|
|
|
// 時間をリセットして純粋な“日付のみ”のタイムスタンプを取得
|
|
|
|
|
const buyDateOnly = new Date(buy); |
|
|
|
|
buyDateOnly.setHours(0, 0, 0, 0); |
|
|
|
|
const expDateOnly = new Date(exp); |
|
|
|
|
expDateOnly.setHours(0, 0, 0, 0); |
|
|
|
|
// console.log("編集buy:", buy);
|
|
|
|
|
// console.log("編集exp:", exp);
|
|
|
|
|
// console.log("編集buyDateOnly:", buyDateOnly);
|
|
|
|
|
// console.log("編集expDateOnly:", expDateOnly);
|
|
|
|
|
|
|
|
|
|
if (buy > exp) { |
|
|
|
|
// alert("購入日は消費・賞味期限より前の日付を設定してください。");
|
|
|
|
|
showErrorMessage('購入日は消費・賞味期限より前の日付を設定してください.'); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
if (amount === 0) { |
|
|
|
|
// 数量が 0 の場合は削除処理へ誘導
|
|
|
|
|
setIsEditOpen(false); // 編集ダイアログを閉じる
|
|
|
|
|
// setIsEditOpen(false); // 編集ダイアログを閉じる
|
|
|
|
|
setSelectedRow(editStock); // 削除対象をセット
|
|
|
|
|
setIsDeleteOpen(true); // 削除ダイアログを開く
|
|
|
|
|
return; |
|
|
|
@ -297,7 +324,6 @@ const StockPage: React.FC = () => { |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** 編集ダイアログを閉じる */ |
|
|
|
|
const handleCloseEdit = () => { |
|
|
|
|
setIsEditOpen(false); |
|
|
|
@ -308,7 +334,8 @@ const StockPage: React.FC = () => { |
|
|
|
|
if (selectedRow) { |
|
|
|
|
setIsDeleteOpen(true); |
|
|
|
|
} else { |
|
|
|
|
showWarningMessage("削除する食材を選択してください。"); |
|
|
|
|
// showWarningMessage("削除する食材を選択してください。");
|
|
|
|
|
showErrorMessage('削除する食材を選択してください.'); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
/** 削除ダイアログを閉じる */ |
|
|
|
@ -328,37 +355,38 @@ const StockPage: React.FC = () => { |
|
|
|
|
<Table> |
|
|
|
|
<TableHead sx={{ backgroundColor: "#dcdcdc", color: "#333" }}> |
|
|
|
|
<TableRow> |
|
|
|
|
<TableCell padding="checkbox" /> |
|
|
|
|
<TableCell>食材名</TableCell> |
|
|
|
|
<TableCell>数量</TableCell> |
|
|
|
|
<TableCell>消費・賞味期限</TableCell> |
|
|
|
|
<TableCell align="center" sx={{ width: '40%', fontSize: '16px' }}>食材名</TableCell> |
|
|
|
|
<TableCell align="center" sx={{ width: '20%', fontSize: '16px' }}>数量</TableCell> |
|
|
|
|
<TableCell align="center" sx={{ width: '40%', fontSize: '16px' }}>消費・賞味期限</TableCell> |
|
|
|
|
</TableRow> |
|
|
|
|
</TableHead> |
|
|
|
|
<TableBody> |
|
|
|
|
{filteredStocks.map(stock => { |
|
|
|
|
const isSelected = selectedRow?.stockId === stock.stockId; |
|
|
|
|
const today = new Date(); |
|
|
|
|
const expDate = new Date(stock.expDate); |
|
|
|
|
const timeDiff = expDate.getTime() - today.getTime(); |
|
|
|
|
// 時間をリセットして純粋な“日付のみ”のタイムスタンプを取得
|
|
|
|
|
const todayDateOnly = new Date(today); |
|
|
|
|
todayDateOnly.setHours(0, 0, 0, 0); |
|
|
|
|
const expDateOnly = new Date(expDate); |
|
|
|
|
expDateOnly.setHours(0, 0, 0, 0); |
|
|
|
|
const timeDiff = expDateOnly.getTime() - todayDateOnly.getTime(); |
|
|
|
|
const daysLeft = Math.ceil(timeDiff / (1000 * 60 * 60 * 24)); |
|
|
|
|
|
|
|
|
|
// console.log("テーブルtoday:", today);
|
|
|
|
|
// console.log("テーブルexp:", expDate);
|
|
|
|
|
// console.log("テーブルtodayDateOnly:", todayDateOnly);
|
|
|
|
|
// console.log("テーブルexpDateOnly:", expDateOnly);
|
|
|
|
|
// console.log("日数差:", daysLeft);
|
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
<TableRow |
|
|
|
|
key={stock.stockId} |
|
|
|
|
sx={{ |
|
|
|
|
backgroundColor: isSelected ? 'yellow' : 'white', |
|
|
|
|
}} |
|
|
|
|
|
|
|
|
|
onClick={() => handleRowClick(stock)} |
|
|
|
|
style={{ backgroundColor: selectedRow?.stockId === stock.stockId ? "yellow" : "white", cursor: "pointer" }} |
|
|
|
|
> |
|
|
|
|
<TableCell padding="checkbox"> |
|
|
|
|
<Checkbox |
|
|
|
|
checked={isSelected} |
|
|
|
|
onChange={() => handleCheckboxChange(stock)} |
|
|
|
|
/> |
|
|
|
|
</TableCell> |
|
|
|
|
<TableCell>{stock.stuffName}</TableCell> |
|
|
|
|
<TableCell>{stock.amount}</TableCell> |
|
|
|
|
<TableCell |
|
|
|
|
<TableCell align="center" sx={{ width: '40%', fontSize: '16px' }}>{stock.stuffName}</TableCell> |
|
|
|
|
<TableCell align="center" sx={{ width: '20%', fontSize: '16px' }}>{stock.amount}</TableCell> |
|
|
|
|
<TableCell align="center" sx={{ width: '40%', fontSize: '16px' }} |
|
|
|
|
style={daysLeft <= 3 ? { color: "red", fontWeight: "bold" } : {}} |
|
|
|
|
> |
|
|
|
|
{formatDate(stock.expDate)} |
|
|
|
@ -370,16 +398,19 @@ const StockPage: React.FC = () => { |
|
|
|
|
</Table> |
|
|
|
|
</TableContainer> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{/* 編集ダイアログ */} |
|
|
|
|
<Dialog open={isEditOpen} onClose={handleCloseEdit} fullWidth maxWidth="sm"> |
|
|
|
|
<DialogTitle>在庫の編集</DialogTitle> |
|
|
|
|
<DialogTitle> |
|
|
|
|
<Typography variant="h5" > |
|
|
|
|
在庫の編集 |
|
|
|
|
</Typography> |
|
|
|
|
</DialogTitle> |
|
|
|
|
<DialogContent> |
|
|
|
|
{editStock && ( |
|
|
|
|
<> |
|
|
|
|
|
|
|
|
|
{/* 材料名 */} |
|
|
|
|
<Typography variant="h4">{editStock.stuffName}</Typography> |
|
|
|
|
<Typography variant="h4">【{editStock.stuffName}】</Typography> |
|
|
|
|
|
|
|
|
|
<TextField |
|
|
|
|
label="現在の数量" |
|
|
|
@ -490,9 +521,10 @@ const StockPage: React.FC = () => { |
|
|
|
|
<Button onClick={() => { setIsEditOpen(false); setSelectedRow(null); }}> |
|
|
|
|
キャンセル |
|
|
|
|
</Button> |
|
|
|
|
<Button variant="contained" color="success" onClick={handleApplyChanges}> |
|
|
|
|
<Button variant="contained" color="success" onClick={handleApplyChanges} sx={{ mt: 3, mb: 2 }}> |
|
|
|
|
変更を適用 |
|
|
|
|
</Button> |
|
|
|
|
<Button variant="contained" color="error" onClick={handleOpenDelete} sx={{ mt: 3, mb: 2 }}>削除</Button> |
|
|
|
|
</Box> |
|
|
|
|
</> |
|
|
|
|
)} |
|
|
|
@ -506,7 +538,11 @@ const StockPage: React.FC = () => { |
|
|
|
|
maxWidth="sm" |
|
|
|
|
sx={{ overflow: "hidden" }} |
|
|
|
|
> |
|
|
|
|
<DialogTitle>食材の削除</DialogTitle> |
|
|
|
|
<DialogTitle> |
|
|
|
|
<Typography variant="h5" > |
|
|
|
|
食材の削除 |
|
|
|
|
</Typography> |
|
|
|
|
</DialogTitle> |
|
|
|
|
<DialogContent> |
|
|
|
|
{selectedRow && ( |
|
|
|
|
<> |
|
|
|
@ -516,7 +552,7 @@ const StockPage: React.FC = () => { |
|
|
|
|
<Box sx={{ display: 'flex', justifyContent: 'flex-end', gap: 2, mt: 3, mb: 2 }}> |
|
|
|
|
<Button onClick={() => { |
|
|
|
|
setIsDeleteOpen(false); |
|
|
|
|
setSelectedRow(null); |
|
|
|
|
// setSelectedRow(null);
|
|
|
|
|
}}> |
|
|
|
|
キャンセル |
|
|
|
|
</Button> |
|
|
|
@ -527,6 +563,7 @@ const StockPage: React.FC = () => { |
|
|
|
|
handleDeleteStock(selectedRow.stockId); |
|
|
|
|
setIsDeleteOpen(false); |
|
|
|
|
setSelectedRow(null); |
|
|
|
|
setIsEditOpen(false); |
|
|
|
|
}} |
|
|
|
|
> |
|
|
|
|
削除 |
|
|
|
@ -540,38 +577,51 @@ const StockPage: React.FC = () => { |
|
|
|
|
); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
<Container> |
|
|
|
|
<Typography variant="h4" component="h1" gutterBottom> |
|
|
|
|
在庫一覧 |
|
|
|
|
<Typography variant="h3" component="h1" sx={{ mb: 4 }} > |
|
|
|
|
在庫リスト |
|
|
|
|
</Typography> |
|
|
|
|
|
|
|
|
|
{/* <Box sx={{ textAlign: 'right' }}> */} |
|
|
|
|
<Box |
|
|
|
|
sx={{ |
|
|
|
|
position: 'sticky', |
|
|
|
|
top: 0, |
|
|
|
|
zIndex: 1000, |
|
|
|
|
position: 'fixed', // ← sticky から fixed に変更
|
|
|
|
|
bottom: 55, // ← 下に固定
|
|
|
|
|
left: 0, |
|
|
|
|
right: 0, |
|
|
|
|
zIndex: 1300, // ダイアログよりは低く
|
|
|
|
|
backgroundColor: '#f5f5f5', |
|
|
|
|
padding: 2, |
|
|
|
|
// backgroundColor: 'white',
|
|
|
|
|
// padding: 2,
|
|
|
|
|
px: 2, |
|
|
|
|
py: 1, |
|
|
|
|
display: 'flex', |
|
|
|
|
gap: 0.5, |
|
|
|
|
justifyContent: 'flex-end', // ← 右寄せ
|
|
|
|
|
borderBottom: 'none', // ← これで線を消す
|
|
|
|
|
boxShadow: 'none', // ← 影も消す
|
|
|
|
|
justifyContent: 'flex-end', // ← 左寄せ
|
|
|
|
|
boxShadow: 'none', // 軽めの上向きシャドウ
|
|
|
|
|
}} |
|
|
|
|
> |
|
|
|
|
|
|
|
|
|
{/* 在庫の食材追加ボタン */} |
|
|
|
|
<Button variant="contained" color="primary" onClick={handleOpenAdd} sx={{ mt: 3, mb: 2, mr: 1 }}> |
|
|
|
|
追加 |
|
|
|
|
</Button> |
|
|
|
|
<Box sx={{ |
|
|
|
|
display: 'flex', flexDirection: 'column', alignItems: 'flex-end', |
|
|
|
|
mr: 2, |
|
|
|
|
}}> |
|
|
|
|
<Typography variant="caption" color="textSecondary"> |
|
|
|
|
食材の追加 |
|
|
|
|
</Typography> |
|
|
|
|
<Fab color="primary" onClick={handleOpenAdd} > |
|
|
|
|
<AddIcon /> |
|
|
|
|
</Fab> |
|
|
|
|
</Box> |
|
|
|
|
|
|
|
|
|
{/* 新規タスク作成ダイアログ */} |
|
|
|
|
<Dialog open={isAddOpen} onClose={handleCloseAdd} disableScrollLock={true}> |
|
|
|
|
<Box display="flex" alignItems="center" > |
|
|
|
|
<DialogTitle sx={{ flexGrow: 1 }}>在庫に食材を追加</DialogTitle> |
|
|
|
|
<DialogTitle sx={{ flexGrow: 1 }}> |
|
|
|
|
<Typography variant="h5" > |
|
|
|
|
在庫に食材を追加 |
|
|
|
|
</Typography> |
|
|
|
|
</DialogTitle> |
|
|
|
|
<FormGroup row> |
|
|
|
|
<FormControlLabel |
|
|
|
|
control={<Checkbox />} |
|
|
|
@ -708,17 +758,6 @@ const StockPage: React.FC = () => { |
|
|
|
|
</Button> |
|
|
|
|
</DialogActions> |
|
|
|
|
</Dialog> |
|
|
|
|
|
|
|
|
|
{/* 在庫の食材編集ボタン(全テーブル共通) */} |
|
|
|
|
<Button variant="contained" color="success" onClick={handleOpenEdit} sx={{ |
|
|
|
|
mt: 3, mb: 2, mr: 1 |
|
|
|
|
}}> |
|
|
|
|
詳細・編集 |
|
|
|
|
</Button> |
|
|
|
|
|
|
|
|
|
{/* 在庫の食材削除ボタン (全テーブル共通) */} |
|
|
|
|
<Button variant="contained" color="error" onClick={handleOpenDelete} sx={{ mt: 3, mb: 2 }}>削除</Button> |
|
|
|
|
|
|
|
|
|
</Box> |
|
|
|
|
|
|
|
|
|
{/* 在庫一覧リスト */} |
|
|
|
@ -751,6 +790,7 @@ const StockPage: React.FC = () => { |
|
|
|
|
<div style={{ border: '3px solid black', borderRadius: '8px', backgroundColor: '#add8e6', height: 'auto', padding: '20px', marginBottom: "20px" }}> |
|
|
|
|
{StockTable(stocks, ["その他"])} |
|
|
|
|
</div> |
|
|
|
|
<Box sx={{ height: '80px' }} /> {/* フッターの高さと同じくらいに調整 */} |
|
|
|
|
</Container> |
|
|
|
|
); |
|
|
|
|
}; |
|
|
|
|