|
|
|
@ -31,16 +31,19 @@ import { GENERAL_ERRORS, STOCK_ERRORS } from '../constants/errorMessages'; |
|
|
|
|
import { Add as AddIcon, KeyboardArrowDown as ArrowDownIcon, KeyboardArrowUp as ArrowUpIcon, Inventory as InventoryIcon } from '@mui/icons-material'; |
|
|
|
|
import DatePicker, { registerLocale } from 'react-datepicker'; |
|
|
|
|
import { ja } from 'date-fns/locale/ja'; // date-fnsの日本語ロケールをインポート
|
|
|
|
|
/*import DatePicker, { registerLocale } from 'react-datepicker'; |
|
|
|
|
import { ja } from 'date-fns/locale/ja'; // date-fnsの日本語ロケールをインポート*/
|
|
|
|
|
import { useMessage } from '../components/MessageContext'; |
|
|
|
|
import BuyExpDateSelect from '../components/BuyExpDateSelect'; |
|
|
|
|
import { STOCK_MESSAGES } from '../constants/normalMessages'; |
|
|
|
|
|
|
|
|
|
// 日付をyyyy-MM-dd形式で返す関数
|
|
|
|
|
/*// 日付をyyyy-MM-dd形式で返す関数 |
|
|
|
|
const formatDateLocal = (date: Date) => { |
|
|
|
|
const year = date.getFullYear(); |
|
|
|
|
const month = (date.getMonth() + 1).toString().padStart(2, '0'); |
|
|
|
|
const day = date.getDate().toString().padStart(2, '0'); |
|
|
|
|
return `${year}-${month}-${day}`; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
};*/ |
|
|
|
|
|
|
|
|
|
// 新規在庫の初期状態
|
|
|
|
|
const EMPTY_STOCK: Omit<Stock, 'stockId' | 'stuffId'> & { stuffId: number | null } & { newAddition: boolean } = { |
|
|
|
@ -59,7 +62,7 @@ const EMPTY_STOCK: Omit<Stock, 'stockId' | 'stuffId'> & { stuffId: number | null |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 日本語ロケールを登録
|
|
|
|
|
registerLocale('ja', ja); |
|
|
|
|
//registerLocale('ja', ja);
|
|
|
|
|
|
|
|
|
|
const StockPage: React.FC = () => { |
|
|
|
|
|
|
|
|
@ -78,7 +81,7 @@ const StockPage: React.FC = () => { |
|
|
|
|
// 在庫の編集状態
|
|
|
|
|
const [editStock, setEditStock] = useState<Stock | null>(null); |
|
|
|
|
|
|
|
|
|
const { showErrorMessage, showWarningMessage } = useMessage(); |
|
|
|
|
const { showErrorMessage, showWarningMessage, showSuccessMessage } = useMessage(); |
|
|
|
|
|
|
|
|
|
// カテゴリ名一覧
|
|
|
|
|
const CATEGORY_NAMES = [ |
|
|
|
@ -121,8 +124,21 @@ const StockPage: React.FC = () => { |
|
|
|
|
if (newStock.newAddition) { |
|
|
|
|
newStock.stuffId = null; |
|
|
|
|
} |
|
|
|
|
if (isNaN(newStock.amount)) return; |
|
|
|
|
if (isNaN(newStock.price)) return; |
|
|
|
|
|
|
|
|
|
if (!newStock.stuffId && !newStock.stuffName) { |
|
|
|
|
showErrorMessage(GENERAL_ERRORS.INVALID_STUFF_NAME); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (isNaN(newStock.amount)) { |
|
|
|
|
showErrorMessage(GENERAL_ERRORS.INVALID_AMOUNT); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (newStock.price === null || isNaN(newStock.price)) { |
|
|
|
|
showErrorMessage(GENERAL_ERRORS.INVALID_PRICE); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (newStock.buyAmount !== null && isNaN(newStock.buyAmount)) { |
|
|
|
|
newStock.buyAmount = null; |
|
|
|
@ -132,23 +148,25 @@ const StockPage: React.FC = () => { |
|
|
|
|
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; |
|
|
|
|
if (newStock.expDate !== null) { |
|
|
|
|
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); |
|
|
|
@ -157,6 +175,7 @@ const StockPage: React.FC = () => { |
|
|
|
|
console.log("送信するデータ:", updatedStock); // 送信前のデータを確認
|
|
|
|
|
await stockApi.addStock(updatedStock); // 修正したオブジェクトを API に送信
|
|
|
|
|
|
|
|
|
|
showSuccessMessage(STOCK_MESSAGES.CREATE_OK); |
|
|
|
|
|
|
|
|
|
// await stockApi.addStock(newStock);
|
|
|
|
|
setIsAddOpen(false); // ダイアログを閉じる
|
|
|
|
@ -175,10 +194,12 @@ const StockPage: React.FC = () => { |
|
|
|
|
try { |
|
|
|
|
await stockApi.updateStock(request); |
|
|
|
|
fetchStocks(); // 削除後の買うもの一覧を再取得
|
|
|
|
|
// showSuccessMessage(STOCK_MESSAGES.UPDATE_OK);
|
|
|
|
|
} catch (error) { |
|
|
|
|
console.error(`${STOCK_ERRORS.UPDATE_FAILED}:`, error); |
|
|
|
|
showErrorMessage(STOCK_ERRORS.UPDATE_FAILED); |
|
|
|
|
// showErrorMessage(STOCK_ERRORS.UPDATE_FAILED);
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
@ -188,6 +209,9 @@ const StockPage: React.FC = () => { |
|
|
|
|
const handleDeleteStock = async (stockId: number) => { |
|
|
|
|
try { |
|
|
|
|
await stockApi.deleteStock(stockId); |
|
|
|
|
|
|
|
|
|
showSuccessMessage(STOCK_MESSAGES.DELETE_OK); |
|
|
|
|
|
|
|
|
|
fetchStocks(); // 削除後の買うもの一覧を再取得
|
|
|
|
|
} catch (error) { |
|
|
|
|
console.error(`${STOCK_ERRORS.DELETE_FAILED}:`, error); |
|
|
|
@ -237,23 +261,25 @@ const StockPage: React.FC = () => { |
|
|
|
|
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; |
|
|
|
|
if (expDate !== null) { |
|
|
|
|
// 購入日が消費・賞味期限より未来の場合はエラー表示
|
|
|
|
|
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 { |
|
|
|
@ -269,14 +295,14 @@ const StockPage: React.FC = () => { |
|
|
|
|
setIsDeleteOpen(true); // 削除ダイアログを開く
|
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
if (!numericAmount || !numericBuyAmount) { |
|
|
|
|
if (!numericAmount /* || !numericBuyAmount */) { |
|
|
|
|
showErrorMessage(GENERAL_ERRORS.INVALID_AMOUNT); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
if (!numericPrice) { |
|
|
|
|
showErrorMessage(GENERAL_ERRORS.INVALID_PRICE); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
// if (!numericPrice) {
|
|
|
|
|
// showErrorMessage(GENERAL_ERRORS.INVALID_PRICE);
|
|
|
|
|
// return;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
const lastUpdate = new Date().toISOString().substring(0, 10); |
|
|
|
|
|
|
|
|
@ -295,6 +321,9 @@ const StockPage: React.FC = () => { |
|
|
|
|
|
|
|
|
|
await handleUpdateStock(updateRequest); |
|
|
|
|
|
|
|
|
|
console.log(STOCK_MESSAGES.UPDATE_OK) |
|
|
|
|
showSuccessMessage(STOCK_MESSAGES.UPDATE_OK); |
|
|
|
|
|
|
|
|
|
setSelectedRow(editStock); // 更新後に選択行を反映
|
|
|
|
|
fetchStocks(); // 最新データを取得
|
|
|
|
|
setSelectedRow(null); // 選択解除
|
|
|
|
@ -373,21 +402,25 @@ const StockPage: React.FC = () => { |
|
|
|
|
</TableHead> |
|
|
|
|
<TableBody> |
|
|
|
|
{filteredStocks.map(stock => { |
|
|
|
|
const today = new Date(); |
|
|
|
|
const expDate = new Date(stock.expDate); |
|
|
|
|
// 時間をリセットして純粋な“日付のみ”のタイムスタンプを取得
|
|
|
|
|
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);
|
|
|
|
|
let daysLeft = null; |
|
|
|
|
|
|
|
|
|
if (stock.expDate !== null) { |
|
|
|
|
const today = new Date(); |
|
|
|
|
const expDate = new Date(stock.expDate); |
|
|
|
|
// 時間をリセットして純粋な“日付のみ”のタイムスタンプを取得
|
|
|
|
|
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(); |
|
|
|
|
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 |
|
|
|
@ -398,9 +431,9 @@ const StockPage: React.FC = () => { |
|
|
|
|
<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" } : {}} |
|
|
|
|
style={daysLeft !== null && daysLeft <= 3 ? { color: "red", fontWeight: "bold" } : {}} |
|
|
|
|
> |
|
|
|
|
{formatDate(stock.expDate)} |
|
|
|
|
{stock.expDate && formatDate(stock.expDate)} |
|
|
|
|
</TableCell> |
|
|
|
|
</TableRow> |
|
|
|
|
); |
|
|
|
@ -485,53 +518,9 @@ const StockPage: React.FC = () => { |
|
|
|
|
onChange={handleChange} |
|
|
|
|
/> |
|
|
|
|
|
|
|
|
|
{/* 購入日・消費期限を横並びに */} |
|
|
|
|
<Box sx={{ display: 'flex', gap: 2, mb: 2 }}> |
|
|
|
|
{/* 購入日フィールド */} |
|
|
|
|
<DatePicker |
|
|
|
|
selected={editStock.buyDate ? new Date(editStock.buyDate) : null} |
|
|
|
|
onChange={(date) => { |
|
|
|
|
if (editStock) { |
|
|
|
|
setEditStock({ |
|
|
|
|
...editStock, |
|
|
|
|
buyDate: date ? formatDateLocal(date) : '', |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
}} |
|
|
|
|
dateFormat="yyyy/MM/dd" |
|
|
|
|
customInput={ |
|
|
|
|
<TextField |
|
|
|
|
margin="normal" |
|
|
|
|
label="購入日 (yyyy/MM/dd)" |
|
|
|
|
fullWidth |
|
|
|
|
name="buyDate" |
|
|
|
|
/> |
|
|
|
|
} |
|
|
|
|
isClearable |
|
|
|
|
/> |
|
|
|
|
{/* 消費・賞味期限フィールド */} |
|
|
|
|
<DatePicker |
|
|
|
|
selected={editStock.expDate ? new Date(editStock.expDate) : null} |
|
|
|
|
onChange={(date) => { |
|
|
|
|
if (editStock) { |
|
|
|
|
setEditStock({ |
|
|
|
|
...editStock, |
|
|
|
|
expDate: date ? formatDateLocal(date) : '', |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
}} |
|
|
|
|
dateFormat="yyyy/MM/dd" |
|
|
|
|
customInput={ |
|
|
|
|
<TextField |
|
|
|
|
margin="normal" |
|
|
|
|
label="消費・賞味期限 (yyyy/MM/dd)" |
|
|
|
|
fullWidth |
|
|
|
|
name="expDate" |
|
|
|
|
/> |
|
|
|
|
} |
|
|
|
|
isClearable |
|
|
|
|
/> |
|
|
|
|
</Box> |
|
|
|
|
{/* 購入日・賞味期限入力 */} |
|
|
|
|
<BuyExpDateSelect newStock={editStock} setNewStock={({ buyDate, expDate }) => setEditStock({ ...editStock, buyDate, expDate })} /> |
|
|
|
|
|
|
|
|
|
<Box sx={{ display: 'flex', justifyContent: 'flex-end', gap: 2, mt: 3, mb: 2 }}> |
|
|
|
|
<Button onClick={() => { setIsEditOpen(false); setSelectedRow(null); }}> |
|
|
|
|
キャンセル |
|
|
|
@ -718,46 +707,14 @@ const StockPage: React.FC = () => { |
|
|
|
|
label="購入店舗" |
|
|
|
|
fullWidth |
|
|
|
|
value={newStock.shop} |
|
|
|
|
onChange={(e) => setNewStock({...newStock, shop: e.target.value})} |
|
|
|
|
onChange={(e) => setNewStock({ ...newStock, shop: e.target.value })} |
|
|
|
|
/> |
|
|
|
|
{/* 購入日・消費期限を横並びに */} |
|
|
|
|
<Box sx={{ display: 'flex', gap: 2, mb: 2 }}> |
|
|
|
|
{/* 購入日入力フィールド */} |
|
|
|
|
<DatePicker |
|
|
|
|
popperClassName="custom-datepicker-popper" |
|
|
|
|
selected={newStock.buyDate ? new Date(newStock.buyDate) : null} |
|
|
|
|
onChange={(date) => |
|
|
|
|
setNewStock({ ...newStock, buyDate: date ? formatDateLocal(date) : '' }) |
|
|
|
|
} |
|
|
|
|
dateFormat="yyyy/MM/dd" |
|
|
|
|
customInput={ |
|
|
|
|
<TextField |
|
|
|
|
margin="dense" |
|
|
|
|
label="購入日(yyyy/MM/dd)" |
|
|
|
|
fullWidth |
|
|
|
|
/> |
|
|
|
|
} |
|
|
|
|
isClearable |
|
|
|
|
//withPortal // ← 他の文字との重なり対策
|
|
|
|
|
/> |
|
|
|
|
{/* 消費・賞味期限入力フィールド */} |
|
|
|
|
<DatePicker |
|
|
|
|
popperClassName="custom-datepicker-popper" |
|
|
|
|
selected={newStock.expDate ? new Date(newStock.expDate) : null} |
|
|
|
|
onChange={(date) => |
|
|
|
|
setNewStock({ ...newStock, expDate: date ? formatDateLocal(date) : '' }) |
|
|
|
|
} |
|
|
|
|
dateFormat="yyyy/MM/dd" |
|
|
|
|
customInput={ |
|
|
|
|
<TextField |
|
|
|
|
margin="dense" |
|
|
|
|
label="消費・賞味期限(yyyy/MM/dd)" |
|
|
|
|
fullWidth |
|
|
|
|
/> |
|
|
|
|
} |
|
|
|
|
isClearable |
|
|
|
|
//withPortal
|
|
|
|
|
/> |
|
|
|
|
|
|
|
|
|
{/* 購入日・賞味期限入力 */} |
|
|
|
|
<BuyExpDateSelect newStock={newStock} setNewStock={({ buyDate, expDate }) => setNewStock({ ...newStock, buyDate, expDate })} /> |
|
|
|
|
|
|
|
|
|
</Box> |
|
|
|
|
</Box> |
|
|
|
|
</DialogContent> |
|
|
|
@ -772,15 +729,15 @@ const StockPage: React.FC = () => { |
|
|
|
|
{/* 各カテゴリを表示 */} |
|
|
|
|
{CATEGORY_NAMES.map(category => { |
|
|
|
|
return ( |
|
|
|
|
<Box sx={{ padding: "1rem" }}> |
|
|
|
|
<Typography variant="h5" component="h1" gutterBottom |
|
|
|
|
onClick={() => setOpenCategory({...openCategory, [category]: !openCategory[category]})} |
|
|
|
|
> |
|
|
|
|
{!openCategory[category] ? <ArrowDownIcon color="primary" /> : <ArrowUpIcon color="primary" />} |
|
|
|
|
{category} |
|
|
|
|
</Typography> |
|
|
|
|
{openCategory[category] && StockTable(stocks, [category])} |
|
|
|
|
</Box> |
|
|
|
|
<Box sx={{ padding: "1rem" }}> |
|
|
|
|
<Typography variant="h5" component="h1" gutterBottom |
|
|
|
|
onClick={() => setOpenCategory({ ...openCategory, [category]: !openCategory[category] })} |
|
|
|
|
> |
|
|
|
|
{!openCategory[category] ? <ArrowDownIcon color="primary" /> : <ArrowUpIcon color="primary" />} |
|
|
|
|
{category} |
|
|
|
|
</Typography> |
|
|
|
|
{openCategory[category] && StockTable(stocks, [category])} |
|
|
|
|
</Box> |
|
|
|
|
) |
|
|
|
|
})} |
|
|
|
|
|
|
|
|
@ -793,7 +750,7 @@ const StockPage: React.FC = () => { |
|
|
|
|
材料の追加 |
|
|
|
|
</Typography> */} |
|
|
|
|
</Box> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</div> |
|
|
|
|
); |
|
|
|
|
}; |
|
|
|
|