-
Notifications
You must be signed in to change notification settings - Fork 1
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 #216 from CS3219-AY2425S1/fix-refresh-matchmaking
fix: allow user to instantly queue after refreshing while in queue
- Loading branch information
Showing
19 changed files
with
513 additions
and
275 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
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 |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import ConfirmDialog from '../customs/confirm-dialog' | ||
import UserAvatar from '../customs/custom-avatar' | ||
import { LongTextSkeleton } from '../customs/custom-loader' | ||
import { Button } from '../ui/button' | ||
import { EndIcon, PlayIcon } from '@/assets/icons' | ||
import { Cross1Icon } from '@radix-ui/react-icons' | ||
|
||
export const CodeActions = ({ | ||
isLoading, | ||
isViewOnly, | ||
handleRunTests, | ||
isCodeRunning, | ||
isOtherUserOnline, | ||
handleEndSession, | ||
username, | ||
isDialogOpen, | ||
setIsDialogOpen, | ||
handleEndSessionConfirmation, | ||
}: { | ||
isLoading: boolean | ||
isViewOnly: boolean | ||
handleEndSession: () => void | ||
handleRunTests: () => void | ||
isCodeRunning: boolean | ||
isOtherUserOnline: boolean | ||
username: string | undefined | ||
isDialogOpen: boolean | ||
setIsDialogOpen: (isOpen: boolean) => void | ||
handleEndSessionConfirmation: () => void | ||
}) => { | ||
const renderCloseButton = () => { | ||
return isViewOnly ? ( | ||
<> | ||
<Cross1Icon className="mr-2" /> | ||
Close | ||
</> | ||
) : ( | ||
<> | ||
<EndIcon fill="white" className="mr-2" /> | ||
End Session | ||
</> | ||
) | ||
} | ||
|
||
if (isLoading) { | ||
return <LongTextSkeleton /> | ||
} | ||
|
||
return ( | ||
<div id="control-panel" className="flex justify-between"> | ||
<div className="flex gap-3"> | ||
{!isViewOnly && ( | ||
<Button variant={'primary'} onClick={handleRunTests} disabled={isCodeRunning}> | ||
{isCodeRunning ? ( | ||
'Executing...' | ||
) : ( | ||
<> | ||
{' '} | ||
<PlayIcon fill="white" height="18px" width="18px" className="mr-2" /> | ||
Run test | ||
</> | ||
)} | ||
</Button> | ||
)} | ||
</div> | ||
<div className="flex flex-row items-center"> | ||
{!isViewOnly && <UserAvatar username={username ?? ''} isOnline={isOtherUserOnline} />} | ||
<Button className="bg-red hover:bg-red-dark" onClick={handleEndSession}> | ||
{renderCloseButton()} | ||
</Button> | ||
<ConfirmDialog | ||
showCancelButton | ||
dialogData={{ | ||
title: 'Warning!', | ||
content: | ||
'Are you sure you want to end the session? This will permanently end the session for both you and the other participant.', | ||
isOpen: isDialogOpen, | ||
}} | ||
closeHandler={() => setIsDialogOpen(false)} | ||
confirmHandler={handleEndSessionConfirmation} | ||
/> | ||
</div> | ||
</div> | ||
) | ||
} |
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 |
---|---|---|
@@ -0,0 +1,119 @@ | ||
'use client' | ||
|
||
import { FC, useEffect, useRef, useState } from 'react' | ||
import { useSession } from 'next-auth/react' | ||
import { ChatModel } from '@repo/collaboration-types' | ||
import { Button } from '@/components/ui/button' | ||
import Image from 'next/image' | ||
import { ScrollArea } from '@/components/ui/scroll-area' | ||
|
||
const formatTimestamp = (timestamp: string) => { | ||
const date = new Date(timestamp) | ||
return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', hour12: true }).toUpperCase() | ||
} | ||
|
||
const Chat: FC<{ | ||
chatData: ChatModel[] | ||
isViewOnly: boolean | ||
handleSendMessage: (msg: string) => void | ||
}> = ({ chatData, isViewOnly, handleSendMessage }) => { | ||
const chatEndRef = useRef<HTMLDivElement | null>(null) | ||
const { data: session } = useSession() | ||
const [value, setValue] = useState('') | ||
const [isChatOpen, setIsChatOpen] = useState(true) | ||
|
||
const getChatBubbleFormat = (currUser: string, type: 'label' | 'text') => { | ||
let format = '' | ||
if (currUser === session?.user.username) { | ||
format = 'items-end ml-5' | ||
if (type === 'text') { | ||
format += ' bg-theme-600 rounded-xl text-white' | ||
} | ||
} else { | ||
format = 'items-start text-left mr-5' | ||
if (type === 'text') { | ||
format += ' bg-slate-100 rounded-xl p-2 text-slate-900' | ||
} | ||
} | ||
return format | ||
} | ||
|
||
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => { | ||
if (e.key === 'Enter' && e.currentTarget.value.trim() !== '') { | ||
handleSendMessage(e.currentTarget.value) | ||
setValue('') | ||
e.currentTarget.value = '' | ||
} | ||
} | ||
|
||
const toggleChat = () => { | ||
setIsChatOpen(!isChatOpen) | ||
} | ||
|
||
useEffect(() => { | ||
if (chatEndRef.current) { | ||
chatEndRef.current.scrollIntoView({ behavior: 'smooth' }) | ||
} | ||
}, [chatData]) | ||
|
||
return ( | ||
<> | ||
<div className="border-2 rounded-lg border-slate-100 mt-4 max-h-twoFifthScreen flex flex-col"> | ||
<div className="flex items-center justify-between border-b-[1px] pl-3"> | ||
<h3 className="text-lg font-medium">Chat</h3> | ||
<Button variant="iconNoBorder" size="icon" onClick={toggleChat}> | ||
<Image | ||
src={`/icons/${isChatOpen ? 'minimise' : 'maximise'}.svg`} | ||
alt="Minimise chat" | ||
width={20} | ||
height={20} | ||
/> | ||
</Button> | ||
</div> | ||
|
||
{isChatOpen && ( | ||
<ScrollArea className="overflow-y-auto p-3"> | ||
{!!chatData?.length && | ||
Object.values(chatData).map((chat, index) => ( | ||
<div | ||
key={index} | ||
className={`flex flex-col gap-1 mb-5 ${getChatBubbleFormat(chat.senderId, 'label')}`} | ||
> | ||
<div className="flex items-center gap-2"> | ||
<h4 className="text-xs font-medium">{chat.senderId}</h4> | ||
<span className="text-xs text-slate-400"> | ||
{formatTimestamp(chat.createdAt.toString())} | ||
</span> | ||
</div> | ||
<div | ||
className={`text-sm py-2 px-3 text-balance break-words w-full ${getChatBubbleFormat(chat.senderId, 'text')}`} | ||
> | ||
{chat.message} | ||
</div> | ||
</div> | ||
))} | ||
{(!chatData || !chatData?.length) && ( | ||
<p className="w-full text-center text-gray-400 text-sm my-1">No chat history</p> | ||
)} | ||
<div ref={chatEndRef}></div> | ||
{!isViewOnly && ( | ||
<div className="m-3 mt-0 px-3 py-1 border-[1px] rounded-xl text-sm"> | ||
<input | ||
type="text" | ||
className="w-full bg-transparent border-none focus:outline-none" | ||
placeholder="Send a message..." | ||
onKeyDown={handleKeyDown} | ||
value={value} | ||
onChange={(e) => setValue(e.target.value)} | ||
readOnly={isViewOnly} | ||
/> | ||
</div> | ||
)} | ||
</ScrollArea> | ||
)} | ||
</div> | ||
</> | ||
) | ||
} | ||
|
||
export default Chat |
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
File renamed without changes.
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 |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import { LargeTextSkeleton, TextSkeleton } from '@/components/customs/custom-loader' | ||
import { DifficultyLabel } from '@/components/customs/difficulty-label' | ||
import CustomLabel from '@/components/ui/label' | ||
import { ScrollArea } from '@/components/ui/scroll-area' | ||
import { capitalizeFirstLowerRest } from '@/util/string-modification' | ||
import { convertSortedComplexityToComplexity } from '@repo/question-types' | ||
import { Category, Complexity } from '@repo/user-types' | ||
|
||
const formatQuestionCategories = (cat: Category[]) => { | ||
return cat.map((c) => capitalizeFirstLowerRest(c)).join(', ') | ||
} | ||
|
||
export const CodeQuestion = ({ | ||
loading, | ||
title, | ||
complexity, | ||
categories, | ||
description, | ||
}: { | ||
loading: boolean | ||
title: string | ||
complexity: Complexity | ||
categories: Category[] | ||
description: string | ||
}) => { | ||
if (loading) { | ||
return ( | ||
<div id="question-data" className="flex-grow border-2 rounded-lg border-slate-100 mt-2 py-2 px-3"> | ||
<h3 className="text-lg font-medium"> | ||
<TextSkeleton /> | ||
</h3> | ||
<div className="flex gap-3 my-2 text-sm"> | ||
<TextSkeleton /> | ||
<TextSkeleton /> | ||
</div> | ||
<div className="mt-6"> | ||
<LargeTextSkeleton /> | ||
</div> | ||
</div> | ||
) | ||
} | ||
return ( | ||
<ScrollArea | ||
id="question-data" | ||
className="flex-grow border-2 rounded-lg border-slate-100 mt-2 py-2 px-3 overflow-y-auto" | ||
> | ||
<h3 className="text-lg font-medium">{title}</h3> | ||
<div className="flex gap-3 my-2 text-sm"> | ||
<DifficultyLabel complexity={convertSortedComplexityToComplexity(complexity)} /> | ||
<CustomLabel | ||
title={formatQuestionCategories(categories ?? [])} | ||
textColor="text-theme" | ||
bgColor="bg-theme-100" | ||
/> | ||
</div> | ||
<div className="mt-6 whitespace-pre-wrap">{description}</div> | ||
</ScrollArea> | ||
) | ||
} |
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
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
Oops, something went wrong.