-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #59 from CS3219-AY2425S1/frontend-changes2
Frontend changes2
- Loading branch information
Showing
10 changed files
with
338 additions
and
353 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,154 +1,185 @@ | ||
import React, { useState, useEffect } from "react"; | ||
import { Modal } from "antd"; | ||
import "typeface-montserrat"; | ||
import "./styles.scss"; | ||
import FindMatchContent from "./modalContent/FindMatchContent"; | ||
import MatchingInProgressContent from "./modalContent/MatchingInProgressContent"; | ||
import MatchFoundContent from "./modalContent/MatchFoundContent"; | ||
import JoinedMatchContent from "./modalContent/JoinedMatchContent"; | ||
import MatchNotFoundContent from "./modalContent/MatchNotFoundContent"; | ||
import MatchCancelledContent from "./modalContent/MatchCancelledContent"; | ||
import useMatching from "../services/use-matching"; | ||
import { useRouter } from "next/navigation"; | ||
"use client" | ||
|
||
import React, { useState, useEffect } from 'react'; | ||
import { | ||
Form, | ||
Button, | ||
Modal, | ||
} from 'antd'; | ||
import 'typeface-montserrat'; | ||
import './styles.scss'; | ||
import FindMatchContent from './modalContent/FindMatchContent'; | ||
import MatchingInProgressContent from './modalContent/MatchingInProgressContent'; | ||
import MatchFoundContent from './modalContent/MatchFoundContent'; | ||
import JoinedMatchContent from './modalContent/JoinedMatchContent'; | ||
import MatchNotFoundContent from './modalContent/MatchNotFoundContent'; | ||
import MatchCancelledContent from './modalContent/MatchCancelledContent'; | ||
import useMatching from '../services/use-matching'; | ||
import { ValidateUser } from '../services/user'; | ||
import { useTimer } from 'react-timer-hook'; | ||
import { useRouter } from 'next/navigation'; | ||
|
||
interface MatchingModalProps { | ||
isOpen: boolean; | ||
close: () => void; | ||
} | ||
|
||
const MatchingModal: React.FC<MatchingModalProps> = ({ | ||
isOpen, | ||
close: _close, | ||
}) => { | ||
const router = useRouter(); | ||
const matchingState = useMatching(); | ||
const [closedType, setClosedType] = useState< | ||
"finding" | "cancelled" | "joined" | ||
>("finding"); | ||
const [timeoutAfter, setTimeoutAfter] = useState<number>(9999); | ||
const isClosable = ["timeout", "closed"].includes(matchingState.state); | ||
export interface MatchParams { | ||
topics: string[], | ||
difficulties: string[], | ||
} | ||
const MATCH_TIMEOUT = 30; | ||
const JOIN_TIMEOUT = 5; | ||
|
||
function close() { | ||
// clean up matching and closedType State | ||
if (matchingState.state === "timeout") { | ||
matchingState.ok(); | ||
} | ||
setClosedType("finding"); | ||
_close(); | ||
} | ||
const MatchingModal: React.FC<MatchingModalProps> = ({ isOpen, close: _close }) => { | ||
const matchingState = useMatching(); | ||
const [closedType, setClosedType] = useState<"finding" | "cancelled" | "joined">("finding"); | ||
const isClosable = ["timeout", "closed"].includes(matchingState.state) && closedType != "joined"; | ||
const router = useRouter(); | ||
const { totalSeconds, pause: pauseTimer, restart: restartTimer } = useTimer({ | ||
expiryTimestamp: new Date(Date.now() + MATCH_TIMEOUT * 1000), | ||
autoStart: false, | ||
onExpire() { | ||
if (matchingState.state === "matching") { | ||
matchingState.timeout(); | ||
return; | ||
} | ||
if (matchingState.state === "found") { | ||
join(); | ||
return; | ||
} | ||
console.warn(`matching is in ${matchingState.state}`) | ||
}, | ||
}); | ||
const passed = MATCH_TIMEOUT - totalSeconds; | ||
|
||
const renderModalContent = () => { | ||
switch (matchingState.state) { | ||
case "closed": | ||
switch (closedType) { | ||
case "finding": | ||
return <FindMatchContent beginMatch={matchingState.start} />; | ||
case "cancelled": | ||
return ( | ||
<MatchCancelledContent | ||
reselect={() => { | ||
setClosedType("finding"); | ||
}} | ||
retry={() => {}} | ||
canceledIn={timeoutAfter} | ||
/> | ||
); | ||
case "joined": | ||
return ( | ||
<JoinedMatchContent | ||
cancel={() => { | ||
setClosedType("cancelled"); | ||
}} | ||
name1={matchingState.info?.user || ""} | ||
name2={matchingState.info?.matchedUser || ""} | ||
/> | ||
); | ||
function close() { | ||
// clean up matching and closedType State | ||
if (matchingState.state === "timeout") { | ||
matchingState.ok(); | ||
} | ||
case "matching": | ||
return ( | ||
<MatchingInProgressContent | ||
cancelMatch={(timeoutAfter: number) => { | ||
setClosedType("cancelled"); | ||
setTimeoutAfter(timeoutAfter); | ||
matchingState.cancel(); | ||
}} | ||
timeout={(timeoutAfter: number) => { | ||
matchingState.timeout(); | ||
setTimeoutAfter(timeoutAfter); | ||
}} | ||
/> | ||
); | ||
case "cancelling": | ||
return ( | ||
<MatchingInProgressContent | ||
cancelMatch={() => {}} | ||
timeout={() => {}} | ||
/> | ||
); | ||
case "starting": | ||
return <FindMatchContent beginMatch={() => {}} />; | ||
case "found": | ||
return ( | ||
<MatchFoundContent | ||
cancel={() => { | ||
matchingState.ok(); | ||
setClosedType("cancelled"); | ||
}} | ||
join={() => { | ||
matchingState.ok(); | ||
setClosedType("joined"); | ||
localStorage.setItem("user", matchingState.info.user); | ||
localStorage.setItem( | ||
"matchedUser", | ||
matchingState.info.matchedUser | ||
); | ||
localStorage.setItem("collabId", matchingState.info.matchId); | ||
localStorage.setItem( | ||
"questionDocRefId", | ||
matchingState.info.questionDocRefId | ||
); | ||
localStorage.setItem( | ||
"matchedTopics", | ||
matchingState.info.matchedTopics.join(",") | ||
); | ||
setClosedType("finding"); | ||
_close(); | ||
} | ||
|
||
// Redirect to collaboration page | ||
router.push(`/collaboration/${matchingState.info.matchId}`); | ||
}} | ||
name1={matchingState.info.user} | ||
name2={matchingState.info.matchedUser} | ||
/> | ||
const startMatch = matchingState.state == "closed" || matchingState.state == "timeout" ? async (params: MatchParams): Promise<void> => { | ||
const user = await ValidateUser(); | ||
|
||
restartTimer( | ||
new Date(Date.now() + MATCH_TIMEOUT * 1000), | ||
); | ||
case "timeout": | ||
return ( | ||
<MatchNotFoundContent | ||
reselect={matchingState.ok} | ||
retry={() => {}} | ||
timedOutIn={10} | ||
/> | ||
|
||
matchingState.start({ | ||
email: user.data.email, | ||
username: user.data.username, | ||
type: "match_request", | ||
...params | ||
}); | ||
} : undefined; | ||
|
||
const join = matchingState.state == "found" ? (() => { | ||
matchingState.ok(); | ||
setClosedType("joined"); | ||
localStorage.setItem("user", matchingState.info.user); | ||
localStorage.setItem( | ||
"matchedUser", | ||
matchingState.info.matchedUser | ||
); | ||
default: | ||
throw new Error("Invalid matching state."); | ||
} | ||
}; | ||
localStorage.setItem("collabId", matchingState.info.matchId); | ||
localStorage.setItem("questionDocRefId", matchingState.info.questionDocRefId); | ||
localStorage.setItem("matchedTopics", matchingState.info.matchedTopics.join(",")); | ||
|
||
// Redirect to collaboration page | ||
router.push(`/collaboration/${matchingState.info.matchId}`); | ||
}) : () => { throw new Error("join called when not found"); } | ||
|
||
useEffect(() => { | ||
if (matchingState.state === "cancelling" || matchingState.state === "timeout") { | ||
pauseTimer(); | ||
return; | ||
} | ||
if (matchingState.state === "found") { | ||
restartTimer( | ||
new Date(Date.now() + JOIN_TIMEOUT * 1000), | ||
) | ||
} | ||
}, [matchingState]) | ||
|
||
return ( | ||
<Modal | ||
open={isOpen} | ||
onCancel={close} | ||
footer={null} | ||
closable={false} | ||
maskClosable={false} | ||
className="modal" | ||
> | ||
{renderModalContent()} | ||
{isClosable && ( | ||
<button className="close-button" onClick={close}> | ||
Close | ||
</button> | ||
)} | ||
</Modal> | ||
); | ||
}; | ||
const renderModalContent = () => { | ||
switch (matchingState.state) { | ||
case 'closed': | ||
switch (closedType) { | ||
case "finding": | ||
return <FindMatchContent beginMatch={params => {}}/>; | ||
case "cancelled": | ||
return <MatchCancelledContent | ||
reselect={() => { | ||
setClosedType("finding"); | ||
}} | ||
canceledIn={passed} | ||
/>; | ||
case "joined": | ||
return <JoinedMatchContent | ||
cancel={() => { | ||
setClosedType("cancelled"); | ||
}} | ||
name1={matchingState.info?.user ?? ""} | ||
name2={matchingState.info?.matchedUser ?? ""} | ||
/>; | ||
} | ||
case 'matching': | ||
return <MatchingInProgressContent | ||
cancelMatch={() => { | ||
setClosedType("cancelled"); | ||
matchingState.cancel(); | ||
pauseTimer(); | ||
}} | ||
timePassed={passed} | ||
/>; | ||
case 'cancelling': | ||
return <MatchingInProgressContent cancelMatch={() => {}} timePassed={passed}/>; | ||
case 'starting': | ||
return <FindMatchContent beginMatch={() => {}}/> | ||
case 'found': | ||
return <MatchFoundContent | ||
cancel={() => { | ||
matchingState.ok(); | ||
setClosedType("cancelled"); | ||
}} | ||
join={join} | ||
name1={matchingState.info.user} | ||
name2={matchingState.info.matchedUser} | ||
joiningIn={totalSeconds} | ||
/> | ||
case 'timeout': | ||
return <MatchNotFoundContent reselect={matchingState.ok} timedOutIn={passed}/>; | ||
default: | ||
throw new Error('Invalid matching state.'); | ||
} | ||
} | ||
|
||
return ( | ||
<Modal open={isOpen} | ||
onCancel={close} | ||
footer={null} | ||
closable={false} | ||
maskClosable={false} | ||
className="modal" | ||
> | ||
<Form<MatchParams> | ||
name="match" | ||
onFinish={startMatch} | ||
initialValues={{ | ||
topics: [], | ||
difficulties: [], | ||
}}> | ||
{renderModalContent()} | ||
</Form> | ||
{isClosable && ( | ||
<button className="close-button" onClick={close}>Close</button> | ||
)} | ||
</Modal> | ||
) | ||
} | ||
|
||
export default MatchingModal; |
Oops, something went wrong.