Rsnarsna's picture
Upload 44 files
b0c3c39 verified
import React from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import { Node, Edge } from 'reactflow';
import styles from './SidePane.module.css';
import MindMapList from './MindMapList';
import axios from '../utils/axios';
import { MindMapData } from '../utils/jsonUtils';
// Icons with improved styling
const HomeIcon = () => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
<polyline points="9 22 9 12 15 12 15 22" />
</svg>
);
const MindMapIcon = () => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<circle cx="12" cy="12" r="10" />
<path d="M12 2v20M2 12h20" />
<path d="M12 2a10 10 0 0 1 10 10M12 22a10 10 0 0 1-10-10" />
</svg>
);
const LogoutIcon = () => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" />
<polyline points="16 17 21 12 16 7" />
<line x1="21" y1="12" x2="9" y2="12" />
</svg>
);
const ChevronIcon = ({ isCollapsed }: { isCollapsed: boolean }) => (
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
style={{
transform: isCollapsed ? 'rotate(180deg)' : 'rotate(0deg)',
transition: 'transform 0.3s ease',
}}
>
<polyline points="15 18 9 12 15 6" />
</svg>
);
interface SidePaneProps {
onSelectMindMap: (mindMap: MindMapData) => void;
onNewMindMap: () => void;
isCollapsed: boolean;
setIsCollapsed: (collapsed: boolean) => void;
onDeleteMindMap: (id: string) => void;
}
const SidePane: React.FC<SidePaneProps> = ({ onSelectMindMap, onNewMindMap, isCollapsed, setIsCollapsed, onDeleteMindMap }) => {
const navigate = useNavigate();
const location = useLocation();
const isEditor = location.pathname === '/editor';
const handleLogout = async () => {
try {
await axios.post('/logout');
} catch (error) {
// Ignore error, proceed to clear token and redirect
}
localStorage.removeItem('token');
navigate('/');
};
const handleNavigation = (path: string) => (e: React.MouseEvent) => {
e.preventDefault();
try {
navigate(path);
} catch (error) {
console.error('Navigation error:', error);
// Fallback to window.location if navigation fails
window.location.href = path;
}
};
return (
<div className={`${styles.sidePane} ${isCollapsed ? styles.collapsed : styles.expanded}`}>
<button
className={styles.toggleButton}
onClick={() => setIsCollapsed(!isCollapsed)}
aria-label={isCollapsed ? 'Expand sidebar' : 'Collapse sidebar'}
>
<ChevronIcon isCollapsed={isCollapsed} />
</button>
<div className={styles.menuItems}>
<a
href="/"
className={`${styles.menuItem} ${location.pathname === '/' ? styles.active : ''}`}
onClick={handleNavigation('/')}
>
<span className={styles.icon}>
<HomeIcon />
</span>
<span className={styles.label}>Home</span>
</a>
<a
href="/editor"
className={`${styles.menuItem} ${location.pathname === '/editor' ? styles.active : ''}`}
onClick={handleNavigation('/editor')}
>
<span className={styles.icon}>
<MindMapIcon />
</span>
<span className={styles.label}>Mind Map</span>
</a>
{isEditor && (
<MindMapList
isCollapsed={isCollapsed}
onSelectMindMap={onSelectMindMap}
onNewMindMap={onNewMindMap}
onDeleteMindMap={onDeleteMindMap}
/>
)}
</div>
<div className={`${styles.logoutButton} ${isCollapsed ? styles.collapsed : ''}`}>
<button onClick={handleLogout} aria-label="Logout">
<span className={styles.icon}>
<LogoutIcon />
</span>
<span className={styles.label}>Logout</span>
</button>
</div>
</div>
);
};
export default SidePane;