| import React, { useState, useEffect } from 'react'; | |
| import axios from '../utils/axios'; | |
| import { MindMapData } from '../utils/jsonUtils'; | |
| import styles from './MindMapList.module.css'; | |
| import MindMapItem from './MindMapItem'; | |
| interface MindMap { | |
| id: string; | |
| name: string; | |
| updatedAt: string; | |
| nodes: any[]; | |
| edges: any[]; | |
| } | |
| interface MindMapListProps { | |
| isCollapsed: boolean; | |
| onSelectMindMap: (mindMap: MindMapData) => void; | |
| onNewMindMap: () => void; | |
| onDeleteMindMap: (id: string) => void; | |
| } | |
| const MindMapList: React.FC<MindMapListProps> = ({ | |
| isCollapsed, | |
| onSelectMindMap, | |
| onNewMindMap, | |
| onDeleteMindMap, | |
| }) => { | |
| const [mindMaps, setMindMaps] = useState<MindMapData[]>([]); | |
| const [selectedId, setSelectedId] = useState<string | null>(null); | |
| const [loading, setLoading] = useState(true); | |
| const [error, setError] = useState<string | null>(null); | |
| const fetchMindMaps = async () => { | |
| setLoading(true); | |
| setError(null); | |
| try { | |
| const res = await axios.get('/api/workflows'); | |
| setMindMaps(res.data); | |
| } catch (err: any) { | |
| setError('Failed to load mind maps'); | |
| } finally { | |
| setLoading(false); | |
| } | |
| }; | |
| useEffect(() => { | |
| fetchMindMaps(); | |
| }, []); | |
| const handleDelete = async (id: string) => { | |
| try { | |
| await axios.delete(`/api/workflows/${id}`); | |
| await fetchMindMaps(); | |
| if (selectedId === id) setSelectedId(null); | |
| onDeleteMindMap(id); | |
| } catch { | |
| setError('Failed to delete mind map'); | |
| } | |
| }; | |
| const handleRename = async (id: string, newName: string) => { | |
| try { | |
| await axios.put(`/api/workflows/${id}`, { name: newName }); | |
| await fetchMindMaps(); | |
| } catch { | |
| setError('Failed to rename mind map'); | |
| } | |
| }; | |
| return ( | |
| <div className={styles.mindMapList}> | |
| <div className={styles.header}> | |
| <h3 className={styles.title}>Your Mind Maps</h3> | |
| <button | |
| onClick={onNewMindMap} | |
| className={styles.newButton} | |
| title="Create new mind map" | |
| > | |
| <svg | |
| width="18" | |
| height="18" | |
| viewBox="0 0 24 24" | |
| fill="none" | |
| stroke="currentColor" | |
| strokeWidth="2" | |
| strokeLinecap="round" | |
| strokeLinejoin="round" | |
| style={{ marginRight: isCollapsed ? 0 : 4 }} | |
| > | |
| <circle cx="12" cy="12" r="10" /> | |
| <line x1="12" y1="8" x2="12" y2="16" /> | |
| <line x1="8" y1="12" x2="16" y2="12" /> | |
| </svg> | |
| {!isCollapsed && <span>New</span>} | |
| </button> | |
| </div> | |
| <div className={styles.list}> | |
| {loading && <div className={styles.loading}>Loading...</div>} | |
| {error && <div className={styles.error}>{error}</div>} | |
| {!loading && !error && mindMaps.length === 0 && ( | |
| <div className={styles.empty}>No mind maps found.</div> | |
| )} | |
| {!loading && !error && mindMaps.map((mindMap) => ( | |
| <MindMapItem | |
| key={mindMap.id} | |
| id={mindMap.id} | |
| name={mindMap.name} | |
| updatedAt={mindMap.updatedAt} | |
| isActive={selectedId === mindMap.id} | |
| onSelect={() => { | |
| setSelectedId(mindMap.id); | |
| onSelectMindMap(mindMap); | |
| }} | |
| onDelete={() => handleDelete(mindMap.id)} | |
| onRename={(newName) => handleRename(mindMap.id, newName)} | |
| onShare={() => {}} | |
| /> | |
| ))} | |
| </div> | |
| </div> | |
| ); | |
| }; | |
| export default MindMapList; |