feat: add AdjustAIButton, EditPlanButton, and AsignaturaPreviewCard components
- Implemented AdjustAIButton for AI-driven plan adjustments with a confetti effect on success. - Created EditPlanButton to allow editing of plan details with form validation and optimistic updates. - Added AsignaturaPreviewCard to display course previews with relevant statistics and details. - Introduced Field component for consistent form field labeling. - Developed GradientMesh for dynamic background effects based on color input. - Added Pulse component for skeleton loading states. - Created SmallStat and StatCard components for displaying statistical information in a card format. - Implemented utility functions in planHelpers for color manipulation and formatting. - Established planQueries for fetching plan and course data from the database. - Updated the plan detail route to utilize new components and queries for improved user experience.
This commit is contained in:
47
src/components/planes/AdjustAIButton.tsx
Normal file
47
src/components/planes/AdjustAIButton.tsx
Normal file
@@ -0,0 +1,47 @@
|
||||
import { useState } from "react"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import * as Icons from "lucide-react"
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from "@/components/ui/dialog"
|
||||
import { Textarea } from "@/components/ui/textarea"
|
||||
import { AuroraButton } from "@/components/effect/aurora-button"
|
||||
import confetti from "canvas-confetti"
|
||||
import type { PlanFull } from "./planQueries"
|
||||
|
||||
export function AdjustAIButton({ plan }: { plan: PlanFull }) {
|
||||
const [open, setOpen] = useState(false)
|
||||
const [prompt, setPrompt] = useState('')
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
async function apply() {
|
||||
setLoading(true)
|
||||
await fetch('https://genesis-engine.apps.lci.ulsa.mx/api/mejorar/plan', {
|
||||
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ prompt, plan_id: plan.id }),
|
||||
}).catch(() => { })
|
||||
setLoading(false)
|
||||
confetti({ particleCount: 120, spread: 80, origin: { y: 0.6 } })
|
||||
setOpen(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button onClick={() => setOpen(true)}>
|
||||
<Icons.Sparkles className="w-4 h-4 mr-2" /> Ajustar con IA
|
||||
</Button>
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogContent className="max-w-lg">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Ajustar con IA</DialogTitle>
|
||||
<DialogDescription>Describe cómo quieres modificar el plan actual.</DialogDescription>
|
||||
</DialogHeader>
|
||||
<Textarea value={prompt} onChange={(e) => setPrompt(e.target.value)} placeholder="Ej.: Enfatiza ciberseguridad y proyectos prácticos…" className="min-h-[120px]" />
|
||||
<DialogFooter>
|
||||
<AuroraButton onClick={apply} disabled={!prompt.trim() || loading}>
|
||||
{loading ? 'Aplicando…' : 'Aplicar ajuste'}
|
||||
</AuroraButton>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user