diff --git a/src/app/editor/[projectId]/FlowchartEditor.tsx b/src/app/editor/[projectId]/FlowchartEditor.tsx index ade31fe..2ba1cab 100644 --- a/src/app/editor/[projectId]/FlowchartEditor.tsx +++ b/src/app/editor/[projectId]/FlowchartEditor.tsx @@ -1,6 +1,6 @@ 'use client' -import React, { useCallback, useMemo, useState } from 'react' +import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' import ReactFlow, { Background, BackgroundVariant, @@ -27,10 +27,12 @@ import ConditionEditor from '@/components/editor/ConditionEditor' import ExportValidationModal, { type ValidationIssue } from '@/components/editor/ExportValidationModal' import { EditorProvider } from '@/components/editor/EditorContext' import Toast from '@/components/Toast' +import { RealtimeConnection, type ConnectionState } from '@/lib/collaboration/realtime' import type { FlowchartData, FlowchartNode, FlowchartEdge, Character, Variable, Condition } from '@/types/flowchart' type FlowchartEditorProps = { projectId: string + userId: string initialData: FlowchartData needsMigration?: boolean } @@ -202,7 +204,7 @@ function computeMigration(initialData: FlowchartData, shouldMigrate: boolean) { } // Inner component that uses useReactFlow hook -function FlowchartEditorInner({ projectId, initialData, needsMigration }: FlowchartEditorProps) { +function FlowchartEditorInner({ projectId, userId, initialData, needsMigration }: FlowchartEditorProps) { // Define custom node types - memoized to prevent re-renders const nodeTypes: NodeTypes = useMemo( () => ({ @@ -232,6 +234,22 @@ function FlowchartEditorInner({ projectId, initialData, needsMigration }: Flowch const [toastMessage, setToastMessage] = useState(migratedData.toastMessage) const [validationIssues, setValidationIssues] = useState(null) const [warningNodeIds, setWarningNodeIds] = useState>(new Set()) + const [connectionState, setConnectionState] = useState('disconnected') + const realtimeRef = useRef(null) + + // Connect to Supabase Realtime channel on mount, disconnect on unmount + useEffect(() => { + const connection = new RealtimeConnection(projectId, userId, { + onConnectionStateChange: setConnectionState, + }) + realtimeRef.current = connection + connection.connect() + + return () => { + connection.disconnect() + realtimeRef.current = null + } + }, [projectId, userId]) const handleAddCharacter = useCallback( (name: string, color: string): string => { @@ -511,6 +529,7 @@ function FlowchartEditorInner({ projectId, initialData, needsMigration }: Flowch onExport={handleExport} onImport={handleImport} onProjectSettings={() => setShowSettings(true)} + connectionState={connectionState} />
diff --git a/src/components/editor/Toolbar.tsx b/src/components/editor/Toolbar.tsx index 81c2c45..3161530 100644 --- a/src/components/editor/Toolbar.tsx +++ b/src/components/editor/Toolbar.tsx @@ -1,5 +1,7 @@ 'use client' +import type { ConnectionState } from '@/lib/collaboration/realtime' + type ToolbarProps = { onAddDialogue: () => void onAddChoice: () => void @@ -8,6 +10,21 @@ type ToolbarProps = { onExport: () => void onImport: () => void onProjectSettings: () => void + connectionState?: ConnectionState +} + +const connectionLabel: Record = { + connecting: 'Connecting…', + connected: 'Connected', + disconnected: 'Disconnected', + reconnecting: 'Reconnecting…', +} + +const connectionColor: Record = { + connecting: 'bg-yellow-400', + connected: 'bg-green-400', + disconnected: 'bg-red-400', + reconnecting: 'bg-yellow-400', } export default function Toolbar({ @@ -18,6 +35,7 @@ export default function Toolbar({ onExport, onImport, onProjectSettings, + connectionState, }: ToolbarProps) { return (
@@ -46,6 +64,14 @@ export default function Toolbar({
+ {connectionState && ( +
+ + + {connectionLabel[connectionState]} + +
+ )}