|
|
|
@ -3,8 +3,8 @@ |
|
|
|
|
* 白紙の状態で表示されるテスト用のページ |
|
|
|
|
*/ |
|
|
|
|
import React, { useState, useEffect } from 'react'; |
|
|
|
|
import { stockApi } from '../services/api'; |
|
|
|
|
import { Stock } from '../types/types'; |
|
|
|
|
import { stockApi, stuffApi } from '../services/api'; |
|
|
|
|
import { Stock, Stuff } from '../types/types'; |
|
|
|
|
import { Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Paper } from "@mui/material"; |
|
|
|
|
import { |
|
|
|
|
Container, |
|
|
|
@ -18,15 +18,40 @@ import { |
|
|
|
|
TextField, |
|
|
|
|
Button, |
|
|
|
|
Box, |
|
|
|
|
|
|
|
|
|
Checkbox, |
|
|
|
|
FormControlLabel, |
|
|
|
|
FormGroup, |
|
|
|
|
FormControl, |
|
|
|
|
InputLabel, |
|
|
|
|
Select, |
|
|
|
|
MenuItem, |
|
|
|
|
} from '@mui/material'; |
|
|
|
|
import { STOCK_ERRORS } from '../constants/errorMessages'; |
|
|
|
|
|
|
|
|
|
// 新規在庫の初期状態
|
|
|
|
|
const EMPTY_STOCK: Omit<Stock, 'stockId' | 'stuffId'> & { stuffId: number | null } & { newAddition: boolean } = { |
|
|
|
|
stuffId: null, |
|
|
|
|
stuffName: '', |
|
|
|
|
amount: 0, |
|
|
|
|
price: 0, |
|
|
|
|
lastUpdate: '', |
|
|
|
|
buyDate: '', |
|
|
|
|
expDate: '', |
|
|
|
|
category: '', |
|
|
|
|
newAddition: false, // 材料を新規作成するか否か
|
|
|
|
|
// shop '',
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const StockPage: React.FC = () => { |
|
|
|
|
|
|
|
|
|
const [stocks, setStocks] = useState<Stock[]>([]); |
|
|
|
|
// セル選択の表示状態
|
|
|
|
|
const [selectedRow, setSelectedRow] = useState<Stock | null>(null); |
|
|
|
|
// 追加ダイアログボックスの表示状態
|
|
|
|
|
const [isAddOpen, setIsAddOpen] = useState(false); |
|
|
|
|
// 在庫追加に使う状態
|
|
|
|
|
const [newStock, setNewStock] = useState(EMPTY_STOCK); |
|
|
|
|
const [stuffs, setStuffs] = useState<Stuff[]>([]); |
|
|
|
|
// 編集ダイアロボックスの表示状態
|
|
|
|
|
const [isEditOpen, setIsEditOpen] = useState(false); |
|
|
|
|
// 削除メッセージダイアログの表示状態
|
|
|
|
@ -53,6 +78,25 @@ const StockPage: React.FC = () => { |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 在庫リストに新規食材を作成するハンドラー |
|
|
|
|
*/ |
|
|
|
|
const handleCreateStock = async () => { |
|
|
|
|
try { |
|
|
|
|
if (newStock.newAddition) { |
|
|
|
|
newStock.stuffId = null; |
|
|
|
|
} |
|
|
|
|
console.log(newStock) |
|
|
|
|
const today = new Date().toISOString().substring(0, 10); |
|
|
|
|
await stockApi.addStock(newStock); |
|
|
|
|
setIsAddOpen(false); // ダイアログを閉じる
|
|
|
|
|
setNewStock(EMPTY_STOCK); // 入力内容をリセット
|
|
|
|
|
fetchStocks(); // 作成後のタスク一覧を再取得
|
|
|
|
|
} catch (error) { |
|
|
|
|
console.error(`${STOCK_ERRORS.CREATE_FAILED}:`, error); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 在庫リストを編集するハンドラー |
|
|
|
|
*/ |
|
|
|
@ -79,6 +123,15 @@ const StockPage: React.FC = () => { |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* カテゴリー選択?? |
|
|
|
|
*/ |
|
|
|
|
const onChangeCategory = async (category: string) => { |
|
|
|
|
setNewStock({ ...newStock, category }) |
|
|
|
|
const result = await stuffApi.getStuffs(category) |
|
|
|
|
setStuffs(result) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 文字列(ISO 8601形式)をyyyy/MM/ddに変換する関数 |
|
|
|
|
*/ |
|
|
|
@ -98,6 +151,15 @@ const StockPage: React.FC = () => { |
|
|
|
|
}; |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
/** 追加ボタンを押したときにダイアログを開く */ |
|
|
|
|
const handleOpenAdd = () => { |
|
|
|
|
setIsAddOpen(true); |
|
|
|
|
}; |
|
|
|
|
/** 削除ダイアログを閉じる */ |
|
|
|
|
const handleCloseAdd = () => { |
|
|
|
|
setIsAddOpen(false); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* セルを選択する関数. 再度クリックで選択解除 |
|
|
|
|
*/ |
|
|
|
@ -315,12 +377,136 @@ const StockPage: React.FC = () => { |
|
|
|
|
在庫一覧 |
|
|
|
|
</Typography> |
|
|
|
|
|
|
|
|
|
{/* タスク編集ボタン(全テーブル共通) */} |
|
|
|
|
{/* 在庫の食材追加ボタン */} |
|
|
|
|
<Button variant="contained" color="primary" onClick={handleOpenAdd} sx={{ mt: 3, mb: 2, left: '78%' }}> |
|
|
|
|
追加 |
|
|
|
|
</Button> |
|
|
|
|
|
|
|
|
|
{/* 新規タスク作成ダイアログ */} |
|
|
|
|
<Dialog open={isAddOpen} onClose={() => setIsAddOpen(false)} disableScrollLock={true}> |
|
|
|
|
<Box display="flex" alignItems="center" > |
|
|
|
|
<DialogTitle sx={{ flexGrow: 1 }}>在庫に食材を追加</DialogTitle> |
|
|
|
|
<FormGroup row> |
|
|
|
|
<FormControlLabel |
|
|
|
|
control={<Checkbox />} |
|
|
|
|
label="食材を新規追加" |
|
|
|
|
checked={newStock.newAddition} |
|
|
|
|
onChange={(e) => setNewStock({ ...newStock, newAddition: (e.target as HTMLInputElement).checked })} |
|
|
|
|
/> |
|
|
|
|
</FormGroup> |
|
|
|
|
</Box> |
|
|
|
|
<DialogContent> |
|
|
|
|
<Box sx={{ pt: 1 }}> |
|
|
|
|
{/*材料カテゴリ選択 */} |
|
|
|
|
|
|
|
|
|
<FormControl sx={{ width: "50%", marginBottom: 2 }}> |
|
|
|
|
<InputLabel id="demo-simple-select-label">カテゴリ</InputLabel> |
|
|
|
|
<Select |
|
|
|
|
labelId="demo-simple-select-label" |
|
|
|
|
value={newStock.category} |
|
|
|
|
onChange={(e) => onChangeCategory(e.target.value)} |
|
|
|
|
> |
|
|
|
|
<MenuItem value="乳製品">乳製品</MenuItem> |
|
|
|
|
<MenuItem value="魚・肉">魚・肉</MenuItem> |
|
|
|
|
<MenuItem value="野菜">野菜</MenuItem> |
|
|
|
|
<MenuItem value="調味料">調味料</MenuItem> |
|
|
|
|
<MenuItem value="その他">その他</MenuItem> |
|
|
|
|
</Select> |
|
|
|
|
</FormControl> |
|
|
|
|
|
|
|
|
|
{!newStock.newAddition && <FormControl sx={{ width: "100%", marginBottom: 2 }}> |
|
|
|
|
<InputLabel id="demo-simple-select-label">材料名(選択)</InputLabel> |
|
|
|
|
<Select |
|
|
|
|
labelId="demo-simple-select-label" |
|
|
|
|
value={newStock.stuffId} |
|
|
|
|
onChange={(e) => setNewStock({ ...newStock, stuffId: Number(e.target.value) })} |
|
|
|
|
> |
|
|
|
|
{stuffs.map((stuff) => ( |
|
|
|
|
<MenuItem key={stuff.stuffId} value={stuff.stuffId}> |
|
|
|
|
{stuff.stuffName} |
|
|
|
|
</MenuItem> |
|
|
|
|
))} |
|
|
|
|
</Select> |
|
|
|
|
</FormControl>} |
|
|
|
|
|
|
|
|
|
{/* タスクタイトル入力フィールド */} |
|
|
|
|
{newStock.newAddition && <TextField |
|
|
|
|
autoFocus |
|
|
|
|
margin="dense" |
|
|
|
|
label="材料名" |
|
|
|
|
fullWidth |
|
|
|
|
value={newStock.stuffName} |
|
|
|
|
onChange={(e) => setNewStock({ ...newStock, stuffName: e.target.value })} |
|
|
|
|
sx={{ marginBottom: 2 }} |
|
|
|
|
/>} |
|
|
|
|
{/* 数量入力フィールド */} |
|
|
|
|
<TextField |
|
|
|
|
margin="dense" |
|
|
|
|
label="数量" |
|
|
|
|
fullWidth |
|
|
|
|
value={newStock.amount} |
|
|
|
|
onChange={(e) => { |
|
|
|
|
const value = e.target.value; |
|
|
|
|
const parsedValue = parseInt(value, 10); // 数値に変換
|
|
|
|
|
if (!isNaN(parsedValue)) { |
|
|
|
|
setNewStock({ ...newStock, amount: parsedValue }); // number型で保存
|
|
|
|
|
} |
|
|
|
|
}} |
|
|
|
|
// sx={{ width: "50%" }}
|
|
|
|
|
type="number" |
|
|
|
|
inputProps={{ inputMode: "numeric", pattern: "[0-9]*" }} // ここで整数のみ許可
|
|
|
|
|
/> |
|
|
|
|
{/* 購入価格入力フィールド */} |
|
|
|
|
<TextField |
|
|
|
|
margin="dense" |
|
|
|
|
label="購入価格" |
|
|
|
|
fullWidth |
|
|
|
|
value={newStock.price} |
|
|
|
|
onChange={(e) => { |
|
|
|
|
const value = e.target.value; |
|
|
|
|
const parsedValue = parseInt(value, 10); // 数値に変換
|
|
|
|
|
if (!isNaN(parsedValue)) { |
|
|
|
|
setNewStock({ ...newStock, price: parsedValue }); // number型で保存
|
|
|
|
|
} |
|
|
|
|
}} |
|
|
|
|
// sx={{ width: "50%" }}
|
|
|
|
|
type="number" |
|
|
|
|
inputProps={{ inputMode: "numeric", pattern: "[0-9]*" }} // ここで整数のみ許可
|
|
|
|
|
/> |
|
|
|
|
|
|
|
|
|
{/* 賞味・消費期限入力フィールド */} |
|
|
|
|
<TextField |
|
|
|
|
margin="dense" |
|
|
|
|
label="消費・賞味期限(yyyy/MM/dd)" |
|
|
|
|
fullWidth |
|
|
|
|
value={newStock.expDate} |
|
|
|
|
onChange={(e) => setNewStock({ ...newStock, expDate: e.target.value })} |
|
|
|
|
/> |
|
|
|
|
|
|
|
|
|
{/* 購入日入力フィールド */} |
|
|
|
|
<TextField |
|
|
|
|
margin="dense" |
|
|
|
|
label="購入日(yyyy/MM/dd)" |
|
|
|
|
fullWidth |
|
|
|
|
value={newStock.buyDate} |
|
|
|
|
onChange={(e) => setNewStock({ ...newStock, buyDate: e.target.value })} |
|
|
|
|
/> |
|
|
|
|
</Box> |
|
|
|
|
</DialogContent> |
|
|
|
|
<DialogActions> |
|
|
|
|
<Button onClick={() => setIsAddOpen(false)}>キャンセル</Button> |
|
|
|
|
<Button onClick={handleCreateStock} variant="contained"> |
|
|
|
|
追加 |
|
|
|
|
</Button> |
|
|
|
|
</DialogActions> |
|
|
|
|
</Dialog> |
|
|
|
|
|
|
|
|
|
{/* 在庫の食材編集ボタン(全テーブル共通) */} |
|
|
|
|
<Button variant="contained" color="success" onClick={handleOpenEdit} sx={{ mt: 3, mb: 2, left: '80%' }}> |
|
|
|
|
編集 |
|
|
|
|
</Button> |
|
|
|
|
|
|
|
|
|
{/* タスク削除ボタン */} |
|
|
|
|
{/* 在庫の食材削除ボタン (全テーブル共通) */} |
|
|
|
|
<Button variant="contained" color="error" onClick={handleOpenDelete} sx={{ mt: 3, mb: 2, left: '82%' }}>削除</Button> |
|
|
|
|
|
|
|
|
|
{/* 在庫一覧リスト */} |
|
|
|
|