You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
joint_exc/frontend/src/components/Layout.tsx

116 lines
3.3 KiB

/**
* アプリケーションの共通レイアウトを提供するコンポーネント
* ヘッダー(AppBar)とメインコンテンツ領域を含む基本的なページ構造を定義
*/
import React, { useState } from 'react';
import {
AppBar,
Toolbar,
Typography,
Container,
Box,
Button,
Drawer,
List,
ListItemText,
ListItemIcon,
ListItemButton,
Divider,
IconButton
} from '@mui/material';
import {
Menu as MenuIcon,
ListAlt as ListAltIcon,
} from '@mui/icons-material';
import { useNavigate, Outlet, useLocation } from 'react-router-dom';
const Layout: React.FC = () => {
const navigate = useNavigate();
const location = useLocation();
const [drawerOpen, setDrawerOpen] = useState(false);
/**
* ログアウト処理を行うハンドラー関数
* ローカルストレージからトークンを削除し、ログインページにリダイレクト
*/
const handleLogout = () => {
localStorage.removeItem('token');
navigate('/login');
};
/**
* 画面遷移処理を行うハンドラー関数
* 指定されたパスに遷移し、サイドメニューを閉じる
*/
const handleNavigate = (path: string) => {
navigate(path);
setDrawerOpen(false);
};
// 現在のパスに基づいてメニュー項目が選択状態かどうかを判定
const isSelected = (path: string): boolean => {
return location.pathname === path;
};
// メニューを開閉するハンドラー
const toggleDrawer = () => {
setDrawerOpen(!drawerOpen);
};
return (
<Box sx={{ display: 'flex', flexDirection: 'column', minHeight: '100vh' }}>
{/* ヘッダー部分 - アプリ名とログアウトボタンを表示 */}
<AppBar position="static" elevation={0}>
<Toolbar>
<IconButton
edge="start"
color="inherit"
aria-label="menu"
onClick={toggleDrawer}
sx={{ mr: 2 }}
>
<MenuIcon />
</IconButton>
<Typography variant="h6" component="div" sx={{ flexGrow: 1 }}>
ToDoアプリ
</Typography>
<Button color="inherit" onClick={handleLogout}>
</Button>
</Toolbar>
</AppBar>
{/* サイドメニュー */}
<Drawer
anchor="left"
open={drawerOpen}
onClose={() => setDrawerOpen(false)}
>
<Box
sx={{ width: 250 }}
role="presentation"
>
<List>
<ListItemButton
onClick={() => handleNavigate('/tasks')}
selected={isSelected('/tasks')}
>
<ListItemIcon><ListAltIcon /></ListItemIcon>
<ListItemText primary="タスク一覧" />
</ListItemButton>
<Divider />
</List>
</Box>
</Drawer>
{/* メインコンテンツ領域 - 子ルートのコンポーネントがここに表示される */}
<Box component="main" sx={{ flexGrow: 1, bgcolor: 'background.default', py: 3 }}>
<Container>
<Outlet /> {/* React Router の Outlet - 子ルートのコンポーネントがここにレンダリングされる */}
</Container>
</Box>
</Box>
);
};
export default Layout;