-
Notifications
You must be signed in to change notification settings - Fork 0
[OA][Fullstack] - OA Websockets #278
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| import { TokenSchema } from '@/lib/schemas/token.schema'; | ||
| import { handleError } from '@/lib/utils/errors.utils'; | ||
| import { generateToken } from '@/lib/utils/token.utils'; | ||
| import { type NextRequest } from 'next/server'; | ||
|
|
||
| export async function POST(request: NextRequest) { | ||
| try { | ||
| // TODO: add route security | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Have we made a ticket for this?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not yet. Will be written, but not urgent for showcase |
||
| const body = await request.json(); | ||
| const parsed = TokenSchema.parse(body); | ||
| const token = await generateToken(parsed.email); | ||
|
|
||
| return Response.json({ data: token }, { status: 201 }); | ||
| } catch (err) { | ||
| return handleError(err); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| /** | ||
| * POST /api/token | ||
| */ | ||
| export async function createToken(email: string): Promise<string> { | ||
| const res = await fetch(`/api/token`, { | ||
| method: 'POST', | ||
| headers: { | ||
| 'Content-Type': 'application/json', | ||
| }, | ||
| body: JSON.stringify({ email }), | ||
| }); | ||
|
|
||
| const json = await res.json(); | ||
|
|
||
| if (!res.ok) { | ||
| throw new Error(json.message); | ||
| } | ||
|
|
||
| return json.data; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| import { Skeleton } from '@/lib/components/ui/Skeleton'; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Something to note (I saw this post abt this package that does exact skeleton according to the content - not really needed here but could be something so that skeleton is just a wrapper and we don't have to do this in the future) not prio tho |
||
| import { | ||
| ResizablePanelGroup, | ||
| ResizablePanel, | ||
| ResizableHandle, | ||
| } from '@/lib/components/ui/Resizable'; | ||
| import { useMemo } from 'react'; | ||
|
|
||
| export default function AssessmentSkeleton() { | ||
| // generating random line widths for the skelton code lines | ||
| const skeletonCodeLineWidths = useMemo( | ||
| () => Array.from({ length: 16 }, () => `${Math.random() * 40 + 30}%`), | ||
| [] | ||
| ); | ||
|
|
||
| return ( | ||
| <ResizablePanelGroup direction="horizontal" className="h-full"> | ||
| <ResizablePanel defaultSize={35} minSize={20}> | ||
| <div className="flex h-full flex-col"> | ||
| <div className="box-content shrink-0 px-5 pt-4 pb-2"> | ||
| <Skeleton className="h-9 w-3/4 rounded-md" /> | ||
| </div> | ||
| <div className="flex-1 space-y-3 overflow-hidden px-5 pt-1 pb-4"> | ||
| <Skeleton className="h-4 w-full rounded" /> | ||
| <Skeleton className="h-4 w-5/6 rounded" /> | ||
| <Skeleton className="h-4 w-full rounded" /> | ||
| <Skeleton className="h-4 w-4/6 rounded" /> | ||
| <Skeleton className="h-4 w-full rounded" /> | ||
| <Skeleton className="h-4 w-3/4 rounded" /> | ||
| <div className="space-y-3 pt-2"> | ||
| <Skeleton className="h-4 w-full rounded" /> | ||
| <Skeleton className="h-4 w-5/6 rounded" /> | ||
| <Skeleton className="h-4 w-full rounded" /> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </ResizablePanel> | ||
|
|
||
| <ResizableHandle className="bg-sarge-gray-200 w-px" /> | ||
|
|
||
| <ResizablePanel defaultSize={65} minSize={40}> | ||
| <div className="flex h-full flex-col overflow-hidden bg-[#3a414f]"> | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. are we just doing this hex bc we have nothing in the design system? (idt we have skeleton so would be fine if not)
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This hex is the same color as our monacode text editor theme
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think eventually we'll make a design token for this then I know olivia has new designs for the editor |
||
| <div className="min-h-0 flex-1 space-y-2 px-4 pt-4"> | ||
| {skeletonCodeLineWidths.map((w, i) => ( | ||
| <Skeleton key={i} className="h-4 rounded" style={{ width: w }} /> | ||
| ))} | ||
| </div> | ||
| <div className="border-sarge-gray-200 flex items-center justify-between border-t bg-white px-4 py-3"> | ||
| <div className="flex gap-2"> | ||
| <Skeleton className="h-8 w-24 rounded-md" /> | ||
| </div> | ||
| <div className="flex gap-2"> | ||
| <Skeleton className="h-8 w-24 rounded-md" /> | ||
| <Skeleton className="h-8 w-24 rounded-md" /> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </ResizablePanel> | ||
| </ResizablePanelGroup> | ||
| ); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,7 @@ import { ChevronDown, ChevronUp, CircleCheck, CircleX, Play, ChevronRight } from | |
| import TestCaseCard from '@/lib/components/core/TestCaseCard'; | ||
| import type { TestCaseDTO } from '@/lib/schemas/task-template.schema'; | ||
| import type { TestCaseResult } from '@/lib/types/candidate-assessment.types'; | ||
| import { Button } from '@/lib/components/ui/Button'; | ||
|
|
||
| type AssessmentTestCasesPanelProps = { | ||
| testCases: TestCaseDTO[]; | ||
|
|
@@ -82,8 +83,8 @@ export default function AssessmentTestCasesPanel({ | |
| <div className="flex h-15 flex-shrink-0 items-center justify-between px-3"> | ||
| <div className="flex items-center gap-4"> | ||
| <div className="flex items-center gap-1"> | ||
| <button | ||
| type="button" | ||
| <Button | ||
| variant="icon" | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah this is better |
||
| onClick={() => setIsOpen((v) => !v)} | ||
| className="text-sarge-gray-700" | ||
| > | ||
|
|
@@ -92,7 +93,7 @@ export default function AssessmentTestCasesPanel({ | |
| ) : ( | ||
| <ChevronUp className="size-5" /> | ||
| )} | ||
| </button> | ||
| </Button> | ||
| <span className="text-sarge-gray-700 text-sm font-medium">Test Cases</span> | ||
| </div> | ||
| {hasResults && ( | ||
|
|
@@ -113,22 +114,22 @@ export default function AssessmentTestCasesPanel({ | |
| )} | ||
| </div> | ||
| <div className="flex items-center gap-2"> | ||
| <button | ||
| type="button" | ||
| <Button | ||
| variant="secondary" | ||
| onClick={onRunTests} | ||
| className="bg-sarge-gray-50 border-sarge-primary-500 text-sarge-primary-500 flex h-9 items-center gap-2 rounded-lg border px-4 text-sm font-medium" | ||
| className="flex h-9 items-center gap-2 rounded-lg border px-4 text-sm font-medium" | ||
| > | ||
| <Play className="size-4" /> | ||
| Run Tests | ||
| </button> | ||
| <button | ||
| type="button" | ||
| </Button> | ||
| <Button | ||
| variant="primary" | ||
| onClick={onSubmit} | ||
| className="bg-sarge-primary-500 text-primary-foreground flex h-9 items-center gap-2 rounded-lg px-4 text-sm font-medium" | ||
| className="text-primary-foreground flex h-9 items-center gap-2 rounded-lg px-4 text-sm font-medium" | ||
| > | ||
| Submit | ||
| <ChevronRight className="size-4" /> | ||
| </button> | ||
| </Button> | ||
| </div> | ||
| </div> | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| import { Dialog, DialogContent, DialogTitle } from '@/lib/components/ui/Modal'; | ||
| import { VisuallyHidden } from '@radix-ui/react-visually-hidden'; | ||
| import { Button } from '@/lib/components/ui/Button'; | ||
|
|
||
| export type LostConnectionModalProps = { | ||
| open: boolean; | ||
| onOpenChange: (open: boolean) => void; | ||
| }; | ||
|
|
||
| export function LostConnectionModal({ open, onOpenChange }: LostConnectionModalProps) { | ||
| return ( | ||
| <Dialog open={open} onOpenChange={onOpenChange}> | ||
| <DialogContent className="h-[234px] w-[381px] gap-4" showCloseButton={true}> | ||
| <VisuallyHidden> | ||
| <DialogTitle>Network Disconnected</DialogTitle> | ||
| </VisuallyHidden> | ||
| <div className="flex flex-col items-center gap-6 text-center"> | ||
| <p className="text-sarge-gray-800 mt-2 text-base leading-tight font-medium tracking-wide"> | ||
| You seem to be having issues with your connection. | ||
| </p> | ||
| <p> | ||
| If you disconnect again during this exam, your current progress will be | ||
| auto-submitted. | ||
| </p> | ||
| <Button className="px-4 py-2">I understand</Button> | ||
| </div> | ||
| </DialogContent> | ||
| </Dialog> | ||
| ); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
when you say "recovery," do you mean a client disconnects and then reconnects after a brief delay?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this is to tee us nicely for handling us having a seperate countdown for clients who have disconnected, and give them a chance to reconnect.