Skip to content

Commit 9845a25

Browse files
authored
Merge pull request #67 from jolynloh/BE/stopmatch
Add question check before matching & show confirmation popup before leaving matching pages
2 parents 63de714 + fa3e33d commit 9845a25

File tree

5 files changed

+69
-29
lines changed

5 files changed

+69
-29
lines changed

frontend/src/contexts/MatchContext.tsx

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import { createContext, useContext, useEffect, useState } from "react";
44
import { matchSocket } from "../utils/matchSocket";
55
import {
6+
ABORT_MATCH_PROCESS_CONFIRMATION_MESSAGE,
67
FAILED_MATCH_REQUEST_MESSAGE,
78
MATCH_CONNECTION_ERROR,
89
MATCH_ENDED_MESSAGE,
@@ -131,11 +132,22 @@ const MatchProvider: React.FC<{ children?: React.ReactNode }> = (props) => {
131132
openSocketConnection();
132133
matchSocket.emit(MatchEvents.USER_CONNECTED, matchUser?.id);
133134

134-
window.addEventListener("beforeunload", () => closeSocketConnection());
135+
const handleBeforeUnload = (e: BeforeUnloadEvent) => {
136+
e.preventDefault();
137+
e.returnValue = ABORT_MATCH_PROCESS_CONFIRMATION_MESSAGE; // for legacy support, does not actually display message
138+
};
139+
140+
const handleUnload = () => {
141+
closeSocketConnection();
142+
};
143+
144+
window.addEventListener("beforeunload", handleBeforeUnload);
145+
window.addEventListener("unload", handleUnload);
135146

136147
return () => {
137148
closeSocketConnection();
138-
window.removeEventListener("beforeunload", () => closeSocketConnection());
149+
window.removeEventListener("beforeunload", handleBeforeUnload);
150+
window.removeEventListener("unload", handleUnload);
139151
};
140152
// eslint-disable-next-line react-hooks/exhaustive-deps
141153
}, [matchUser?.id, location.pathname]);

frontend/src/pages/Home/index.tsx

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import {
77
Grid2,
88
TextField,
99
Typography,
10+
CircularProgress,
11+
useMediaQuery,
1012
} from "@mui/material";
1113
import { useEffect, useReducer, useState } from "react";
1214

@@ -17,23 +19,28 @@ import {
1719
languageList,
1820
maxMatchTimeout,
1921
minMatchTimeout,
22+
QUESTION_DOES_NOT_EXIST_ERROR,
2023
USE_MATCH_ERROR_MESSAGE,
2124
} from "../../utils/constants";
2225
import reducer, {
2326
getQuestionCategories,
27+
getQuestionList,
2428
initialState as initialState,
2529
} from "../../reducers/questionReducer";
2630
import CustomChip from "../../components/CustomChip";
2731
import homepageImage from "/homepage_image.svg";
2832
import { useMatch } from "../../contexts/MatchContext";
2933
import Loader from "../../components/Loader";
34+
import { toast } from "react-toastify";
3035

