Skip to content

Commit f77bbfa

Browse files
authored
Merge pull request #59 from CS3219-AY2425S1/frontend-changes2
Frontend changes2
2 parents 48d6745 + 3ff07c4 commit f77bbfa

File tree

10 files changed

+338
-353
lines changed

10 files changed

+338
-353
lines changed
Lines changed: 170 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -1,154 +1,185 @@
1-
import React, { useState, useEffect } from "react";
2-
import { Modal } from "antd";
3-
import "typeface-montserrat";
4-
import "./styles.scss";
5-
import FindMatchContent from "./modalContent/FindMatchContent";
6-
import MatchingInProgressContent from "./modalContent/MatchingInProgressContent";
7-
import MatchFoundContent from "./modalContent/MatchFoundContent";
8-
import JoinedMatchContent from "./modalContent/JoinedMatchContent";
9-
import MatchNotFoundContent from "./modalContent/MatchNotFoundContent";
10-
import MatchCancelledContent from "./modalContent/MatchCancelledContent";
11-
import useMatching from "../services/use-matching";
12-
import { useRouter } from "next/navigation";
1+
"use client"
2+
3+
import React, { useState, useEffect } from 'react';
4+
import {
5+
Form,
6+
Button,
7+
Modal,
8+
} from 'antd';
9+
import 'typeface-montserrat';
10+
import './styles.scss';
11+
import FindMatchContent from './modalContent/FindMatchContent';
12+
import MatchingInProgressContent from './modalContent/MatchingInProgressContent';
13+
import MatchFoundContent from './modalContent/MatchFoundContent';
14+
import JoinedMatchContent from './modalContent/JoinedMatchContent';
15+
import MatchNotFoundContent from './modalContent/MatchNotFoundContent';
16+
import MatchCancelledContent from './modalContent/MatchCancelledContent';
17+
import useMatching from '../services/use-matching';
18+
import { ValidateUser } from '../services/user';
19+
import { useTimer } from 'react-timer-hook';
20+
import { useRouter } from 'next/navigation';
1321

1422
interface MatchingModalProps {
1523
isOpen: boolean;
1624
close: () => void;
1725
}
1826

