1- import React , { useEffect , useRef } from " react" ;
1+ import React , { useEffect , useRef } from ' react' ;
22
33function CoursePagePopup ( {
4- favouriteCourses,
5- addFavourite,
6- removeFavourite,
7- isOpen,
8- onClose,
9- course,
10- prerequisiteTree,
11- reviewPresenter,
12- } ) {
13- const treeRef = useRef ( null ) ;
14- useEffect ( ( ) => {
15- const handleKeyDown = ( event ) => {
16- if ( event . key === "Escape" ) {
17- onClose ( ) ;
18- }
19- } ;
4+ favouriteCourses,
5+ handleFavouriteClick,
6+ isOpen,
7+ onClose,
8+ course,
9+ prerequisiteTree,
10+ reviewPresenter,
11+ } ) {
12+ const treeRef = useRef ( null ) ;
2013
21- if ( isOpen ) {
22- window . addEventListener ( "keydown" , handleKeyDown ) ;
23- }
14+ useEffect ( ( ) => {
15+ const handleKeyDown = ( event ) => {
16+ if ( event . key === 'Escape' ) {
17+ onClose ( ) ;
18+ }
19+ } ;
20+ if ( isOpen ) {
21+ window . addEventListener ( 'keydown' , handleKeyDown ) ;
22+ }
23+ return ( ) => {
24+ window . removeEventListener ( 'keydown' , handleKeyDown ) ;
25+ } ;
26+ } , [ isOpen , onClose ] ) ;
2427
25- return ( ) => {
26- window . removeEventListener ( "keydown" , handleKeyDown ) ;
27- } ;
28- } , [ isOpen , onClose ] ) ;
28+ const handleTreeClick = ( ) => {
29+ if ( treeRef . current ) {
30+ treeRef . current . focus ( ) ;
31+ }
32+ } ;
2933
30- const handleFavouriteClick = ( course ) => {
31- if ( favouriteCourses . some ( ( fav ) => fav . code === course . code ) ) {
32- removeFavourite ( course ) ;
33- } else {
34- addFavourite ( course ) ;
35- }
36- } ;
34+ if ( ! isOpen || ! course ) return null ;
3735
38- const handleTreeClick = ( ) => {
39- if ( treeRef . current ) {
40- treeRef . current . focus ( ) ; // gives it focus
41- }
42- } ;
43-
44- if ( ! isOpen || ! course ) return null ; // Don't render if not open or course not selected
45- return (
46- < div
47- className = "fixed backdrop-blur-sm inset-0 bg-transparent flex justify-end z-50"
48- onClick = { onClose }
49- >
50- < div
51- className = "bg-indigo-300/75 backdrop-blur-lg h-full w-3/4 flex flex-col overflow-auto"
52- onClick = { ( e ) => e . stopPropagation ( ) }
53- >
54- < div className = "flex-1" >
55- < div className = "px-10 py-10 md:px-20 md:py-16 text-slate-900 space-y-12 font-sans" >
56- { /* Course Title Section */ }
57- < div >
58- < h2 className = "text-5xl font-extrabold text-[#2e2e4f] " >
59- < span className = "text-violet-700" > { course . code } </ span > -{ " " }
60- { course . name }
61- < span className = "ml-4 text-lg text-violet-700 whitespace-nowrap" >
62- ({ course . credits } Credits)
63- </ span >
64- </ h2 >
65- < div className = "my-6 h-1.5 w-full bg-violet-500" > </ div >
66- </ div >
67- < div >
68- < button
69- className = "text-yellow-500 bg-yellow-400 cursor-pointer"
70- onClick = { ( e ) => {
71- e . stopPropagation ( ) ; // prevent popup from opening
72- handleFavouriteClick ( course . code ) ;
73- } }
74- >
75- { favouriteCourses . includes ( course . code )
76- ? "Remove from Favourites"
77- : "Add to Favourites" }
78- </ button >
79- </ div >
80-
81- { /* Description Section */ }
82- < div >
83- < h3 className = "text-2xl font-bold text-[#2e2e4f] mb-0.5" >
84- Course Description
85- </ h3 >
86- < div className = "mb-3 h-0.5 w-full bg-violet-500" > </ div >
87- < div
88- className = "text-lg leading-8 text-[#2e2e4f] font-semibold tracking-wide prose prose-slate max-w-full"
89- dangerouslySetInnerHTML = { { __html : course . description } }
90- />
91- </ div >
92-
93- { /* Prerequisite Graph Tree Section */ }
94- < div >
95- < h3 className = "text-2xl font-semibold text-[#2e2e4f] mb-0.5" >
96- Prerequisite Graph Tree
97- </ h3 >
98- < div className = "mb-4 h-0.5 w-full bg-violet-500" > </ div >
99- < div
100- className = "bg-indigo-300/50 outline-none focus:outline-none focus:ring-2 focus:ring-violet-600 rounded-lg transition-shadow"
101- ref = { treeRef }
102- onClick = { handleTreeClick }
103- tabIndex = { 0 } // allows the div to receive focus
104- >
105- { prerequisiteTree }
106- </ div >
107- </ div >
108- { reviewPresenter }
109- </ div >
110- </ div >
111- < button
112- onClick = { onClose }
113- className = "px-4 py-2 bg-violet-500 text-white"
114- >
115- Close
116- </ button >
117- </ div >
118- </ div >
119- ) ;
36+ return (
37+ < div
38+ className = "fixed backdrop-blur-sm inset-0 bg-transparent flex justify-end z-50"
39+ onClick = { onClose }
40+ >
41+ < div
42+ className = "bg-indigo-300/75 backdrop-blur-lg h-full w-3/4 flex flex-col overflow-auto"
43+ onClick = { ( e ) => e . stopPropagation ( ) }
44+ >
45+ < div className = "flex-1" >
46+ < div className = "px-10 py-10 md:px-20 md:py-16 text-slate-900 space-y-12 font-sans" >
47+ { /* Course Title Section */ }
48+ < div >
49+ < h2 className = "text-5xl font-extrabold text-[#2e2e4f]" >
50+ < span className = "text-violet-700" > { course . code } </ span > - { course . name }
51+ < span className = "ml-4 text-lg text-violet-700 whitespace-nowrap" >
52+ ({ course . credits } Credits)
53+ </ span >
54+ </ h2 >
55+ < div className = "my-6 h-1.5 w-full bg-violet-500" > </ div >
56+ </ div >
57+ < div >
58+ < button
59+ className = "text-yellow-100 bg-yellow-400 cursor-pointer"
60+ onClick = { ( e ) => {
61+ e . stopPropagation ( ) ;
62+ handleFavouriteClick ( course ) ;
63+ } }
64+ >
65+ { favouriteCourses . some ( ( fav ) => fav . code === course . code )
66+ ? 'Remove from Favourites'
67+ : 'Add to Favourites' }
68+ </ button >
69+ </ div >
70+ { /* Description Section */ }
71+ < div >
72+ < h3 className = "text-2xl font-bold text-[#2e2e4f] mb-0.5" > Course Description</ h3 >
73+ < div className = "mb-3 h-0.5 w-full bg-violet-500" > </ div >
74+ < div
75+ className = "text-lg leading-8 text-[#2e2e4f] font-semibold tracking-wide prose prose-slate max-w-full"
76+ dangerouslySetInnerHTML = { { __html : course . description } }
77+ />
78+ </ div >
79+ { /* Prerequisite Graph Tree Section */ }
80+ < div >
81+ < h3 className = "text-2xl font-semibold text-[#2e2e4f] mb-0.5" > Prerequisite Graph Tree</ h3 >
82+ < div className = "mb-4 h-0.5 w-full bg-violet-500" > </ div >
83+ < div
84+ className = "bg-indigo-300/50 outline-none focus:outline-none focus:ring-2 focus:ring-violet-600 rounded-lg transition-shadow"
85+ ref = { treeRef }
86+ onClick = { handleTreeClick }
87+ tabIndex = { 0 }
88+ >
89+ { prerequisiteTree }
90+ </ div >
91+ </ div >
92+ { /* Reviews Section (optional) */ }
93+ { reviewPresenter && (
94+ < div >
95+ < h3 className = "text-2xl font-semibold text-[#2e2e4f] mb-0.5" > Reviews</ h3 >
96+ < div className = "mb-4 h-0.5 w-full bg-violet-500" > </ div >
97+ { reviewPresenter }
98+ </ div >
99+ ) }
100+ </ div >
101+ </ div >
102+ < button onClick = { onClose } className = "px-4 py-2 bg-violet-500 text-white" >
103+ Close
104+ </ button >
105+ </ div >
106+ </ div >
107+ ) ;
120108}
121109
122- export default CoursePagePopup ;
110+ export default CoursePagePopup ;
0 commit comments