3136
const Home: React.FC = () => {
3237
const [complexities, setComplexities] = useState<string[]>([]);
3338
const [categories, setCategories] = useState<string[]>([]);
3439
const [languages, setLanguages] = useState<string[]>([]);
3540
const [timeout, setTimeout] = useState<number | undefined>(30);
3641

42+
const [isQueryingQnDB, setIsQueryingQnDB] = useState<boolean>(false);
43+
3744
const [state, dispatch] = useReducer(reducer, initialState);
3845

3946
const match = useMatch();
@@ -42,10 +49,23 @@ const Home: React.FC = () => {
4249
}
4350
const { findMatch, loading } = match;
4451

52+
const isSmallerThan1100px = useMediaQuery('(max-width:1100px)');
53+
4554
useEffect(() => {
4655
getQuestionCategories(dispatch);
4756
}, []);
4857

58+
useEffect(() => {
59+
if (isQueryingQnDB) {
60+
if (state.questions.length > 0) {
61+
findMatch(complexities, categories, languages, timeout!);
62+
} else {
63+
toast.error(QUESTION_DOES_NOT_EXIST_ERROR);
64+
}
65+
}
66+
setIsQueryingQnDB(false);
67+
}, [state.questions]);
68+
4969
if (loading) {
5070
return <Loader />;
5171
}
@@ -78,19 +98,21 @@ const Home: React.FC = () => {
7898
Specify your question preferences and sit back as we find you the best
7999
match.
80100
</Typography>
81-
<Box
82-
component="img"
83-
src={homepageImage}
84-
alt="Interview Practice Buddy"
85-
sx={{
86-
position: "absolute",
87-
top: "35%",
88-
left: "10%",
89-
width: "128px",
90-
height: "auto",
91-
objectFit: "contain",
92-
}}
93-
/>
101+
{isSmallerThan1100px && (
102+
<Box
103+
component="img"
104+
src={homepageImage}
105+
alt="Interview Practice Buddy"
106+
sx={{
107+
position: "absolute",
108+
top: "35%",
109+
left: "10%",
110+
width: "128px",
111+
height: "auto",
112+
objectFit: "contain",
113+
}}
114+
/>
115+
)}
94116
<Card
95117
sx={{
96118
padding: 4,
@@ -272,11 +294,12 @@ const Home: React.FC = () => {
272294
categories.length == 0 ||
273295
languages.length == 0
274296
}
275-
onClick={() =>
276-
findMatch(complexities, categories, languages, timeout!)
277-
}
297+
onClick={() => {
298+
setIsQueryingQnDB(true);
299+
getQuestionList(1, 10, "", complexities, categories, dispatch);
300+
}}
278301
>
279-
Find my match!
302+
{isQueryingQnDB ? <CircularProgress /> : "Find my match!"}
280303
</Button>
281304
</Card>
282305
</AppMargin>

frontend/src/pages/NewQuestion/index.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import reducer, {
1515
import { toast } from "react-toastify";
1616

1717
import {
18+
ABORT_CREATE_OR_EDIT_QUESTION_CONFIRMATION_MESSAGE,
1819
complexityList,
1920
FAILED_QUESTION_CREATE,
2021
FILL_ALL_FIELDS,
@@ -47,11 +48,7 @@ const NewQuestion = () => {
4748
selectedComplexity ||
4849
selectedCategories.length > 0
4950
) {
50-
if (
51-
!confirm(
52-
"Are you sure you want to leave this page? All process will be lost."
53-
)
54-
) {
51+
if (!confirm(ABORT_CREATE_OR_EDIT_QUESTION_CONFIRMATION_MESSAGE)) {
5552
return;
5653
}
5754
}

frontend/src/pages/QuestionEdit/index.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import ArrowBackIcon from "@mui/icons-material/ArrowBack";
1111
import { toast } from "react-toastify";
1212

1313
import {
14+
ABORT_CREATE_OR_EDIT_QUESTION_CONFIRMATION_MESSAGE,
1415
complexityList,
1516
FAILED_QUESTION_UPDATE,
1617
FILL_ALL_FIELDS,
@@ -61,11 +62,7 @@ const QuestionEdit = () => {
6162
}, [state.selectedQuestion]);
6263

6364
const handleBack = () => {
64-
if (
65-
!confirm(
66-
"Are you sure you want to leave this page? All process will be lost."
67-
)
68-
) {
65+
if (!confirm(ABORT_CREATE_OR_EDIT_QUESTION_CONFIRMATION_MESSAGE)) {
6966
return;
7067
}
7168
navigate("/questions");

frontend/src/utils/constants.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,17 @@ export const MATCH_LOGIN_REQUIRED_MESSAGE =
9696
export const MATCH_OFFER_TIMEOUT_MESSAGE = "Match offer timeout!";
9797
export const MATCH_CONNECTION_ERROR =
9898
"Connection error! Please try again later.";
99+
export const QUESTION_DOES_NOT_EXIST_ERROR =
100+
"There are no questions with the specified complexity and category. Please try another combination.";
101+
102+
/* Alerts & Dialog Boxes */
103+
// Questions
104+
export const ABORT_CREATE_OR_EDIT_QUESTION_CONFIRMATION_MESSAGE =
105+
"Are you sure you want to leave this page? All process will be lost.";
106+
107+
// Match
108+
export const ABORT_MATCH_PROCESS_CONFIRMATION_MESSAGE =
109+
"Are you sure you want to leave the matching process?";
99110

100111
/* Image paths */
101112
export const FIND_MATCH_FORM_PATH = "/find_match_form.png";

0 commit comments

Comments
 (0)