mirror of
https://github.com/nihonbuzz/nihonbuzz-academy.git
synced 2026-01-26 05:25:37 +07:00
113 lines
5.9 KiB
TypeScript
113 lines
5.9 KiB
TypeScript
|
|
import React, { useState } from 'react';
|
|
import { Head, Link, useForm } from '@inertiajs/react';
|
|
import { CheckCircle, AlertCircle, RefreshCcw } from 'lucide-react';
|
|
import CourseLayout from '@/Layouts/CourseLayout';
|
|
import { Button } from '@/Components/ui/button';
|
|
import { RadioGroup, RadioGroupItem } from "@/Components/ui/radio-group";
|
|
import { Label } from "@/Components/ui/label";
|
|
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/Components/ui/card";
|
|
import { cn } from '@/lib/utils';
|
|
|
|
|
|
export default function Exam({ course, modules, lesson, previousResult, flash }: any) {
|
|
const [answers, setAnswers] = useState<Record<string, string>>({});
|
|
const { post, processing, wasSuccessful } = useForm();
|
|
|
|
// We can use flash messages or page props to show result state
|
|
const result = flash?.score !== undefined ? flash : (previousResult ? { score: previousResult, passed: previousResult >= 70 } : null);
|
|
|
|
const handleSelect = (questionId: string, value: string) => {
|
|
setAnswers(prev => ({ ...prev, [questionId]: value }));
|
|
};
|
|
|
|
const handleSubmit = (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
post(route('exams.store', { course: course.slug, lesson: lesson.slug, answers }), {
|
|
preserveScroll: true,
|
|
});
|
|
};
|
|
|
|
return (
|
|
<CourseLayout course={course} modules={modules} currentLesson={lesson}>
|
|
<Head title={`Ujian: ${lesson.title}`} />
|
|
|
|
<div className="max-w-2xl mx-auto space-y-8 pb-20">
|
|
<div className="text-center space-y-2">
|
|
<h1 className="text-3xl font-black tracking-tight">{lesson.title}</h1>
|
|
<p className="text-muted-foreground">Jawab semua pertanyaan untuk menyelesaikan kursus ini.</p>
|
|
</div>
|
|
|
|
{result && (
|
|
<div className={cn(
|
|
"p-6 rounded-2xl border flex flex-col items-center text-center gap-4 animate-in zoom-in-50 duration-500",
|
|
result.passed ? "bg-green-50 border-green-200 dark:bg-green-900/20 dark:border-green-900" : "bg-red-50 border-red-200 dark:bg-red-900/20 dark:border-red-900"
|
|
)}>
|
|
{result.passed ? (
|
|
<div className="h-16 w-16 bg-green-100 text-green-600 rounded-full flex items-center justify-center dark:bg-green-800 dark:text-green-200">
|
|
<CheckCircle size={32} />
|
|
</div>
|
|
) : (
|
|
<div className="h-16 w-16 bg-red-100 text-red-600 rounded-full flex items-center justify-center dark:bg-red-800 dark:text-red-200">
|
|
<AlertCircle size={32} />
|
|
</div>
|
|
)}
|
|
|
|
<div>
|
|
<h2 className="text-xl font-bold">{result.passed ? "Lulus!" : "Belum Lulus"}</h2>
|
|
<p className="font-medium text-muted-foreground">Skor Anda: <span className="text-foreground font-black text-lg">{result.score}%</span></p>
|
|
</div>
|
|
|
|
{result.passed ? (
|
|
<Button size="lg" className="rounded-full font-bold" disabled>
|
|
Sertifikat Terbit
|
|
</Button>
|
|
) : (
|
|
<Button size="lg" variant="outline" onClick={() => window.location.reload()} className="rounded-full gap-2">
|
|
<RefreshCcw size={16} />
|
|
Coba Lagi
|
|
</Button>
|
|
)}
|
|
</div>
|
|
)}
|
|
|
|
{!result?.passed && (
|
|
<form onSubmit={handleSubmit} className="space-y-8">
|
|
{lesson.questions.map((q: any, i: number) => (
|
|
<Card key={q.id} className="border-border/50 shadow-sm">
|
|
<CardHeader>
|
|
<CardTitle className="text-base font-bold leading-relaxed">
|
|
<span className="text-muted-foreground mr-2">{i + 1}.</span>
|
|
{q.question}
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<RadioGroup value={answers[q.id]} onValueChange={(val: string) => handleSelect(q.id, val)}>
|
|
{q.options.map((opt: string, idx: number) => (
|
|
<div key={idx} className="flex items-center space-x-2 border rounded-xl p-3 hover:bg-muted/50 transition-colors cursor-pointer">
|
|
<RadioGroupItem value={opt} id={`q${q.id}-opt${idx}`} />
|
|
<Label htmlFor={`q${q.id}-opt${idx}`} className="flex-1 cursor-pointer font-medium">{opt}</Label>
|
|
</div>
|
|
))}
|
|
</RadioGroup>
|
|
</CardContent>
|
|
</Card>
|
|
))}
|
|
|
|
<div className="flex justify-end pt-4">
|
|
<Button
|
|
type="submit"
|
|
size="lg"
|
|
className="w-full sm:w-auto rounded-full font-bold px-8"
|
|
disabled={processing}
|
|
>
|
|
{processing ? 'Memeriksa...' : 'Kirim Jawaban'}
|
|
</Button>
|
|
</div>
|
|
</form>
|
|
)}
|
|
</div>
|
|
</CourseLayout>
|
|
);
|
|
}
|