Generation Page (complete rebuild): - Full production-parity exam generation wizard with 4 IELTS modules - Reading: AI passage gen, 5 exercise types (MCQ, Fill, Write, T/F, Match) - Listening: 4 section types, AI context gen, TTS audio gen (ElevenLabs) - Writing: Task 1/2, AI instruction gen, word limits, marks - Speaking: 3 parts, AI script gen, avatar video gen (7 avatars) - Per-module config: timer, CEFR difficulty, access, approval, rubrics - Exam submission workflow (draft/published) Exam Structures: - New encoach.exam.structure model + CRUD controller - ExamStructuresPage wired to real API AI Module (encoach_ai): - OpenAI service, ElevenLabs TTS, AWS Polly, ELAI avatars - AI settings model with Odoo config parameters - 7 generation endpoints (passage, exercises, instructions, scripts, context) Vector Module (encoach_vector): - pgvector integration for RAG-based content search - Embedding service with sentence-transformers Exam Session Fixes: - Fixed ExamSession.tsx field mapping (question_type→type, exam_title→title) - Fixed submit payload to include attempt_id and answers - Fixed normalizeType to handle null/undefined Tested: 12/12 API tests passed, browser-verified with real OpenAI calls Made-with: Cursor
95 lines
5.2 KiB
TypeScript
95 lines
5.2 KiB
TypeScript
import { useState } from "react";
|
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|
import { Progress } from "@/components/ui/progress";
|
|
import { Badge } from "@/components/ui/badge";
|
|
import { Switch } from "@/components/ui/switch";
|
|
import { Label } from "@/components/ui/label";
|
|
import { CheckCircle, PenTool, Sparkles } from "lucide-react";
|
|
import AiTipBanner from "@/components/ai/AiTipBanner";
|
|
|
|
const grammarItems = [
|
|
{ rule: "Conditional Sentences (Type 2 & 3)", description: "If + past simple / past perfect for hypothetical situations", level: "B2", completed: true },
|
|
{ rule: "Passive Voice in Academic Writing", description: "Using passive constructions in formal reports", level: "B2", completed: false },
|
|
{ rule: "Relative Clauses", description: "Defining vs non-defining relative clauses", level: "B1", completed: true },
|
|
{ rule: "Subject-Verb Agreement", description: "Complex subjects with prepositional phrases", level: "B1", completed: false },
|
|
{ rule: "Modal Verbs for Speculation", description: "Must have, could have, might have + past participle", level: "C1", completed: false },
|
|
{ rule: "Reported Speech", description: "Tense changes and time references in indirect speech", level: "B2", completed: true },
|
|
];
|
|
|
|
export default function GrammarPage() {
|
|
const [showCompleted, setShowCompleted] = useState(false);
|
|
const completed = grammarItems.filter(g => g.completed).length;
|
|
const filtered = showCompleted ? grammarItems : grammarItems.filter(g => !g.completed);
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
<div>
|
|
<h1 className="text-2xl font-bold tracking-tight">Grammar Training</h1>
|
|
<p className="text-muted-foreground">Master grammar rules essential for IELTS.</p>
|
|
</div>
|
|
|
|
<AiTipBanner context="grammar" variant="recommendation" />
|
|
|
|
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
|
<div className="lg:col-span-2 space-y-4">
|
|
<Card className="border-0 shadow-sm">
|
|
<CardHeader className="pb-3">
|
|
<div className="flex items-center justify-between">
|
|
<CardTitle className="text-base">Progress</CardTitle>
|
|
<span className="text-sm text-muted-foreground">{completed}/{grammarItems.length} completed</span>
|
|
</div>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<Progress value={(completed / grammarItems.length) * 100} className="h-3" />
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<div className="flex items-center gap-2">
|
|
<Switch id="show" checked={showCompleted} onCheckedChange={setShowCompleted} />
|
|
<Label htmlFor="show" className="text-sm">Show completed</Label>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
{filtered.map((g) => (
|
|
<Card key={g.rule} className="border-0 shadow-sm">
|
|
<CardContent className="p-4 flex items-center justify-between">
|
|
<div className="flex items-center gap-3">
|
|
{g.completed && <CheckCircle className="h-4 w-4 text-success shrink-0" />}
|
|
<div>
|
|
<p className="font-semibold text-sm">{g.rule}</p>
|
|
<p className="text-xs text-muted-foreground">{g.description}</p>
|
|
</div>
|
|
</div>
|
|
<Badge variant="outline">{g.level}</Badge>
|
|
</CardContent>
|
|
</Card>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="space-y-4">
|
|
<Card className="border-0 shadow-sm">
|
|
<CardHeader className="pb-3">
|
|
<CardTitle className="text-base flex items-center gap-2"><Sparkles className="h-4 w-4 text-primary" /> AI Recommendations</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<ul className="space-y-2">
|
|
<li className="text-sm text-muted-foreground flex items-start gap-2"><span className="text-primary font-bold">•</span>Practice passive voice transformations — high exam frequency</li>
|
|
<li className="text-sm text-muted-foreground flex items-start gap-2"><span className="text-primary font-bold">•</span>Review modal verbs for IELTS Writing Task 1</li>
|
|
<li className="text-sm text-muted-foreground flex items-start gap-2"><span className="text-primary font-bold">•</span>Focus on complex sentence structures for C1 readiness</li>
|
|
<li className="text-sm text-muted-foreground flex items-start gap-2"><span className="text-primary font-bold">•</span>Your conditional sentences are strong — try advanced mixed conditionals</li>
|
|
</ul>
|
|
</CardContent>
|
|
</Card>
|
|
<Card className="border-0 shadow-sm border-primary/20 bg-primary/5">
|
|
<CardContent className="p-4">
|
|
<p className="text-xs font-semibold text-primary flex items-center gap-1 mb-2"><Sparkles className="h-3 w-3" /> AI Study Plan</p>
|
|
<p className="text-sm text-muted-foreground">Based on your progress, complete Passive Voice and Subject-Verb Agreement this week. At your current pace, you'll finish all B2 grammar by April 15.</p>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|