diff --git a/frontend/components/account/Profile.tsx b/frontend/components/account/Profile.tsx index b17c4c1f17..ce3574deac 100644 --- a/frontend/components/account/Profile.tsx +++ b/frontend/components/account/Profile.tsx @@ -107,7 +107,7 @@ function Profile() { dialogOpen={isDialogOpen} onDialogOpenChange={manageDialog} // Allow toggling the dialog text="Update Profile" - className="w-fit bg-btn text-white text-sm py-2 px-4 rounded-md hover:bg-purple-700" + className="w-fit bg-btn text-white text-sm py-2 px-4 rounded-md" type="button" variant="primary" description="Are you sure you want to update your profile?" diff --git a/frontend/components/account/Settings.tsx b/frontend/components/account/Settings.tsx index c327bd4605..5113800068 100644 --- a/frontend/components/account/Settings.tsx +++ b/frontend/components/account/Settings.tsx @@ -120,7 +120,7 @@ function Setting() { dialogOpen={isUpdateDialogOpen} onDialogOpenChange={manageUpdateDialog} text="Update Settings" - className="w-fit bg-btn text-white text-sm py-2 px-4 rounded-md hover:bg-theme-700" + className="w-fit bg-btn text-white text-sm py-2 px-4 rounded-md" type="button" variant="primary" description="Are you sure you want to update your settings?" diff --git a/frontend/components/customs/custom-dialog.tsx b/frontend/components/customs/custom-dialog.tsx index 047558b707..be81151dfd 100644 --- a/frontend/components/customs/custom-dialog.tsx +++ b/frontend/components/customs/custom-dialog.tsx @@ -56,7 +56,7 @@ function CustomDialogWithButton(props: CustomDialogProps) {
- Warning + {props.text || 'Warning'}
diff --git a/frontend/components/customs/datatable.tsx b/frontend/components/customs/datatable.tsx index c7dec5ab39..8c4d3a7c5e 100644 --- a/frontend/components/customs/datatable.tsx +++ b/frontend/components/customs/datatable.tsx @@ -65,7 +65,7 @@ export default function Datatable({ - {hideIdx ? null : 'No.'} + {hideIdx ? null : 'No.'} {columns.map((elem) => { if (elem.isHidden) { return null @@ -129,21 +129,22 @@ export default function Datatable({ )} - {col.customAction && col.customAction.formatter ? ( - col.customAction.formatter(elem, router) - ) : ( - - )} + {col.customAction && + (col.customAction.formatter ? ( + col.customAction.formatter(elem, router) + ) : ( + + ))} ) } diff --git a/frontend/components/dashboard/new-session.tsx b/frontend/components/dashboard/new-session.tsx index 15b8b6f580..890ce3b82c 100644 --- a/frontend/components/dashboard/new-session.tsx +++ b/frontend/components/dashboard/new-session.tsx @@ -14,6 +14,7 @@ import { addUserToMatchmaking } from '../../services/matching-service-api' import CustomModal from '../customs/custom-modal' import Loading from '../customs/loading' import { capitalizeFirstLowerRest } from '@/util/string-modification' +import { encodeStr } from '@/util/encryption' export const NewSession = () => { const router = useRouter() @@ -109,7 +110,8 @@ export const NewSession = () => { switch (newMessage.type) { case WebSocketMessageType.SUCCESS: updateMatchmakingStatus(MatchingStatus.MATCH_FOUND, newMessage.matchId) - router.push(`/code/${newMessage.matchId}`) + const encodedId = encodeStr(newMessage.matchId) + router.push(`/code/${encodedId}`) break case WebSocketMessageType.FAILURE: socketRef.current?.close() @@ -204,7 +206,7 @@ export const NewSession = () => { - @@ -267,7 +269,7 @@ export const NewSession = () => { diff --git a/frontend/components/dashboard/resume-session.tsx b/frontend/components/dashboard/resume-session.tsx index 4f6ec06293..abc6ceb7ed 100644 --- a/frontend/components/dashboard/resume-session.tsx +++ b/frontend/components/dashboard/resume-session.tsx @@ -3,6 +3,8 @@ import { Button } from '../ui/button' import { IMatch } from '@repo/user-types' import { convertSortedComplexityToComplexity } from '@repo/question-types' import { capitalizeFirstLowerRest } from '@/util/string-modification' +import { encodeStr } from '@/util/encryption' +import { toast } from 'sonner' interface IResumeSessionProps { match: IMatch @@ -18,8 +20,11 @@ export default function ResumeSession({ match, isOngoing }: IResumeSessionProps) try { const ongoing = await isOngoing() if (!ongoing) return - router.push(`/code/${match.id}`) - } catch (error) {} + const encodedId = encodeStr(match.id) + router.push(`/code/${encodedId}`) + } catch (error) { + toast.error('Unable to resume session due to a server error') + } } return ( diff --git a/frontend/components/ui/button.tsx b/frontend/components/ui/button.tsx index 8bf8d0f16a..12073ffa15 100644 --- a/frontend/components/ui/button.tsx +++ b/frontend/components/ui/button.tsx @@ -5,7 +5,7 @@ import { cva, type VariantProps } from 'class-variance-authority' import { cn } from '@/lib/utils' const buttonVariants = cva( - 'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50', + 'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-gray-300 disabled:pointer-events-none disabled:opacity-50', { variants: { variant: { @@ -16,7 +16,7 @@ const buttonVariants = cva( link: 'text-primary underline-offset-4 hover:underline', icon: 'bg-transparent border-[1px] rounded-xl hover:bg-btn-secondaryHover', iconNoBorder: 'hover:bg-btn-hover', - primary: 'bg-theme-600 hover:bg-theme-700 text-primary-foreground', + primary: 'bg-theme-600 hover:bg-theme-700 text-primary-foreground focus-visible:ring-gray-500', activeTab: 'text-foreground bg-transparent hover:bg-btn-hover rounded-b-none border-b-2 border-theme-600', ghostTab: 'text-foreground bg-transparent hover:bg-btn-hover rounded-b-none', diff --git a/frontend/components/ui/dialog.tsx b/frontend/components/ui/dialog.tsx index bd27c8a468..c20850997a 100644 --- a/frontend/components/ui/dialog.tsx +++ b/frontend/components/ui/dialog.tsx @@ -21,7 +21,7 @@ const DialogOverlay = React.forwardRef< { return cat.map((c) => capitalizeFirstLowerRest(c)).join(', ') @@ -40,7 +41,7 @@ const formatQuestionCategories = (cat: Category[]) => { export default function Code() { const router = useRouter() const [isChatOpen, setIsChatOpen] = useState(true) - const { id } = router.query + const [id, setId] = useState(router.query.id as string) const editorRef = useRef<{ getText: () => string } | null>(null) const [editorLanguage, setEditorLanguage] = useState(LanguageMode.Javascript) const testTabs = ['Testcases', 'Test Results'] @@ -81,8 +82,10 @@ export default function Code() { const { data: sessionData } = useSession() useEffect(() => { - const matchId = router.query.id as string + const encodedId = router.query.id as string + const matchId = decodeStr(encodedId) retrieveMatchDetails(matchId) + setId(matchId) }, [router.query.id, retry]) useEffect(() => { @@ -136,6 +139,7 @@ export default function Code() { socketRef.current.on('disconnect', () => { if (!isViewOnly) { router.push('/') + toast.info('The session has ended') } }) @@ -201,7 +205,7 @@ export default function Code() { function handleEndSessionConfirmation() { if (socketRef.current) { - socketRef.current?.emit('end-session') + socketRef.current.emit('end-session') router.push('/') } setIsDialogOpen(false) diff --git a/frontend/pages/questions/index.tsx b/frontend/pages/questions/index.tsx index 2b556e3f33..06f79b1ada 100644 --- a/frontend/pages/questions/index.tsx +++ b/frontend/pages/questions/index.tsx @@ -156,10 +156,8 @@ export default function Questions() { } else if (modificationType === Modification.DELETE) { if (!questionData.id) return try { - const res = await deleteQuestionById(questionData.id) - if (res) { - toast.success('Question deleted successfully') - } + await deleteQuestionById(questionData.id) + toast.success('Question deleted successfully') } catch (error) { toast.error('Failed to delete question' + error) return diff --git a/frontend/pages/questions/props.tsx b/frontend/pages/questions/props.tsx index 2e034d04e6..517e3c328a 100644 --- a/frontend/pages/questions/props.tsx +++ b/frontend/pages/questions/props.tsx @@ -15,12 +15,10 @@ const getColumns = (isAdmin: boolean): IDatatableColumn[] => { }, { key: 'title', - width: '30%', offAutoCapitalize: true, }, { key: 'categories', - width: '40%', formatter: (values) => { const c = values.map((v: string) => ( { }, { key: 'complexity', - width: '10%', isSortable: true, formatter: (value) => { return diff --git a/frontend/pages/sessions/columns.tsx b/frontend/pages/sessions/columns.tsx index 1ac1c8172a..e4fe12f99b 100644 --- a/frontend/pages/sessions/columns.tsx +++ b/frontend/pages/sessions/columns.tsx @@ -3,6 +3,7 @@ import { DifficultyLabel } from '@/components/customs/difficulty-label' import { Button } from '@/components/ui/button' import CustomLabel from '@/components/ui/label' import { IDatatableColumn, IRowData } from '@/types' +import { encodeStr } from '@/util/encryption' import { capitalizeFirstLowerRest } from '@/util/string-modification' import { EyeIcon } from 'lucide-react' import { NextRouter } from 'next/router' @@ -77,7 +78,8 @@ export const columns: IDatatableColumn[] = [ variant="iconNoBorder" size="icon" onClick={() => { - router.push(`/code/${elem._id}`) + const encoded = encodeStr(elem._id) + router.push(`/code/${encoded}`) }} > {elem.isCompleted ? : } diff --git a/frontend/pages/sessions/index.tsx b/frontend/pages/sessions/index.tsx index 913bb4f212..7778b879eb 100644 --- a/frontend/pages/sessions/index.tsx +++ b/frontend/pages/sessions/index.tsx @@ -11,6 +11,7 @@ import { Button } from '@/components/ui/button' import ConfirmDialog, { ConfirmDialogProps } from '@/components/customs/confirm-dialog' import { getOngoingMatch } from '@/services/matching-service-api' import { useRouter } from 'next/router' +import { encodeStr } from '@/util/encryption' export default function Sessions() { const router = useRouter() @@ -111,7 +112,8 @@ export default function Sessions() { if (!session?.user?.id) return const matchData = await getOngoingMatch(session.user.id) if (matchData) { - router.push(`/code/${matchData.id}`) + const encodedId = encodeStr(matchData.id) + router.push(`/code/${encodedId}`) } else { setDialog((prev) => ({ ...prev, dialogData: { ...prev.dialogData, isOpen: true } })) } diff --git a/frontend/util/encryption.ts b/frontend/util/encryption.ts new file mode 100644 index 0000000000..58a66b278b --- /dev/null +++ b/frontend/util/encryption.ts @@ -0,0 +1,8 @@ +export const encodeStr = (str: string) => { + return btoa(str) +} + +export const decodeStr = (encoded: string) => { + if (!encoded) return '' + return atob(encoded) +}