19-
const MatchingModal: React.FC<MatchingModalProps> = ({
20-
isOpen,
21-
close: _close,
22-
}) => {
23-
const router = useRouter();
24-
const matchingState = useMatching();
25-
const [closedType, setClosedType] = useState<
26-
"finding" | "cancelled" | "joined"
27-
>("finding");
28-
const [timeoutAfter, setTimeoutAfter] = useState<number>(9999);
29-
const isClosable = ["timeout", "closed"].includes(matchingState.state);
27+
export interface MatchParams {
28+
topics: string[],
29+
difficulties: string[],
30+
}
31+
const MATCH_TIMEOUT = 30;
32+
const JOIN_TIMEOUT = 5;
3033

31-
function close() {
32-
// clean up matching and closedType State
33-
if (matchingState.state === "timeout") {
34-
matchingState.ok();
35-
}
36-
setClosedType("finding");
37-
_close();
38-
}
34+
const MatchingModal: React.FC<MatchingModalProps> = ({ isOpen, close: _close }) => {
35+
const matchingState = useMatching();
36+
const [closedType, setClosedType] = useState<"finding" | "cancelled" | "joined">("finding");
37+
const isClosable = ["timeout", "closed"].includes(matchingState.state) && closedType != "joined";
38+
const router = useRouter();
39+
const { totalSeconds, pause: pauseTimer, restart: restartTimer } = useTimer({
40+
expiryTimestamp: new Date(Date.now() + MATCH_TIMEOUT * 1000),
41+
autoStart: false,
42+
onExpire() {
43+
if (matchingState.state === "matching") {
44+
matchingState.timeout();
45+
return;
46+
}
47+
if (matchingState.state === "found") {
48+
join();
49+
return;
50+
}
51+
console.warn(`matching is in ${matchingState.state}`)
52+
},
53+
});
54+
const passed = MATCH_TIMEOUT - totalSeconds;
3955

40-
const renderModalContent = () => {
41-
switch (matchingState.state) {
42-
case "closed":
43-
switch (closedType) {
44-
case "finding":
45-
return <FindMatchContent beginMatch={matchingState.start} />;
46-
case "cancelled":
47-
return (
48-
<MatchCancelledContent
49-
reselect={() => {
50-
setClosedType("finding");
51-
}}
52-
retry={() => {}}
53-
canceledIn={timeoutAfter}
54-
/>
55-
);
56-
case "joined":
57-
return (
58-
<JoinedMatchContent
59-
cancel={() => {
60-
setClosedType("cancelled");
61-
}}
62-
name1={matchingState.info?.user || ""}
63-
name2={matchingState.info?.matchedUser || ""}
64-
/>
65-
);
56+
function close() {
57+
// clean up matching and closedType State
58+
if (matchingState.state === "timeout") {
59+
matchingState.ok();
6660
}
67-
case "matching":
68-
return (
69-
<MatchingInProgressContent
70-
cancelMatch={(timeoutAfter: number) => {
71-
setClosedType("cancelled");
72-
setTimeoutAfter(timeoutAfter);
73-
matchingState.cancel();
74-
}}
75-
timeout={(timeoutAfter: number) => {
76-
matchingState.timeout();
77-
setTimeoutAfter(timeoutAfter);
78-
}}
79-
/>
80-
);
81-
case "cancelling":
82-
return (
83-
<MatchingInProgressContent
84-
cancelMatch={() => {}}
85-
timeout={() => {}}
86-
/>
87-
);
88-
case "starting":
89-
return <FindMatchContent beginMatch={() => {}} />;
90-
case "found":
91-
return (
92-
<MatchFoundContent
93-
cancel={() => {
94-
matchingState.ok();
95-
setClosedType("cancelled");
96-
}}
97-
join={() => {
98-
matchingState.ok();
99-
setClosedType("joined");
100-
localStorage.setItem("user", matchingState.info.user);
101-
localStorage.setItem(
102-
"matchedUser",
103-
matchingState.info.matchedUser
104-
);
105-
localStorage.setItem("collabId", matchingState.info.matchId);
106-
localStorage.setItem(
107-
"questionDocRefId",
108-
matchingState.info.questionDocRefId
109-
);
110-
localStorage.setItem(
111-
"matchedTopics",
112-
matchingState.info.matchedTopics.join(",")
113-
);
61+
setClosedType("finding");
62+
_close();
63+
}
11464

115-
// Redirect to collaboration page
116-
router.push(`/collaboration/${matchingState.info.matchId}`);
117-
}}
118-
name1={matchingState.info.user}
119-
name2={matchingState.info.matchedUser}
120-
/>
65+
const startMatch = matchingState.state == "closed" || matchingState.state == "timeout" ? async (params: MatchParams): Promise<void> => {
66+
const user = await ValidateUser();
67+
68+
restartTimer(
69+
new Date(Date.now() + MATCH_TIMEOUT * 1000),
12170
);
122-
case "timeout":
123-
return (
124-
<MatchNotFoundContent
125-
reselect={matchingState.ok}
126-
retry={() => {}}
127-
timedOutIn={10}
128-
/>
71+
72+
matchingState.start({
73+
email: user.data.email,
74+
username: user.data.username,
75+
type: "match_request",
76+
...params
77+
});
78+
} : undefined;
79+
80+
const join = matchingState.state == "found" ? (() => {
81+
matchingState.ok();
82+
setClosedType("joined");
83+
localStorage.setItem("user", matchingState.info.user);
84+
localStorage.setItem(
85+
"matchedUser",
86+
matchingState.info.matchedUser
12987
);
130-
default:
131-
throw new Error("Invalid matching state.");
132-
}
133-
};
88+
localStorage.setItem("collabId", matchingState.info.matchId);
89+
localStorage.setItem("questionDocRefId", matchingState.info.questionDocRefId);
90+
localStorage.setItem("matchedTopics", matchingState.info.matchedTopics.join(","));
91+
92+
// Redirect to collaboration page
93+
router.push(`/collaboration/${matchingState.info.matchId}`);
94+
}) : () => { throw new Error("join called when not found"); }
95+
96+
useEffect(() => {
97+
if (matchingState.state === "cancelling" || matchingState.state === "timeout") {
98+
pauseTimer();
99+
return;
100+
}
101+
if (matchingState.state === "found") {
102+
restartTimer(
103+
new Date(Date.now() + JOIN_TIMEOUT * 1000),
104+
)
105+
}
106+
}, [matchingState])
134107

135-
return (
136-
<Modal
137-
open={isOpen}
138-
onCancel={close}
139-
footer={null}
140-
closable={false}
141-
maskClosable={false}
142-
className="modal"
143-
>
144-
{renderModalContent()}
145-
{isClosable && (
146-
<button className="close-button" onClick={close}>
147-
Close
148-
</button>
149-
)}
150-
</Modal>
151-
);
152-
};
108+
const renderModalContent = () => {
109+
switch (matchingState.state) {
110+
case 'closed':
111+
switch (closedType) {
112+
case "finding":
113+
return <FindMatchContent beginMatch={params => {}}/>;
114+
case "cancelled":
115+
return <MatchCancelledContent
116+
reselect={() => {
117+
setClosedType("finding");
118+
}}
119+
canceledIn={passed}
120+
/>;
121+
case "joined":
122+
return <JoinedMatchContent
123+
cancel={() => {
124+
setClosedType("cancelled");
125+
}}
126+
name1={matchingState.info?.user ?? ""}
127+
name2={matchingState.info?.matchedUser ?? ""}
128+
/>;
129+
}
130+
case 'matching':
131+
return <MatchingInProgressContent
132+
cancelMatch={() => {
133+
setClosedType("cancelled");
134+
matchingState.cancel();
135+
pauseTimer();
136+
}}
137+
timePassed={passed}
138+
/>;
139+
case 'cancelling':
140+
return <MatchingInProgressContent cancelMatch={() => {}} timePassed={passed}/>;
141+
case 'starting':
142+
return <FindMatchContent beginMatch={() => {}}/>
143+
case 'found':
144+
return <MatchFoundContent
145+
cancel={() => {
146+
matchingState.ok();
147+
setClosedType("cancelled");
148+
}}
149+
join={join}
150+
name1={matchingState.info.user}
151+
name2={matchingState.info.matchedUser}
152+
joiningIn={totalSeconds}
153+
/>
154+
case 'timeout':
155+
return <MatchNotFoundContent reselect={matchingState.ok} timedOutIn={passed}/>;
156+
default:
157+
throw new Error('Invalid matching state.');
158+
}
159+
}
160+
161+
return (
162+
<Modal open={isOpen}
163+
onCancel={close}
164+
footer={null}
165+
closable={false}
166+
maskClosable={false}
167+
className="modal"
168+
>
169+
<Form<MatchParams>
170+
name="match"
171+
onFinish={startMatch}
172+
initialValues={{
173+
topics: [],
174+
difficulties: [],
175+
}}>
176+
{renderModalContent()}
177+
</Form>
178+
{isClosable && (
179+
<button className="close-button" onClick={close}>Close</button>
180+
)}
181+
</Modal>
182+
)
183+
}
153184

154185
export default MatchingModal;

0 commit comments

Comments
 (0)