1
0
mirror of https://github.com/kamranahmedse/developer-roadmap.git synced 2025-08-31 21:11:44 +02:00
This commit is contained in:
Arik Chakma
2025-07-03 00:40:10 +06:00
parent c370bafc53
commit 9f15ca1e53
2 changed files with 85 additions and 1 deletions

View File

@@ -6,6 +6,8 @@ import { QuizTopNavigation } from './QuizTopNavigation';
import { getPercentage } from '../../lib/number';
import { AIQuizResults } from './AIQuizResults';
import { flushSync } from 'react-dom';
import { AIQuizStripe } from './AIQuizStripe';
import { cn } from '../../lib/classname';
export type QuestionState = {
isSubmitted: boolean;
@@ -146,7 +148,12 @@ export function AIQuizContent(props: AIQuizContentProps) {
};
return (
<div className="mx-auto w-full max-w-lg py-10">
<div
className={cn(
'mx-auto w-full max-w-lg py-10',
quizStatus === 'reviewing' && 'pb-24',
)}
>
{shouldShowQuestions && (
<QuizTopNavigation
activeQuestionIndex={activeQuestionIndex}
@@ -203,6 +210,20 @@ export function AIQuizContent(props: AIQuizContentProps) {
)}
</>
)}
{quizStatus === 'reviewing' && (
<AIQuizStripe
activeQuestionIndex={activeQuestionIndex}
questionStates={questionStates}
onReview={(questionIndex) => {
setActiveQuestionIndex(questionIndex);
setQuizStatus('reviewing');
}}
onComplete={() => {
setQuizStatus('submitted');
}}
/>
)}
</div>
);
}

View File

@@ -0,0 +1,63 @@
import { cn } from '../../lib/classname';
import {
ArrowRightIcon,
CheckIcon,
SkipForwardIcon,
XIcon,
} from 'lucide-react';
import type { QuestionState } from './AIQuizContent';
type AIQuizStripeProps = {
activeQuestionIndex: number;
questionStates: Record<number, QuestionState>;
onReview?: (questionIndex: number) => void;
onComplete?: () => void;
};
export function AIQuizStripe(props: AIQuizStripeProps) {
const { activeQuestionIndex, questionStates, onReview, onComplete } = props;
const states = Object.values(questionStates);
return (
<div className="fixed right-0 bottom-0 w-[calc(100vw-255px)] border-t border-gray-200 bg-white p-3">
<div className="flex items-center justify-between gap-2">
<div className="flex w-full gap-2">
{states.map((state, quizIndex) => {
const { status } = state;
const isActive = quizIndex === activeQuestionIndex;
const isCorrect = status === 'correct';
const isIncorrect = status === 'incorrect';
const isSkipped = status === 'skipped';
return (
<button
key={quizIndex}
onClick={() => onReview?.(quizIndex)}
className={cn(
'flex aspect-square flex-col items-center justify-center rounded-xl border p-1 hover:opacity-80',
isCorrect && 'border-green-700 bg-green-700 text-white',
isIncorrect && 'border-red-700 bg-red-700 text-white',
isSkipped && 'border-gray-700 bg-gray-700 text-white',
!isActive && 'opacity-50',
)}
>
{isCorrect && <CheckIcon className="h-6 w-6" />}
{isIncorrect && <XIcon className="h-6 w-6" />}
{isSkipped && <SkipForwardIcon className="h-6 w-6" />}
</button>
);
})}
</div>
<button
className="flex shrink-0 items-center gap-2 rounded-xl bg-black px-4 py-2 text-white hover:bg-gray-900 disabled:opacity-70"
onClick={onComplete}
>
Complete Quiz <ArrowRightIcon className="h-4 w-4" />
</button>
</div>
</div>
);
}