Skip to content

Commit b4f9609

Browse files
committed
fix matching link by sorting
1 parent 88dcc9e commit b4f9609

File tree

1 file changed

+189
-103
lines changed

1 file changed

+189
-103
lines changed
Lines changed: 189 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,119 +1,205 @@
1-
import * as React from 'react';
1+
import * as React from "react";
22
import { Box } from "@mui/material";
3-
import Button from '@mui/material/Button';
4-
import InputLabel from '@mui/material/InputLabel';
5-
import MenuItem from '@mui/material/MenuItem';
6-
import FormControl from '@mui/material/FormControl';
7-
import Select, { SelectChangeEvent } from '@mui/material/Select';
8-
import { useNavigate } from 'react-router-dom'; // Import useNavigate for redirection
9-
import socket from './socket';
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";
10+
import { sha256 } from "js-sha256";
11+
import Question from "../Questions/Question";
1012

1113
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,
2628
};
2729

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+
2851
const MatchingForm = React.forwardRef(function MatchingForm() {
29-
const [difficulty, setDifficulty] = React.useState('');
30-
const [category, setCategory] = React.useState('');
31-
const [isMatching, setIsMatching] = React.useState(false); // Track matching state
32-
const navigate = useNavigate(); // Get navigate for redirection
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);
3360

34-
const handleDiffChange = (event: SelectChangeEvent) => {
35-
setDifficulty(event.target.value);
61+
const handleConnect = async () => {
62+
const preferences = {
63+
userEmail,
64+
difficulty,
65+
category,
3666
};
67+
// if no such question with difficulty and category, show a pop up saying no question
68+
// matching the requirements
3769

38-
const handleCatChange = (event: SelectChangeEvent) => {
39-
setCategory(event.target.value);
40-
};
70+
const questions = await getAllQuestions();
71+
const filteredQuestions = questions.data.filter((q: any) => {
72+
return q.categories.includes(category) && q.difficulty === difficulty;
73+
});
4174

42-
const handleConnect = () => {
43-
const preferences = {
44-
difficulty,
45-
category,
46-
};
75+
if (filteredQuestions.length === 0) {
76+
setOpenSnackbar(true);
77+
return;
78+
}
4779

48-
// Emit the startMatching event to the server with user preferences
49-
socket.emit('startMatching', preferences);
80+
socket.emit("startMatching", preferences);
81+
setIsMatching(true);
82+
};
5083

51-
// Set matching state to true when attempting to match
52-
setIsMatching(true);
53-
};
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+
});
5493

55-
// Handle the "matchFound" event from the server
56-
React.useEffect(() => {
57-
socket.on('matchFound', (matchedUserPreferences) => {
58-
// Handle the matched user's preferences here
59-
console.log('Match Found:', matchedUserPreferences);
60-
setIsMatching(false); // Set matching state to false
61-
// Redirect to the question page with the code editor
62-
navigate('/question'); // Update the route as needed
63-
});
64-
65-
// Clean up the event listener when the component unmounts
66-
return () => {
67-
socket.off('matchFound');
68-
};
69-
}, [navigate]);
70-
71-
return (
72-
<Box sx={style}>
73-
<h2><center>Please select a difficulty and question category.</center></h2>
74-
<h4><center>We will attempt to connect you with a user who chose the same options as you within 30 seconds.</center></h4>
75-
<FormControl sx={{ mt: 1, width: '100%' }}>
76-
<InputLabel id="demo-simple-select-helper-label">Difficulty</InputLabel>
77-
<Select
78-
labelId="demo-simple-select-helper-label"
79-
id="demo-simple-select-helper"
80-
value={difficulty}
81-
label="Difficulty"
82-
onChange={handleDiffChange}
83-
>
84-
<MenuItem value="">
85-
<em>None</em>
86-
</MenuItem>
87-
<MenuItem value={'Easy'}>Easy</MenuItem>
88-
<MenuItem value={'Medium'}>Medium</MenuItem>
89-
<MenuItem value={'Hard'}>Hard</MenuItem>
90-
</Select>
91-
</FormControl>
92-
<FormControl sx={{ mt: 1, mb: 1, width: '100%' }}>
93-
<InputLabel id="demo-simple-select-helper-label">Category</InputLabel>
94-
<Select
95-
labelId="demo-simple-select-helper-label"
96-
id="demo-simple-select-helper"
97-
value={category}
98-
label="Category"
99-
onChange={handleCatChange}
100-
>
101-
<MenuItem value="">
102-
<em>None</em>
103-
</MenuItem>
104-
<MenuItem value={'Algo'}>Algo</MenuItem>
105-
<MenuItem value={'ML'}>ML</MenuItem>
106-
</Select>
107-
</FormControl>
108-
{isMatching ? (
109-
<div>Loading...</div> // Show loading spinner
110-
) : (
111-
<Button sx={{ mt: '5%' }} variant="contained" onClick={handleConnect}>
112-
Connect
113-
</Button>
114-
)}
115-
</Box>
94+
const randomIndex = generateConsistentRandomIndex(
95+
seed,
96+
filteredQuestions.length
11697
);
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+
);
117203
});
118204

119-
export default MatchingForm;
205+
export default MatchingForm;

0 commit comments

Comments
 (0)