feat: Puente Mayúscula-Minúscula + TTS SpeechSynthesis + E2E fixes

This commit is contained in:
renato97
2026-07-21 15:31:46 -03:00
commit fa8e0c58ce
120 changed files with 16013 additions and 0 deletions
+78
View File
@@ -0,0 +1,78 @@
"use client"
import { useState, useEffect } from "react"
import { motion } from "framer-motion"
import { GatoMascota } from "@/components/child/gato-mascota"
const ALL_SKILLS = [
{ id: "vocal-a", label: "Letra A", emoji: "✈️" },
{ id: "vocal-e", label: "Letra E", emoji: "🐘" },
{ id: "vocal-i", label: "Letra I", emoji: "🏔️" },
{ id: "vocal-o", label: "Letra O", emoji: "🐻" },
{ id: "vocal-u", label: "Letra U", emoji: "🍇" },
{ id: "numero-1", label: "Número 1", emoji: "1️⃣" },
{ id: "numero-2", label: "Número 2", emoji: "2️⃣" },
{ id: "numero-3", label: "Número 3", emoji: "3️⃣" },
{ id: "numero-4", label: "Número 4", emoji: "4️⃣" },
{ id: "numero-5", label: "Número 5", emoji: "5️⃣" },
]
const CHILD_ID_KEY = "edueasy_child_id"
export default function LogrosPage() {
const [milestones, setMilestones] = useState<string[]>([])
const [loading, setLoading] = useState(true)
useEffect(() => {
const childId = localStorage.getItem(CHILD_ID_KEY)
if (!childId) {
setLoading(false)
return
}
fetch(`/api/milestones?childId=${childId}`)
.then((r) => r.json())
.then((data) => {
if (Array.isArray(data)) {
setMilestones(data.map((m: any) => m.skillCode))
}
})
.catch(() => {})
.finally(() => setLoading(false))
}, [])
const completedCount = milestones.length
return (
<div className="flex-1 flex flex-col items-center p-6 gap-6">
<GatoMascota mood="happy" message="Tus logros" size="sm" />
<p className="text-lg font-display">
{completedCount} de {ALL_SKILLS.length} completados
</p>
{loading ? (
<p className="text-muted-foreground">Cargando...</p>
) : (
<div className="flex flex-wrap gap-3 justify-center max-w-sm">
{ALL_SKILLS.map((skill, i) => {
const completed = milestones.includes(skill.id)
return (
<motion.div
key={skill.id}
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ delay: i * 0.05 }}
className={`rounded-2xl p-4 flex flex-col items-center gap-1 w-24 ${
completed ? "bg-primary/20 border-2 border-primary" : "bg-muted opacity-50"
}`}
>
<span className="text-3xl">{skill.emoji}</span>
<span className="text-xs text-center font-display font-medium">{skill.label}</span>
</motion.div>
)
})}
</div>
)}
</div>
)
}