@@ -4,6 +4,7 @@ import { useState, useEffect, useRef, useCallback } from 'react';
44import { useSearchParams } from 'next/navigation' ;
55import VoiceTranscription from '../../components/VoiceTranscription' ;
66import LiveCaptions from '../../components/LiveCaptions' ;
7+ import Whiteboard from '../../components/Whiteboard' ;
78
89interface Message {
910 id : string ;
@@ -64,6 +65,52 @@ export default function ClassroomContent({ classId }: { classId: string }) {
6465 finalText : '' ,
6566 isActive : false
6667 } ) ;
68+
69+ // Whiteboard state
70+ const [ whiteboardVisible , setWhiteboardVisible ] = useState ( false ) ;
71+
72+ // Whiteboard drawing function - always available
73+ const applyWhiteboardUpdate = useCallback ( ( data : any ) => {
74+ const canvas = document . querySelector ( 'canvas' ) ;
75+ if ( ! canvas ) {
76+ console . log ( '❌ No canvas found for whiteboard update' ) ;
77+ return ;
78+ }
79+
80+ const ctx = canvas . getContext ( '2d' ) ;
81+ if ( ! ctx ) return ;
82+
83+ if ( data . action === 'clear' ) {
84+ ctx . clearRect ( 0 , 0 , canvas . width , canvas . height ) ;
85+ console . log ( '✅ Cleared whiteboard canvas' ) ;
86+ return ;
87+ }
88+
89+ if ( data . tool === 'eraser' ) {
90+ ctx . globalCompositeOperation = 'destination-out' ;
91+ } else {
92+ ctx . globalCompositeOperation = 'source-over' ;
93+ ctx . strokeStyle = data . color || '#ffffff' ;
94+ }
95+
96+ ctx . lineWidth = data . size ;
97+ ctx . lineTo ( data . x , data . y ) ;
98+ ctx . stroke ( ) ;
99+ ctx . beginPath ( ) ;
100+ ctx . moveTo ( data . x , data . y ) ;
101+
102+ console . log ( '✅ Applied whiteboard drawing:' , data ) ;
103+ } , [ ] ) ;
104+
105+ // Register whiteboard function globally
106+ useEffect ( ( ) => {
107+ ( window as any ) . applyWhiteboardUpdate = applyWhiteboardUpdate ;
108+ console . log ( '✅ Whiteboard function registered at parent level' ) ;
109+
110+ return ( ) => {
111+ ( window as any ) . applyWhiteboardUpdate = null ;
112+ } ;
113+ } , [ applyWhiteboardUpdate ] ) ;
67114
68115 const wsRef = useRef < WebSocket | null > ( null ) ;
69116 const videoRef = useRef < HTMLVideoElement > ( null ) ;
@@ -164,6 +211,16 @@ export default function ClassroomContent({ classId }: { classId: string }) {
164211 // Show warning to user that their message was blocked
165212 alert ( `⚠️ Message Blocked: ${ data . reason } ` ) ;
166213 break ;
214+ case 'whiteboard_update' :
215+ // Apply whiteboard drawing update
216+ console . log ( '📝 Student received whiteboard update:' , data . drawing_data ) ;
217+ if ( ( window as any ) . applyWhiteboardUpdate ) {
218+ ( window as any ) . applyWhiteboardUpdate ( data . drawing_data ) ;
219+ console . log ( '✅ Applied whiteboard update to canvas' ) ;
220+ } else {
221+ console . log ( '❌ applyWhiteboardUpdate function not available' ) ;
222+ }
223+ break ;
167224 }
168225 } ;
169226
@@ -481,10 +538,15 @@ export default function ClassroomContent({ classId }: { classId: string }) {
481538
482539 if ( useScreen && mediaState . canShareScreen ) {
483540 console . log ( '📺 Starting screen share...' ) ;
484- // Screen sharing
541+ // Screen sharing with Chrome compatibility
485542 stream = await navigator . mediaDevices . getDisplayMedia ( {
486- video : true ,
487- audio : mediaState . hasAudio
543+ video : {
544+ mediaSource : 'screen' ,
545+ width : { max : 1920 } ,
546+ height : { max : 1080 } ,
547+ frameRate : { max : 30 }
548+ } ,
549+ audio : false
488550 } ) ;
489551 setMediaState ( prev => ( { ...prev , isScreenSharing : true } ) ) ;
490552 } else {
@@ -656,6 +718,24 @@ export default function ClassroomContent({ classId }: { classId: string }) {
656718 setCaptionState ( { currentText, finalText, isActive } ) ;
657719 } , [ ] ) ;
658720
721+ // Handle whiteboard drawing updates
722+ const handleWhiteboardUpdate = useCallback ( ( drawingData : any ) => {
723+ console . log ( '📝 Sending whiteboard update:' , drawingData ) ;
724+ if ( wsRef . current && role === 'teacher' ) {
725+ // Send test message first
726+ wsRef . current . send ( JSON . stringify ( {
727+ type : 'test_message' ,
728+ data : 'Testing WebSocket connection'
729+ } ) ) ;
730+
731+ // Then send whiteboard data
732+ wsRef . current . send ( JSON . stringify ( {
733+ type : 'whiteboard_draw' ,
734+ drawing_data : drawingData
735+ } ) ) ;
736+ }
737+ } , [ role ] ) ;
738+
659739 if ( ! isConnected ) {
660740 return (
661741 < div className = "min-h-screen bg-gray-100 flex items-center justify-center" >
@@ -755,6 +835,13 @@ export default function ClassroomContent({ classId }: { classId: string }) {
755835 currentText = { captionState . currentText }
756836 finalText = { captionState . finalText }
757837 />
838+
839+ { /* Whiteboard Overlay */ }
840+ < Whiteboard
841+ isVisible = { whiteboardVisible }
842+ isTeacher = { role === 'teacher' }
843+ onDrawingUpdate = { handleWhiteboardUpdate }
844+ />
758845 </ div >
759846
760847 { /* Professional Media Controls for Teacher */ }
@@ -836,7 +923,7 @@ export default function ClassroomContent({ classId }: { classId: string }) {
836923 </ div >
837924 </ div >
838925
839- { /* Center Section - Screen Share */ }
926+ { /* Center Section - Screen Share & Whiteboard */ }
840927 < div className = "flex items-center space-x-3" >
841928 < div className = "relative group" >
842929 < button
@@ -860,6 +947,26 @@ export default function ClassroomContent({ classId }: { classId: string }) {
860947 ) }
861948 </ button >
862949 </ div >
950+
951+ < div className = "relative group" >
952+ < button
953+ onClick = { ( ) => setWhiteboardVisible ( ! whiteboardVisible ) }
954+ className = { `px-6 py-3 rounded-lg transition-all duration-200 flex items-center space-x-2 font-medium ${
955+ whiteboardVisible
956+ ? 'bg-purple-500 hover:bg-purple-600 text-white shadow-lg shadow-purple-500/25'
957+ : 'bg-gray-700 hover:bg-gray-600 text-white shadow-lg'
958+ } `}
959+ title = { whiteboardVisible ? 'Hide whiteboard' : 'Show whiteboard' }
960+ >
961+ < svg className = "w-5 h-5" fill = "currentColor" viewBox = "0 0 20 20" >
962+ < path d = "M3 4a1 1 0 011-1h12a1 1 0 011 1v2a1 1 0 01-1 1H4a1 1 0 01-1-1V4zM3 10a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H4a1 1 0 01-1-1v-6zM14 9a1 1 0 00-1 1v6a1 1 0 001 1h2a1 1 0 001-1v-6a1 1 0 00-1-1h-2z" />
963+ </ svg >
964+ < span > 🎨 Whiteboard</ span >
965+ { whiteboardVisible && (
966+ < div className = "w-2 h-2 bg-purple-400 rounded-full animate-pulse" > </ div >
967+ ) }
968+ </ button >
969+ </ div >
863970 </ div >
864971
865972 { /* Right Section - End Session */ }
0 commit comments