-
Notifications
You must be signed in to change notification settings - Fork 1
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
✨ Q/A Session Interface #25
base: master
Are you sure you want to change the base?
Changes from 14 commits
f66b8e9
82dccfb
e41cc88
61a84d1
ec2bfb5
738ef59
8a90d09
39a2067
8d14fe5
c3696c2
6e7ab87
c101f6a
02d99be
156b216
76afcd6
f9149a1
9dd0f58
c20bf71
289f70d
84601a4
982d362
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,3 +27,5 @@ h4 { | |
.form-input-wrapper { | ||
@apply grid grid-cols-1 gap-2 my-6; | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
'use client' | ||
import PageContent from "@/components/layouts/page-content" | ||
import ViewContainer from "@/components/layouts/view-container" | ||
import { Button } from "@/components/ui/button" | ||
import { QnaQuestionsList } from "@/components/sections/qna-questions-list" | ||
import { fetchQnaQuestions } from "@/middleware/qna/qna-questions" | ||
import { useEffect, useState } from "react" | ||
import { Textarea } from "@/components/ui/textarea" | ||
import { Check } from 'lucide-react'; | ||
import { Timer } from "@/components/ui/qna-timer" | ||
import { QnaQuesCard } from "@/components/ui/qna-ques-card"; | ||
import { BoxCard } from "@/components/layouts/box-card" | ||
import { cn } from "@/lib/utils"; | ||
|
||
|
||
const QNASession: React.FunctionComponent = () => { | ||
|
||
const [time, setTime] = useState("12:34") | ||
const [progressVal, setProgressVal] = useState(0); | ||
const qData = fetchQnaQuestions(); | ||
const [qNum, setQNum] = useState(0); | ||
const [storeAns, setStoreAns] = useState(["", "", "", "", "", "", "", "", "", "",]) | ||
const handleAnsChange = (e: any) => { | ||
setStoreAns([ | ||
storeAns[qNum] = e.target.value as string | ||
]) | ||
} | ||
|
||
return ( | ||
<PageContent> | ||
<ViewContainer className="flex justify-between gap-[120px]"> | ||
{/* <QnaQuestionsList data={fetchQnaQuestions()}/> */} | ||
{/**/} | ||
<section className="qna-question-list flex flex-col items-center"> | ||
<div className="qna-topic mb-7 text-xl font-bold">Frontend Engineering</div> | ||
<div className="qna-questions flex flex-col gap-4 overflow-y-scroll max-h-[575px] hide-scrollbar h-[90svh]"> | ||
{qData?.map((q, index) => { | ||
return ( | ||
// <QnaQuesCard | ||
// key={index} | ||
// question={q.question} | ||
// score = {q.score} | ||
// questionId={q.questionId} | ||
// /> | ||
<BoxCard className={cn('bg-neutral-200 hover:brightness-90 flex flex-col justify-between p-4 min-h-[140px] cursor-pointer')} onClick={() => setQNum(q?.questionId)} key={index}> | ||
<div className="flex gap-1 align-items-center font-semibold text-lg truncate " > | ||
<span>{q?.questionId}.</span> | ||
<p>{q?.question}</p> | ||
</div> | ||
<span className=" | ||
text-neutral-400">+{q?.score} score</span> | ||
</BoxCard> | ||
); | ||
})} | ||
</div> | ||
</section> | ||
{/**/} | ||
<div className="w-full flex flex-col gap-16 "> | ||
<div className="remainingTime-endSessionAction-wrapper flex justify-between"> | ||
<Timer seconds={3600} /> | ||
<Button variant="destructive" className="end-session-btn">End Session</Button> | ||
</div> | ||
<div> | ||
<div className="flex flex-col gap-11"> | ||
<h2 className="question text-3xl font-semibold">{qData[qNum].question}</h2> | ||
<div className="answer-wrapper "> | ||
<p className="font-medium mb-1 text-sm" >Write your answer here</p> | ||
<Textarea className="answer-box min-h-[300px] w-full px-4 py-2 placeholder:text-base text-base" placeholder="Good luck! You will do well" onChange={handleAnsChange} value={storeAns[qNum]} /> | ||
</div> | ||
</div> | ||
<Button className="mark-complete-btn mt-3 flex gap-1"><Check /><span>Mark as completed</span></Button> | ||
</div> | ||
<Button className="submit-btn w-fit ml-auto mt-[-25px]">Submit and End Session</Button> | ||
</div> | ||
</ViewContainer> | ||
</PageContent> | ||
) | ||
} | ||
export default QNASession |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { QnaQuesCard } from "@/components/ui/qna-ques-card"; | ||
|
||
const QnaQuestionsList: React.FunctionComponent<{ data: Array<QnaQueCardInterface> }> = ({ data }) => { | ||
|
||
return( | ||
<section className="qna-question-list flex flex-col items-center"> | ||
<div className="qna-topic mb-7 text-xl font-bold">Frontend Engineering</div> | ||
<div className="qna-questions flex flex-col gap-4 overflow-y-scroll max-h-[575px] hide-scrollbar h-[90svh]"> | ||
{data.map((q, index) => { | ||
return ( | ||
<QnaQuesCard | ||
key={index} | ||
question={q.question} | ||
score = {q.score} | ||
questionId={q.questionId} | ||
/> | ||
); | ||
})} | ||
</div> | ||
</section> | ||
) | ||
} | ||
|
||
export {QnaQuestionsList}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import Link from "next/link"; | ||
import { BoxCard } from "../layouts/box-card"; | ||
import { cn } from "@/lib/utils"; | ||
|
||
const QnaQuesCard: React.FunctionComponent<QnaQueCardInterface> = ({question, questionId, score})=>{ | ||
return( | ||
<BoxCard className={cn('bg-neutral-200 hover:brightness-90 flex flex-col justify-between p-4 min-h-[140px]')}> | ||
<div className="flex gap-1 align-items-center font-semibold text-lg truncate " > | ||
<span>{questionId}.</span> | ||
<p>{question}</p> | ||
</div> | ||
<span className=" | ||
text-neutral-400">+{score} score</span> | ||
</BoxCard> | ||
) | ||
} | ||
|
||
export {QnaQuesCard}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
|
||
import { useEffect, useRef, useState } from "react"; | ||
import { Progress } from "@/components/ui/progress"; | ||
|
||
const formatTime = (time: number) => { | ||
let minutes = Math.floor(time / 60); | ||
let seconds = time % 60; | ||
|
||
const formattedMinutes = minutes < 10 ? `0${minutes}` : `${minutes}`; | ||
const formattedSeconds = seconds < 10 ? `0${seconds}` : `${seconds}`; | ||
|
||
return `${formattedMinutes}:${formattedSeconds}`; | ||
} | ||
|
||
function Timer({ seconds }: any) { | ||
const totalTime = seconds; | ||
const [progressVal, setProgressVal] = useState(0); | ||
const [timer, setTimer] = useState(seconds); | ||
const timerId: any = useRef(); | ||
|
||
useEffect(() => { | ||
timerId.current = setInterval(() => { | ||
setTimer((prev: number) => prev - 1); | ||
}, 1000); | ||
return () => clearInterval(timerId.current); | ||
}, []); | ||
|
||
useEffect(() => { | ||
const percent = ((totalTime - timer) / seconds) * 100; // Calculate progress relative to 'seconds' | ||
setProgressVal(percent); | ||
if (timer <= 0) { | ||
clearInterval(timerId.current); | ||
alert("Time up!"); | ||
} | ||
}, [timer, seconds]); | ||
|
||
return ( | ||
<div className="remainingTime-progress-wrapper w-3/4 flex flex-col gap-4"> | ||
<div className="remaining-time-wrapper"> | ||
<div className="remaining-time flex justify-between"> | ||
<h3 className="font-semibold text-lg">Remaining Time</h3> | ||
<div className="text-neutral-400 font-medium">{formatTime(timer)}</div> | ||
</div> | ||
</div> | ||
<Progress value={progressVal} /> | ||
</div> | ||
); | ||
} | ||
|
||
export { Timer }; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import * as React from "react" | ||
|
||
import { cn } from "@/lib/utils" | ||
|
||
export interface TextareaProps | ||
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {} | ||
|
||
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>( | ||
({ className, ...props }, ref) => { | ||
return ( | ||
<textarea | ||
className={cn( | ||
"flex min-h-[300px] w-full rounded-md border border-neutral-200 hover:border-neutral-400 bg-white px-3 py-2 text-sm ring-offset-white placeholder:text-neutral-400 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-neutral-300 disabled:cursor-not-allowed disabled:opacity-50 dark:border-neutral-800 dark:bg-neutral-950 dark:ring-offset-neutral-950 dark:placeholder:text-neutral-400 dark:focus-visible:ring-neutral-300 text-neutral-700", | ||
className | ||
)} | ||
ref={ref} | ||
{...props} | ||
/> | ||
) | ||
} | ||
) | ||
Textarea.displayName = "Textarea" | ||
|
||
export { Textarea } |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { Environment } from '@/common/environment-variables'; | ||
import { QnaMockQuestions } from '@/mocks/qna-questions-mock'; | ||
|
||
function fetchQnaQuestions(){ | ||
switch (Environment.ENVIRONMENT_TYPE){ | ||
case "development": | ||
return QnaMockQuestions; | ||
case "production": | ||
//TODO Send topic-name and fetch questions-list with marks for each question via openAI | ||
return []; | ||
default: | ||
return []; | ||
} | ||
} | ||
|
||
export {fetchQnaQuestions}; |
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. Do add random questions of different word lengths for better UI clarity. You can use ChatGPT to generate questions. 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. Done |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
|
||
|
||
const QnaMockQuestions: Array<QnaQueCardInterface> = [ | ||
{ | ||
question: "Define Diffing Algorithm 1", | ||
score: 10, | ||
questionId: 0 | ||
}, | ||
{ | ||
question: "Define Diffing Algorithm 2", | ||
score: 10, | ||
questionId: 1 | ||
}, | ||
{ | ||
question: "Define Diffing Algorithm 3", | ||
score: 10, | ||
questionId: 2 | ||
}, | ||
{ | ||
question: "Define Diffing Algorithm 4", | ||
score: 10, | ||
questionId: 3 | ||
}, | ||
{ | ||
question: "Define Diffing Algorithm 5", | ||
score: 10, | ||
questionId: 4 | ||
}, | ||
{ | ||
question: "Define Diffing Algorithm 6", | ||
score: 10, | ||
questionId: 5 | ||
}, | ||
{ | ||
question: "Define Diffing Algorithm 7", | ||
score: 10, | ||
questionId: 6 | ||
}, | ||
{ | ||
question: "Define Diffing Algorithm 8", | ||
score: 10, | ||
questionId: 7 | ||
}, | ||
{ | ||
question: "Define Diffing Algorithm 9", | ||
score: 10, | ||
questionId: 8 | ||
}, | ||
{ | ||
question: "Define Diffing Algorithm 10", | ||
score: 10, | ||
questionId: 9 | ||
} | ||
] | ||
|
||
|
||
export {QnaMockQuestions}; |
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 type is related to Q/A session, thus this type doesn't need a new file, |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
declare interface QnaQueCardInterface { | ||
question: string; | ||
score: number; | ||
questionId: number; | ||
} |
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.
Try to use better naming conventions. Instead of
q
usequestion