From 289ade187ee0660b034b6dcbc0918d04f3cd8433 Mon Sep 17 00:00:00 2001 From: Leopoldadmin Date: Mon, 22 Jun 2026 23:13:21 +0000 Subject: [PATCH] T20: Add export/import UI to RibbonBar.tsx --- frontend/src/components/RibbonBar.tsx | 134 +++++++++++++++++++++++++- 1 file changed, 131 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/RibbonBar.tsx b/frontend/src/components/RibbonBar.tsx index d423143..41947e0 100644 --- a/frontend/src/components/RibbonBar.tsx +++ b/frontend/src/components/RibbonBar.tsx @@ -1,12 +1,21 @@ -import React, { useState } from 'react'; +import React, { useState, useRef, useCallback } from 'react'; +import type { YjsDocument } from '../crdt/YjsDocument'; +import { exportDrawing, type ExportFormat } from '../services/exportService'; +import { importDrawing, type ImportFormat, type ImportResult } from '../services/importService'; import './RibbonBar.css'; interface RibbonBarProps { onTabChange: (tab: string) => void; + yjsDoc?: React.RefObject; } -const RibbonBar: React.FC = ({ onTabChange }) => { +const RibbonBar: React.FC = ({ onTabChange, yjsDoc }) => { const [activeTab, setActiveTab] = useState('draw'); + const [showExportMenu, setShowExportMenu] = useState(false); + const [showImportMenu, setShowImportMenu] = useState(false); + const [importStatus, setImportStatus] = useState(null); + const fileInputRef = useRef(null); + const pendingImportFormat = useRef('json'); const tabs = [ { id: 'draw', label: 'Draw', icon: '✏️' }, @@ -21,6 +30,57 @@ const RibbonBar: React.FC = ({ onTabChange }) => { onTabChange(tabId); }; + const handleExport = useCallback(async (format: ExportFormat) => { + setShowExportMenu(false); + const doc = yjsDoc?.current; + if (!doc) { + setImportStatus('Error: No document available'); + setTimeout(() => setImportStatus(null), 3000); + return; + } + try { + await exportDrawing(doc, format); + } catch (e) { + setImportStatus(`Export error: ${(e as Error).message}`); + setTimeout(() => setImportStatus(null), 5000); + } + }, [yjsDoc]); + + const triggerImport = useCallback((format: ImportFormat) => { + setShowImportMenu(false); + pendingImportFormat.current = format; + if (fileInputRef.current) { + fileInputRef.current.accept = format === 'json' ? '.json,application/json' : '.dxf,application/dxf'; + fileInputRef.current.click(); + } + }, []); + + const handleFileSelected = useCallback(async (e: React.ChangeEvent) => { + const file = e.target.files?.[0]; + if (!file) return; + const doc = yjsDoc?.current; + if (!doc) { + setImportStatus('Error: No document available'); + setTimeout(() => setImportStatus(null), 3000); + return; + } + try { + const result: ImportResult = await importDrawing(file, pendingImportFormat.current, doc); + if (result.success) { + setImportStatus(`Imported: ${result.elementsImported} elements, ${result.layersImported} layers`); + } else { + setImportStatus(`Import failed: ${result.errors.join(', ')}`); + } + } catch (err) { + setImportStatus(`Import error: ${(err as Error).message}`); + } + setTimeout(() => setImportStatus(null), 5000); + // Reset input so same file can be selected again + if (fileInputRef.current) { + fileInputRef.current.value = ''; + } + }, [yjsDoc]); + return (
{tabs.map((tab) => ( @@ -35,8 +95,76 @@ const RibbonBar: React.FC = ({ onTabChange }) => { {tab.label} ))} + + {/* Export/Import section */} + ); }; -export default RibbonBar; \ No newline at end of file +export default RibbonBar;