1
- import * as React from ' react' ;
1
+ import * as React from " react" ;
2
2
import { Box } from "@mui/material" ;
3
- import Button from '@mui/material/Button' ;
4
- import { useNavigate } from 'react-router-dom' ;
5
- import socket from './socket' ;
6
- import { getAllQuestions } from '../../api/questions/data' ;
7
- import { useAuth } from '../../auth/auth.context' ;
3
+ import Button from "@mui/material/Button" ;
4
+ import Snackbar from "@mui/material/Snackbar" ;
5
+ import Alert from "@mui/material/Alert" ;
6
+ import { useNavigate } from "react-router-dom" ;
7
+ import socket from "./socket" ;
8
+ import { getAllQuestions } from "../../api/questions/data" ;
9
+ import { useAuth } from "../../auth/auth.context" ;
8
10
import { sha256 } from "js-sha256" ;
9
- import Question from ' ../Questions/Question' ;
11
+ import Question from " ../Questions/Question" ;
10
12
11
13
const style = {
12
- position : ' absolute' as ' absolute' ,
13
- top : ' 50%' ,
14
- left : ' 50%' ,
15
- transform : ' translate(-50%, -50%)' ,
16
- width : ' 50%' ,
17
- display : ' flex-wrap' ,
18
- maxHeight : ' 60%' ,
19
- justifyContent : "center" ,
20
- textAlign : "center" ,
21
- bgcolor : ' background.paper' ,
22
- border : ' 2px solid #000' ,
23
- boxShadow : 24 ,
24
- overflow : ' auto' ,
25
- p : 4 ,
14
+ position : " absolute" as " absolute" ,
15
+ top : " 50%" ,
16
+ left : " 50%" ,
17
+ transform : " translate(-50%, -50%)" ,
18
+ width : " 50%" ,
19
+ display : " flex-wrap" ,
20
+ maxHeight : " 60%" ,
21
+ justifyContent : "center" ,
22
+ textAlign : "center" ,
23
+ bgcolor : " background.paper" ,
24
+ border : " 2px solid #000" ,
25
+ boxShadow : 24 ,
26
+ overflow : " auto" ,
27
+ p : 4 ,
26
28
} ;
27
29
30
+
31
+
32
+ const titleStyle = {
33
+ fontSize : "2rem" // Increase the title size
34
+ } ;
35
+
36
+ const subtitleStyle = {
37
+ fontSize : "1.5rem" ,
38
+ padding :'10px' ,
39
+
40
+ // Increase the subtitle size
41
+ } ;
42
+
43
+
44
+ const dropdownStyle = {
45
+ fontSize : "1.5rem" , // Increase the font size
46
+ padding : "10px" , // Add padding for a bigger and more clickable area
47
+ margin : "10px 0" // Space out the dropdowns a bit more
48
+ } ;
49
+
50
+
28
51
const MatchingForm = React . forwardRef ( function MatchingForm ( ) {
29
- const [ difficulty , setDifficulty ] = React . useState ( 'Easy' ) ;
30
- const [ category , setCategory ] = React . useState ( 'Strings' ) ;
31
- const [ categoryList , setCategoryList ] = React . useState < string [ ] > ( [ ] ) ;
32
- const [ isMatching , setIsMatching ] = React . useState ( false ) ;
33
- const navigate = useNavigate ( ) ;
34
- const { user } = useAuth ( ) ;
35
- const userEmail = user ?. email ;
36
-
37
- const handleConnect = ( ) => {
38
- const preferences = {
39
- userEmail,
40
- difficulty,
41
- category,
42
- } ;
43
- socket . emit ( 'startMatching' , preferences ) ;
44
- setIsMatching ( true ) ;
52
+ const [ difficulty , setDifficulty ] = React . useState ( "Easy" ) ;
53
+ const [ category , setCategory ] = React . useState ( "Strings" ) ;
54
+ const [ categoryList , setCategoryList ] = React . useState < string [ ] > ( [ ] ) ;
55
+ const [ isMatching , setIsMatching ] = React . useState ( false ) ;
56
+ const navigate = useNavigate ( ) ;
57
+ const { user } = useAuth ( ) ;
58
+ const userEmail = user ?. email ;
59
+ const [ openSnackbar , setOpenSnackbar ] = React . useState ( false ) ;
60
+
61
+ const handleConnect = async ( ) => {
62
+ const preferences = {
63
+ userEmail,
64
+ difficulty,
65
+ category,
45
66
} ;
67
+ // if no such question with difficulty and category, show a pop up saying no question
68
+ // matching the requirements
46
69
47
- const generateConsistentRandomIndex = ( seed : any , arrayLength : number ) => {
48
- return seed % arrayLength ;
49
- }
70
+ const questions = await getAllQuestions ( ) ;
71
+ const filteredQuestions = questions . data . filter ( ( q : any ) => {
72
+ return q . categories . includes ( category ) && q . difficulty === difficulty ;
73
+ } ) ;
50
74
51
- const getQuestions = async ( seed : any ) => {
52
- const questions = await getAllQuestions ( ) ;
53
- const filteredQuestions = questions . data . filter ( ( q : any ) => {
54
- return q . categories . includes ( category ) && q . difficulty === difficulty
55
- } ) ;
56
-
57
- const randomIndex = generateConsistentRandomIndex ( seed , filteredQuestions . length )
58
- const selectedQuestion = filteredQuestions [ randomIndex ] ;
59
- if ( ! selectedQuestion ) {
60
- return 1
61
- }
62
- const selectedId = selectedQuestion . id ;
63
- return selectedId
75
+ if ( filteredQuestions . length === 0 ) {
76
+ setOpenSnackbar ( true ) ;
77
+ return ;
64
78
}
65
79
66
- React . useEffect ( ( ) => {
67
- async function getCategories ( ) {
68
- const questionsData = await getAllQuestions ( ) as { data : Question [ ] } ;
69
- const allCategories = questionsData . data . reduce ( ( acc : string [ ] , question : Question ) => {
70
- return [ ...acc , ...question . categories ] ;
71
- } , [ ] ) ;
72
- const uniqueCategories = Array . from ( new Set ( allCategories ) ) ;
73
- setCategoryList ( uniqueCategories ) ;
74
- }
75
- getCategories ( ) ;
76
- } , [ ] ) ;
77
-
78
- React . useEffect ( ( ) => {
79
- socket . on ( 'matchFound' , async ( matchedUserPreferences ) => {
80
- console . log ( 'Match Found:' , matchedUserPreferences ) ;
81
- const seed = matchedUserPreferences . seed ;
82
- const matchedUser = matchedUserPreferences . matchedUserPreferences ;
83
- setIsMatching ( false ) ;
84
- const qId = await getQuestions ( seed ) ;
85
- const hashedEmailOne = sha256 ( userEmail || "" ) ;
86
- const hashedEmailTwo = sha256 ( matchedUser . userEmail )
87
- navigate ( `/collab/question/${ qId } /${ hashedEmailOne } /${ hashedEmailTwo } ` ) ;
88
- } ) ;
89
-
90
- return ( ) => {
91
- socket . off ( 'matchFound' ) ;
92
- } ;
93
- } , [ difficulty , category , userEmail , navigate ] ) ;
94
-
95
- return (
96
- < Box sx = { style } >
97
- < h2 > < center > Please select a difficulty and question category.</ center > </ h2 >
98
- < h4 > < center > We will attempt to connect you with a user who chose the same options as you within 30 seconds.</ center > </ h4 >
99
- < div >
100
- < label htmlFor = "difficulty" > Difficulty:</ label >
101
- < select id = "difficulty" value = { difficulty } onChange = { e => setDifficulty ( e . target . value ) } >
102
- < option value = "" > None</ option >
103
- < option value = "Easy" > Easy</ option >
104
- < option value = "Medium" > Medium</ option >
105
- < option value = "Hard" > Hard</ option >
106
- </ select >
107
- </ div >
108
- < div >
109
- < label htmlFor = "category" > Category:</ label >
110
- < select id = "category" value = { category } onChange = { e => setCategory ( e . target . value ) } >
111
- < option value = "" > None</ option >
112
- { categoryList . map ( cat => (
113
- < option key = { cat } value = { cat } > { cat } </ option >
114
- ) ) }
115
- </ select >
116
- </ div >
117
- { isMatching ? (
118
- < div > Loading...</ div >
119
- ) : (
120
- < Button sx = { { mt : '5%' } } variant = "contained" onClick = { handleConnect } >
121
- Connect
122
- </ Button >
123
- ) }
124
- </ Box >
80
+ socket . emit ( "startMatching" , preferences ) ;
81
+ setIsMatching ( true ) ;
82
+ } ;
83
+
84
+ const generateConsistentRandomIndex = ( seed : any , arrayLength : number ) => {
85
+ return seed % arrayLength ;
86
+ } ;
87
+
88
+ const getQuestions = async ( seed : any ) => {
89
+ const questions = await getAllQuestions ( ) ;
90
+ const filteredQuestions = questions . data . filter ( ( q : any ) => {
91
+ return q . categories . includes ( category ) && q . difficulty === difficulty ;
92
+ } ) ;
93
+
94
+ const randomIndex = generateConsistentRandomIndex (
95
+ seed ,
96
+ filteredQuestions . length
125
97
) ;
98
+ const selectedQuestion = filteredQuestions [ randomIndex ] ;
99
+ if ( ! selectedQuestion ) {
100
+ return 1 ;
101
+ }
102
+ const selectedId = selectedQuestion . id ;
103
+ return selectedId ;
104
+ } ;
105
+
106
+ React . useEffect ( ( ) => {
107
+ async function getCategories ( ) {
108
+ const questionsData = ( await getAllQuestions ( ) ) as { data : Question [ ] } ;
109
+ const allCategories = questionsData . data . reduce (
110
+ ( acc : string [ ] , question : Question ) => {
111
+ return [ ...acc , ...question . categories ] ;
112
+ } ,
113
+ [ ]
114
+ ) ;
115
+ const uniqueCategories = Array . from ( new Set ( allCategories ) ) ;
116
+ setCategoryList ( uniqueCategories ) ;
117
+ }
118
+ getCategories ( ) ;
119
+ } , [ ] ) ;
120
+
121
+ React . useEffect ( ( ) => {
122
+ socket . on ( "matchFound" , async ( matchedUserPreferences ) => {
123
+ console . log ( "Match Found:" , matchedUserPreferences ) ;
124
+ const seed = matchedUserPreferences . seed ;
125
+ const matchedUser = matchedUserPreferences . matchedUserPreferences ;
126
+ setIsMatching ( false ) ;
127
+ const qId = await getQuestions ( seed ) ;
128
+ const hashedEmailOne = sha256 ( userEmail || "" ) ;
129
+ const hashedEmailTwo = sha256 ( matchedUser . userEmail ) ;
130
+ navigate ( `/collab/question/${ qId } /${ hashedEmailOne } /${ hashedEmailTwo } ` ) ;
131
+ } ) ;
132
+
133
+ return ( ) => {
134
+ socket . off ( "matchFound" ) ;
135
+ } ;
136
+ } , [ difficulty , category , userEmail , navigate ] ) ;
137
+
138
+ return (
139
+ < Box sx = { style } >
140
+ < h2 style = { titleStyle } >
141
+ < center > Please select a difficulty and question category.</ center >
142
+ </ h2 >
143
+ < h4 style = { subtitleStyle } >
144
+ < center >
145
+ We will attempt to connect you with a user who chose the same options
146
+ as you within 30 seconds.
147
+ </ center >
148
+ </ h4 >
149
+ < div >
150
+ < label htmlFor = "difficulty" style = { subtitleStyle } > Difficulty:</ label >
151
+ < select
152
+ id = "difficulty"
153
+ value = { difficulty }
154
+ onChange = { ( e ) => setDifficulty ( e . target . value ) }
155
+ style = { dropdownStyle }
156
+ >
157
+ < option value = "" > None</ option >
158
+ < option value = "Easy" > Easy</ option >
159
+ < option value = "Medium" > Medium</ option >
160
+ < option value = "Hard" > Hard</ option >
161
+ </ select >
162
+ </ div >
163
+ < div >
164
+ < label htmlFor = "category" style = { subtitleStyle } > Category:</ label >
165
+ < select
166
+ id = "category"
167
+ value = { category }
168
+ onChange = { ( e ) => setCategory ( e . target . value ) }
169
+ style = { dropdownStyle }
170
+ >
171
+ < option value = "" > None</ option >
172
+ { categoryList . map ( ( cat ) => (
173
+ < option key = { cat } value = { cat } >
174
+ { cat }
175
+ </ option >
176
+ ) ) }
177
+ </ select >
178
+ </ div >
179
+ { isMatching ? (
180
+ < div > Loading...</ div >
181
+ ) : (
182
+ < Button sx = { { mt : "5%" } } variant = "contained" onClick = { handleConnect } >
183
+ Connect
184
+ </ Button >
185
+ ) }
186
+
187
+ < Snackbar
188
+ open = { openSnackbar }
189
+ autoHideDuration = { 6000 }
190
+ onClose = { ( ) => setOpenSnackbar ( false ) }
191
+ anchorOrigin = { { vertical : "top" , horizontal : "center" } }
192
+ >
193
+ < Alert
194
+ onClose = { ( ) => setOpenSnackbar ( false ) }
195
+ severity = "warning"
196
+ sx = { { width : "100%" } }
197
+ >
198
+ No questions match the selected difficulty and category.
199
+ </ Alert >
200
+ </ Snackbar >
201
+ </ Box >
202
+ ) ;
126
203
} ) ;
127
204
128
- export default MatchingForm ;
205
+ export default MatchingForm ;
0 commit comments