1
0
mirror of https://github.com/kamranahmedse/developer-roadmap.git synced 2025-09-02 13:52:46 +02:00
This commit is contained in:
Arik Chakma
2025-07-03 02:14:29 +06:00
parent 920d0512f6
commit e7e1c1c8d5
2 changed files with 58 additions and 54 deletions

View File

@@ -1,21 +1,15 @@
import {
CheckCircle,
PartyPopper,
RefreshCcw,
RotateCcw,
XCircle,
SkipForward,
CheckCircle2Icon,
PlusIcon,
CheckCircleIcon,
XCircleIcon,
SkipForwardIcon,
CheckIcon,
XIcon,
} from 'lucide-react';
import type { QuestionState } from './AIQuizContent';
import { getPercentage } from '../../lib/number';
import { cn } from '../../lib/classname';
import { QuizStateButton } from './AIQuizStripe';
type AIQuizResultsProps = {
questionStates: Record<number, QuestionState>;
@@ -61,27 +55,15 @@ export function AIQuizResults(props: AIQuizResultsProps) {
<div className="mb-6 grid w-full grid-cols-5 gap-2">
{states.map((state, quizIndex) => {
const { status } = state;
const isCorrect = status === 'correct';
const isIncorrect = status === 'incorrect';
const isSkipped = status === 'skipped';
return (
<button
<QuizStateButton
key={quizIndex}
onClick={() => onReview?.(quizIndex)}
className={cn(
'flex aspect-square flex-col items-center justify-center rounded-xl border border-gray-200 p-2 hover:opacity-80',
isCorrect && 'bg-green-700 text-white',
isIncorrect && 'bg-red-700 text-white',
isSkipped && 'bg-gray-700 text-white',
)}
>
{isCorrect && <CheckIcon className="h-6 w-6" />}
{isIncorrect && <XIcon className="h-6 w-6" />}
{isSkipped && <SkipForwardIcon className="h-6 w-6" />}
</button>
state={state}
quizIndex={quizIndex}
isActive={true}
onReview={onReview}
className="p-2"
/>
);
})}
</div>

View File

@@ -2,6 +2,7 @@ import { cn } from '../../lib/classname';
import {
ArrowRightIcon,
CheckIcon,
CircleAlertIcon,
SkipForwardIcon,
XIcon,
} from 'lucide-react';
@@ -14,48 +15,69 @@ type AIQuizStripeProps = {
onComplete?: () => void;
};
type QuizStateButtonProps = {
state: QuestionState;
quizIndex: number;
isActive: boolean;
onReview?: (questionIndex: number) => void;
className?: string;
};
export function QuizStateButton(props: QuizStateButtonProps) {
const { state, quizIndex, isActive, onReview, className } = props;
const { status } = state;
const isCorrect = status === 'correct';
const isIncorrect = status === 'incorrect';
const isSkipped = status === 'skipped';
const isCanBeImproved = status === 'can_be_improved';
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',
isCanBeImproved && 'border-yellow-700 bg-yellow-700 text-white',
!isActive && 'opacity-50',
className,
)}
>
{isCorrect && <CheckIcon className="h-6 w-6" />}
{isIncorrect && <XIcon className="h-6 w-6" />}
{isSkipped && <SkipForwardIcon className="h-6 w-6" />}
{isCanBeImproved && <CircleAlertIcon className="h-6 w-6" />}
</button>
);
}
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>
);
})}
{states.map((state, quizIndex) => (
<QuizStateButton
key={quizIndex}
state={state}
quizIndex={quizIndex}
isActive={quizIndex === activeQuestionIndex}
onReview={onReview}
/>
))}
</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" />
Show Results <ArrowRightIcon className="h-4 w-4" />
</button>
</div>
</div>