diff --git a/.gitignore b/.gitignore index be5020e..19b7d18 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,20 @@ -node_modules -.env +# Dependencies +node_modules/ package-lock.json -.cursor -*.excalidraw -public/dist/assets/ \ No newline at end of file + +# Build artifacts +dist/ +public/dist/ + +# Environment files +.env + +# Logs +*.log + +# Editor artifacts +.cursor/ +.claude/ + +# Development artifacts +*.excalidraw \ No newline at end of file diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index beb8e2d..3f1f822 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -5,24 +5,8 @@ import '@excalidraw/excalidraw/index.css' function App() { const [excalidrawAPI, setExcalidrawAPI] = useState(null) const [isConnected, setIsConnected] = useState(false) - const [elementCount, setElementCount] = useState(0) - const [apiPanelVisible, setApiPanelVisible] = useState(true) - const [notifications, setNotifications] = useState([]) const websocketRef = useRef(null) - // Form state - const [formData, setFormData] = useState({ - type: 'rectangle', - x: 100, - y: 100, - width: 100, - height: 100, - text: '', - backgroundColor: '#ffffff', - strokeColor: '#000000', - strokeWidth: 2 - }) - // WebSocket connection useEffect(() => { connectWebSocket() @@ -36,17 +20,11 @@ function App() { // Load existing elements when Excalidraw API becomes available useEffect(() => { if (excalidrawAPI) { - console.log('ExcalidrawAPI ready, setting up real-time sync') - - // Load existing elements immediately loadExistingElements() // Ensure WebSocket is connected for real-time updates if (!isConnected) { - console.log('ExcalidrawAPI ready but WebSocket not connected, connecting...') connectWebSocket() - } else { - console.log('Both ExcalidrawAPI and WebSocket are ready for real-time sync') } } }, [excalidrawAPI, isConnected]) @@ -57,9 +35,7 @@ function App() { const result = await response.json() if (result.success && result.elements && result.elements.length > 0) { - console.log('Loading existing elements from API:', result.elements.length) const convertedElements = convertToExcalidrawElements(result.elements) - console.log('Converted existing elements:', convertedElements) excalidrawAPI.updateScene({ elements: convertedElements }) } } catch (error) { @@ -69,24 +45,19 @@ function App() { const connectWebSocket = () => { if (websocketRef.current && websocketRef.current.readyState === WebSocket.OPEN) { - console.log('WebSocket already connected') return } const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:' const wsUrl = `${protocol}//${window.location.host}` - console.log('Connecting to WebSocket:', wsUrl) websocketRef.current = new WebSocket(wsUrl) websocketRef.current.onopen = () => { - console.log('WebSocket connected successfully') setIsConnected(true) - // Request existing elements when WebSocket connects and API is ready if (excalidrawAPI) { - console.log('WebSocket connected and ExcalidrawAPI ready - requesting refresh') - setTimeout(loadExistingElements, 100) // Small delay to ensure connection is stable + setTimeout(loadExistingElements, 100) } } @@ -100,12 +71,10 @@ function App() { } websocketRef.current.onclose = (event) => { - console.log('WebSocket disconnected:', event.code, event.reason) setIsConnected(false) // Reconnect after 3 seconds if not a clean close if (event.code !== 1000) { - console.log('Attempting to reconnect in 3 seconds...') setTimeout(connectWebSocket, 3000) } } @@ -117,62 +86,44 @@ function App() { } const handleWebSocketMessage = (data) => { - console.log('WebSocket message received:', data.type, data) - if (!excalidrawAPI) { - console.log('ExcalidrawAPI not ready, skipping message:', data.type) return } try { const currentElements = excalidrawAPI.getSceneElements() - console.log('Current elements count:', currentElements.length) switch (data.type) { case 'initial_elements': if (data.elements && data.elements.length > 0) { - console.log('Loading initial elements:', data.elements.length) const convertedElements = convertToExcalidrawElements(data.elements) - console.log('Converted initial elements:', convertedElements.length) excalidrawAPI.updateScene({ elements: convertedElements }) } break case 'element_created': - console.log('Processing element_created:', data.element) const newElement = convertToExcalidrawElements([data.element]) - console.log('Converted new element:', newElement) const updatedElementsAfterCreate = [...currentElements, ...newElement] - console.log('Total elements after create:', updatedElementsAfterCreate.length) excalidrawAPI.updateScene({ elements: updatedElementsAfterCreate }) - showNotification('Element created successfully!', 'success') break case 'element_updated': - console.log('Processing element_updated:', data.element.id) const convertedUpdatedElement = convertToExcalidrawElements([data.element])[0] const updatedElements = currentElements.map(el => el.id === data.element.id ? convertedUpdatedElement : el ) excalidrawAPI.updateScene({ elements: updatedElements }) - showNotification('Element updated successfully!', 'success') break case 'element_deleted': - console.log('Processing element_deleted:', data.elementId) const filteredElements = currentElements.filter(el => el.id !== data.elementId) excalidrawAPI.updateScene({ elements: filteredElements }) - showNotification('Element deleted successfully!', 'success') break case 'elements_batch_created': - console.log('Processing elements_batch_created:', data.elements.length) const batchElements = convertToExcalidrawElements(data.elements) - console.log('Converted batch elements:', batchElements.length) const updatedElementsAfterBatch = [...currentElements, ...batchElements] - console.log('Total elements after batch:', updatedElementsAfterBatch.length) excalidrawAPI.updateScene({ elements: updatedElementsAfterBatch }) - showNotification(`${data.elements.length} elements created!`, 'success') break default: @@ -180,344 +131,51 @@ function App() { } } catch (error) { console.error('Error processing WebSocket message:', error, data) - showNotification('Error processing real-time update', 'error') - } - } - - const showNotification = (message, type = 'success') => { - const id = Date.now() - const notification = { id, message, type } - setNotifications(prev => [...prev, notification]) - - setTimeout(() => { - setNotifications(prev => prev.filter(n => n.id !== id)) - }, 3000) - } - - const handleExcalidrawChange = (elements, appState, files) => { - setElementCount(elements.length) - } - - const handleFormSubmit = async (e) => { - e.preventDefault() - - const elementData = { - type: formData.type, - x: parseInt(formData.x), - y: parseInt(formData.y), - width: parseInt(formData.width) || undefined, - height: parseInt(formData.height) || undefined, - backgroundColor: formData.backgroundColor, - strokeColor: formData.strokeColor, - strokeWidth: parseInt(formData.strokeWidth) - } - - if (formData.text) { - elementData.text = formData.text - } - - // Remove undefined values - Object.keys(elementData).forEach(key => { - if (elementData[key] === undefined) { - delete elementData[key] - } - }) - - try { - const response = await fetch('/api/elements', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify(elementData) - }) - - const result = await response.json() - - if (result.success) { - showNotification('Element created via API!', 'success') - // Reset form positions - setFormData(prev => ({ - ...prev, - x: Math.floor(Math.random() * 400) + 50, - y: Math.floor(Math.random() * 300) + 50 - })) - } else { - showNotification(`Error: ${result.error}`, 'error') - } - } catch (error) { - console.error('Error creating element:', error) - showNotification('Failed to create element', 'error') - } - } - - const createSampleElements = async () => { - const sampleElements = [ - { - type: 'rectangle', - x: 50, - y: 50, - width: 150, - height: 100, - backgroundColor: '#ffeaa7', - strokeColor: '#2d3436' - }, - { - type: 'ellipse', - x: 250, - y: 50, - width: 120, - height: 120, - backgroundColor: '#74b9ff', - strokeColor: '#0984e3' - }, - { - type: 'diamond', - x: 50, - y: 200, - width: 100, - height: 100, - backgroundColor: '#fd79a8', - strokeColor: '#e84393' - }, - { - type: 'text', - x: 250, - y: 220, - text: 'Hello from API!', - fontSize: 20, - strokeColor: '#2d3436' - } - ] - - try { - const response = await fetch('/api/elements/batch', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ elements: sampleElements }) - }) - - const result = await response.json() - - if (result.success) { - showNotification(`${result.count} sample elements created!`, 'success') - } else { - showNotification(`Error: ${result.error}`, 'error') - } - } catch (error) { - console.error('Error creating sample elements:', error) - showNotification('Failed to create sample elements', 'error') } } const clearCanvas = async () => { if (excalidrawAPI) { try { - // First, get all current elements + // Get all current elements and delete them from backend const response = await fetch('/api/elements') const result = await response.json() if (result.success && result.elements) { - // Delete all elements from backend const deletePromises = result.elements.map(element => fetch(`/api/elements/${element.id}`, { method: 'DELETE' }) ) - await Promise.all(deletePromises) - console.log('All elements deleted from backend') } // Clear the frontend canvas excalidrawAPI.updateScene({ elements: [] }) - showNotification('Canvas cleared completely!', 'success') } catch (error) { console.error('Error clearing canvas:', error) // Still clear frontend even if backend fails excalidrawAPI.updateScene({ elements: [] }) - showNotification('Canvas cleared (frontend only)', 'warning') } } } - const refreshElements = async () => { - console.log('Manual refresh requested') - if (excalidrawAPI) { - await loadExistingElements() - showNotification('Elements refreshed!', 'success') - } else { - showNotification('Canvas not ready yet', 'error') - } - } - - const forceReconnectWebSocket = () => { - console.log('Force reconnecting WebSocket') - if (websocketRef.current) { - websocketRef.current.close() - } - setTimeout(connectWebSocket, 100) - } - - const toggleApiPanel = () => { - setApiPanelVisible(!apiPanelVisible) - } - - const handleInputChange = (e) => { - const { name, value } = e.target - setFormData(prev => ({ - ...prev, - [name]: value - })) - } - return (