メッセージコンテキストとして実装

feature-frontend-alert
Masaharu.Kato 4 months ago
parent 00b6f7f1c7
commit 3867bfb306
  1. 63
      frontend/src/components/Layout.tsx
  2. 17
      frontend/src/components/MessageContext.tsx
  3. 20
      frontend/src/pages/AddRecipe.tsx

@ -2,7 +2,7 @@
*
* AppBar
*/
import React, { useState } from 'react';
import React, { useEffect, useState } from 'react';
import {
AppBar,
Toolbar,
@ -16,7 +16,8 @@ import {
ListItemIcon,
ListItemButton,
Divider,
IconButton
IconButton,
AlertColor
} from '@mui/material';
import {
Menu as MenuIcon,
@ -26,6 +27,8 @@ import {
SoupKitchen as SoupKitchenIcon,
} from '@mui/icons-material';
import { useNavigate, Outlet, useLocation } from 'react-router-dom';
import { MessageContext } from './MessageContext';
import MessageAlert from './MessageAlert';
const Layout: React.FC = () => {
const navigate = useNavigate();
@ -60,6 +63,40 @@ const Layout: React.FC = () => {
setDrawerOpen(!drawerOpen);
};
// メッセージ表示
// ページ遷移後もメッセージを維持
useEffect(() => {
const saved = sessionStorage.getItem('globalMessage');
if (saved) {
const { message, severity } = JSON.parse(saved);
showMessage(message, severity);
}
}, []);
const [msgOpen, setMsgOpen] = useState(false);
const [msgText, setMsgText] = useState('');
const [msgType, setMsgType] = useState<AlertColor>('info');
const showMessage = (msg: string, sev: AlertColor) => {
setMsgText(msg);
setMsgType(sev);
setMsgOpen(true);
sessionStorage.setItem('globalMessage', JSON.stringify({ message: msg, severity: sev }));
};
const showErrorMessage = (message: string) => showMessage(message, 'error');
const showWarningMessage = (message: string) => showMessage(message, 'warning');
const showInfoMessage = (message: string) => showMessage(message, 'info');
const showSuccessMessage = (message: string) => showMessage(message, 'success');
const handleMsgClose = () => {
setMsgOpen(false);
setMsgText('');
sessionStorage.removeItem('globalMessage');
};
return (
<Box sx={{ display: 'flex', flexDirection: 'column', minHeight: '100vh' }}>
{/* ヘッダー部分 - アプリ名とログアウトボタンを表示 */}
@ -103,16 +140,16 @@ const Layout: React.FC = () => {
</ListItemButton>
{/* テストページへのリンクを追加 */}
{/* 在庫リストへのリンクを追加 */}
<ListItemButton
onClick={() => handleNavigate('/addRecipe')}
{/* 在庫リストへのリンクを追加 */}
<ListItemButton
onClick={() => handleNavigate('/addRecipe')}
selected={isSelected('/addRecipe')}
>
<ListItemIcon><SoupKitchenIcon /></ListItemIcon>
<ListItemText primary="料理の追加" />
</ListItemButton>
<ListItemButton
onClick={() => handleNavigate('/recipeList')}
<ListItemButton
onClick={() => handleNavigate('/recipeList')}
selected={isSelected('/recipeList')}
>
<ListItemIcon><ScienceIcon /></ListItemIcon>
@ -133,7 +170,17 @@ const Layout: React.FC = () => {
{/* メインコンテンツ領域 - 子ルートのコンポーネントがここに表示される */}
<Box component="main" sx={{ flexGrow: 1, bgcolor: 'background.default', py: 3 }}>
<Container>
<Outlet /> {/* React Router の Outlet - 子ルートのコンポーネントがここにレンダリングされる */}
<MessageContext.Provider value={{ showErrorMessage, showWarningMessage, showSuccessMessage, showInfoMessage }}>
<MessageAlert
open={msgOpen}
message={msgText}
severity={msgType}
onClose={handleMsgClose}
/>
<Outlet /> {/* React Router の Outlet - 子ルートのコンポーネントがここにレンダリングされる */}
</MessageContext.Provider>
</Container>
</Box>
</Box>

@ -0,0 +1,17 @@
import React, { createContext, useContext } from 'react';
export interface MessageContextType {
showErrorMessage: (message: string) => void;
showWarningMessage: (message: string) => void;
showSuccessMessage: (message: string) => void;
showInfoMessage: (message: string) => void;
}
export const MessageContext = createContext<MessageContextType | undefined>(undefined);
export const useMessage = () => {
const context = useContext(MessageContext);
if (!context) throw new Error('useMessage must be used within MessageContext.Provider');
return context;
};

@ -38,6 +38,7 @@ 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();
@ -45,20 +46,6 @@ const AddRecipe: React.FC = () => {
const navigate = useNavigate();
// メッセージ
const [_openMessage, _setOpenMessage] = useState(false);
const [_messageText, _setMessageText] = useState('');
const [_messageType, _setMessageType] = useState<AlertColor>('info');
const _showMessage = (message: string, severity: AlertColor) => {
_setOpenMessage(true);
_setMessageText(message);
_setMessageType(severity);
}
const showErrorMessage = (message: string) => _showMessage(message, 'error');
const showWarningMessage = (message: string) => _showMessage(message, 'warning');
const showInfoMessage = (message: string) => _showMessage(message, 'info');
const showSuccessMessage = (message: string) => _showMessage(message, 'success');
// 編集時,既存情報を読み込んだかどうか
const [recipeLoaded, setRecipeLoaded] = useState(false);
// 料理名,説明
@ -77,6 +64,9 @@ const AddRecipe: React.FC = () => {
const [editingItem, setEditingItem] = useState<StuffAndCategoryAndAmount>(emptyItem);
const [editingItemIdx, setEditingItemIdx] = useState(0);
// エラーメッセージ表示
const { showErrorMessage } = useMessage();
const loadRecipe = async () => {
if (recipeId && !recipeLoaded) {
const recipe = await recipeApi.getById(recipeId);
@ -147,8 +137,6 @@ const AddRecipe: React.FC = () => {
return (
<>
<MessageAlert open={_openMessage} message={_messageText} severity={_messageType} onClose={() => _setOpenMessage(false)}></MessageAlert>
{(recipeId && !recipeLoaded)
? <p>...</p>
:

Loading…
Cancel
Save