mirror of
https://github.com/lucasrcsantana/story-generator.git
synced 2025-12-18 14:27:51 +00:00
128 lines
3.8 KiB
TypeScript
128 lines
3.8 KiB
TypeScript
import React, { useEffect, useState } from 'react';
|
|
import { BookOpen, Puzzle, Mic } from 'lucide-react';
|
|
import { useNavigate } from 'react-router-dom';
|
|
import { supabase } from '../../lib/supabase';
|
|
|
|
interface ExerciseSuggestionsProps {
|
|
storyId: string;
|
|
storyText: string;
|
|
readingMetrics: {
|
|
difficultWords: string[];
|
|
errorCount: number;
|
|
pauseCount: number;
|
|
fluencyScore: number;
|
|
};
|
|
}
|
|
|
|
interface ExerciseWord {
|
|
word: string;
|
|
exercise_type: string;
|
|
phonemes: string[] | null;
|
|
syllable_pattern: string | null;
|
|
}
|
|
|
|
export function ExerciseSuggestions({ storyId, storyText, readingMetrics }: ExerciseSuggestionsProps) {
|
|
const navigate = useNavigate();
|
|
const [exerciseWords, setExerciseWords] = useState<ExerciseWord[]>([]);
|
|
|
|
useEffect(() => {
|
|
const loadExerciseWords = async () => {
|
|
const { data, error } = await supabase
|
|
.from('story_exercise_words')
|
|
.select('*')
|
|
.eq('story_id', storyId)
|
|
.order('created_at', { ascending: true });
|
|
|
|
if (!error && data) {
|
|
setExerciseWords(data);
|
|
}
|
|
};
|
|
|
|
loadExerciseWords();
|
|
}, [storyId]);
|
|
|
|
const handleExerciseSelect = (exerciseType: string) => {
|
|
if (!storyId) {
|
|
console.error('ID da história não fornecido');
|
|
return;
|
|
}
|
|
navigate(`/aluno/historias/${storyId}/exercicios/${exerciseType}`);
|
|
};
|
|
|
|
const generateExercises = () => {
|
|
const exercises = [
|
|
{
|
|
type: 'word-formation',
|
|
title: 'Formação de Palavras',
|
|
description: 'Monte novas palavras usando sílabas da história',
|
|
icon: <Puzzle className="w-6 h-6" />,
|
|
words: exerciseWords
|
|
.filter(w => w.exercise_type === 'formation')
|
|
.map(w => w.word),
|
|
},
|
|
{
|
|
type: 'sentence-completion',
|
|
title: 'Complete a História',
|
|
description: 'Complete as frases com as palavras corretas',
|
|
icon: <BookOpen className="w-6 h-6" />,
|
|
words: exerciseWords
|
|
.filter(w => w.exercise_type === 'completion')
|
|
.map(w => w.word),
|
|
},
|
|
{
|
|
type: 'pronunciation-practice',
|
|
title: 'Treino de Pronúncia',
|
|
description: 'Pratique a pronúncia das palavras difíceis',
|
|
icon: <Mic className="w-6 h-6" />,
|
|
words: exerciseWords
|
|
.filter(w => w.exercise_type === 'pronunciation')
|
|
.map(w => w.word),
|
|
}
|
|
];
|
|
|
|
return exercises;
|
|
};
|
|
|
|
return (
|
|
<div className="mt-8">
|
|
<h2 className="text-2xl font-bold text-gray-900 mb-4 ">
|
|
Exercícios Sugeridos
|
|
</h2>
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
|
{generateExercises().map((exercise) => (
|
|
<button
|
|
key={exercise.type}
|
|
onClick={() => handleExerciseSelect(exercise.type)}
|
|
className="p-4 bg-white rounded-lg border border-gray-200 hover:border-purple-500 transition-colors"
|
|
>
|
|
<div className="flex items-center gap-3 mb-2">
|
|
<div className="text-purple-600">
|
|
{exercise.icon}
|
|
</div>
|
|
<h4 className="font-semibold text-gray-900">
|
|
{exercise.title}
|
|
</h4>
|
|
</div>
|
|
<p className="text-sm text-gray-600 mb-3">
|
|
{exercise.description}
|
|
</p>
|
|
<div className="text-xs text-gray-500">
|
|
{exercise.type === 'word-formation' && (
|
|
<div>
|
|
Palavras para praticar:
|
|
<div className="mt-1 flex flex-wrap gap-1">
|
|
{exercise.words.map(word => (
|
|
<span key={word} className="bg-purple-100 px-2 py-1 rounded">
|
|
{word}
|
|
</span>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|