Files
Academia-Front/src/views/CreateCourseView.tsx
T
2026-08-22 00:09:06 -05:00

313 lines
13 KiB
TypeScript

import React, { useState } from 'react';
import { useNavigate } from 'react-router';
import type { Course } from '../types/course';
import { FiArrowLeft, FiPlus, FiTrash2, FiUploadCloud } from 'react-icons/fi';
interface CreateCourseViewProps {
onCreateCourse: (course: Course) => void;
onShowToast: (msg: string) => void;
}
export const CreateCourseView: React.FC<CreateCourseViewProps> = ({
onCreateCourse,
onShowToast,
}) => {
const navigate = useNavigate();
const [title, setTitle] = useState('');
const [subtitle, setSubtitle] = useState('');
const [category, setCategory] = useState('Desarrollo Web');
const [level, setLevel] = useState<'Principiante' | 'Intermedio' | 'Avanzado' | 'Todos los niveles'>('Principiante');
const [price, setPrice] = useState(29.99);
const [originalPrice, setOriginalPrice] = useState(89.99);
const [thumbnail, setThumbnail] = useState('https://images.unsplash.com/photo-1517694712202-14dd9538aa97?w=800&auto=format&fit=crop&q=80');
const [modules, setModules] = useState<{ title: string; lessonsCount: number }[]>([
{ title: 'Módulo 1: Introducción y Fundamentos', lessonsCount: 4 },
{ title: 'Módulo 2: Proyecto Práctico Principal', lessonsCount: 6 },
]);
const [newModuleTitle, setNewModuleTitle] = useState('');
const handleAddModule = () => {
if (newModuleTitle.trim()) {
setModules([...modules, { title: newModuleTitle, lessonsCount: 3 }]);
setNewModuleTitle('');
}
};
const handleRemoveModule = (idx: number) => {
setModules(modules.filter((_, i) => i !== idx));
};
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (!title.trim()) return;
const newCourse: Course = {
id: `course-${Date.now()}`,
title,
subtitle: subtitle || 'Aprende paso a paso con proyectos prácticos.',
category,
level,
price: Number(price),
originalPrice: Number(originalPrice),
rating: 5.0,
reviewsCount: 1,
studentsCount: 1,
thumbnail,
duration: '12h 30m',
lessonsCount: modules.reduce((sum, m) => sum + m.lessonsCount, 0),
badge: 'Nuevo',
instructor: {
id: 'inst-1',
name: 'Tu Nombre (Instructor)',
role: 'Instructor Experto',
avatar: 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=100&auto=format&fit=crop&q=80',
rating: 5.0,
totalStudents: 1,
totalCourses: 1,
bio: 'Creador de contenido y profesional en tecnología.',
},
updatedAt: 'Reciente',
language: 'Español',
whatYouWillLearn: [
'Dominio completo de la tecnología aprendida.',
'Construcción de proyectos prácticos listos para producción.',
'Código fuente completo e instructivos.',
],
requirements: ['Computadora con conexión a internet.'],
modules: modules.map((m, idx) => ({
id: `mod-${idx}`,
title: m.title,
lessons: [
{ id: `l-${idx}-1`, title: 'Lección 1: Conceptos Clave', duration: '15:00', isFreePreview: true },
{ id: `l-${idx}-2`, title: 'Lección 2: Implementación', duration: '22:30' },
],
})),
reviews: [],
isPublished: true,
salesCount: 0,
totalRevenue: 0,
};
onCreateCourse(newCourse);
onShowToast('¡Tu curso ha sido publicado exitosamente en el Marketplace!');
navigate('/seller');
};
return (
<div className="min-h-screen bg-slate-950 py-10">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 space-y-8">
{/* Header */}
<div className="flex items-center justify-between border-b border-slate-800 pb-5">
<div className="space-y-1">
<button
onClick={() => navigate('/seller')}
className="inline-flex items-center gap-2 text-xs font-semibold text-slate-400 hover:text-cyan-400 mb-2 transition"
>
<FiArrowLeft /> Regresar a Panel de Instructor
</button>
<h1 className="text-2xl sm:text-3xl font-extrabold text-white">
Publicar Nuevo Curso
</h1>
<p className="text-xs text-slate-400">
Completa los detalles de tu curso para lanzarlo a la comunidad de estudiantes
</p>
</div>
</div>
{/* Form Container */}
<form onSubmit={handleSubmit} className="space-y-8">
{/* Card 1: Informacion Basica */}
<div className="bg-slate-900 border border-slate-800 rounded-3xl p-6 sm:p-8 space-y-6 shadow-xl">
<h3 className="text-sm font-bold text-cyan-400 uppercase tracking-wider">
1. Información Básica
</h3>
<div className="space-y-4">
<div>
<label className="block text-xs font-semibold text-slate-300 mb-1">
Título del Curso *
</label>
<input
type="text"
required
value={title}
onChange={(e) => setTitle(e.target.value)}
placeholder="Ej: Master en React 19 y Next.js 15 desde Cero"
className="w-full px-4 py-3 bg-slate-950 border border-slate-700/80 rounded-xl text-xs text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-cyan-500"
/>
</div>
<div>
<label className="block text-xs font-semibold text-slate-300 mb-1">
Subtítulo Resumen
</label>
<input
type="text"
value={subtitle}
onChange={(e) => setSubtitle(e.target.value)}
placeholder="Aprende a construir aplicaciones fullstack de alto rendimiento..."
className="w-full px-4 py-3 bg-slate-950 border border-slate-700/80 rounded-xl text-xs text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-cyan-500"
/>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div>
<label className="block text-xs font-semibold text-slate-300 mb-1">
Categoría
</label>
<select
value={category}
onChange={(e) => setCategory(e.target.value)}
className="w-full px-4 py-3 bg-slate-950 border border-slate-700/80 rounded-xl text-xs text-white focus:outline-none focus:ring-2 focus:ring-cyan-500"
>
<option value="Desarrollo Web">Desarrollo Web</option>
<option value="Inteligencia Artificial">Inteligencia Artificial</option>
<option value="Diseño UI/UX">Diseño UI/UX</option>
<option value="Ciberseguridad">Ciberseguridad</option>
<option value="Marketing Digital">Marketing Digital</option>
<option value="Negocios">Negocios</option>
</select>
</div>
<div>
<label className="block text-xs font-semibold text-slate-300 mb-1">
Nivel del Curso
</label>
<select
value={level}
onChange={(e) => setLevel(e.target.value as any)}
className="w-full px-4 py-3 bg-slate-950 border border-slate-700/80 rounded-xl text-xs text-white focus:outline-none focus:ring-2 focus:ring-cyan-500"
>
<option value="Principiante">Principiante</option>
<option value="Intermedio">Intermedio</option>
<option value="Avanzado">Avanzado</option>
<option value="Todos los niveles">Todos los niveles</option>
</select>
</div>
</div>
</div>
</div>
{/* Card 2: Precio e Imagen */}
<div className="bg-slate-900 border border-slate-800 rounded-3xl p-6 sm:p-8 space-y-6 shadow-xl">
<h3 className="text-sm font-bold text-cyan-400 uppercase tracking-wider">
2. Precio e Imagen de Portada
</h3>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div>
<label className="block text-xs font-semibold text-slate-300 mb-1">
Precio de Venta ($ USD)
</label>
<input
type="number"
step="0.01"
required
value={price}
onChange={(e) => setPrice(Number(e.target.value))}
className="w-full px-4 py-3 bg-slate-950 border border-slate-700/80 rounded-xl text-xs text-white font-mono focus:outline-none focus:ring-2 focus:ring-cyan-500"
/>
</div>
<div>
<label className="block text-xs font-semibold text-slate-300 mb-1">
Precio Original Táchado ($ USD)
</label>
<input
type="number"
step="0.01"
required
value={originalPrice}
onChange={(e) => setOriginalPrice(Number(e.target.value))}
className="w-full px-4 py-3 bg-slate-950 border border-slate-700/80 rounded-xl text-xs text-white font-mono focus:outline-none focus:ring-2 focus:ring-cyan-500"
/>
</div>
</div>
<div>
<label className="block text-xs font-semibold text-slate-300 mb-1">
URL de la Imagen de Portada
</label>
<div className="flex gap-2">
<input
type="url"
value={thumbnail}
onChange={(e) => setThumbnail(e.target.value)}
className="flex-1 px-4 py-3 bg-slate-950 border border-slate-700/80 rounded-xl text-xs text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-cyan-500"
/>
</div>
<div className="mt-3 aspect-video max-w-sm rounded-xl overflow-hidden bg-slate-950 border border-slate-800">
<img src={thumbnail} alt="Vista previa" className="w-full h-full object-cover" />
</div>
</div>
</div>
{/* Card 3: Estructura del Temario */}
<div className="bg-slate-900 border border-slate-800 rounded-3xl p-6 sm:p-8 space-y-6 shadow-xl">
<h3 className="text-sm font-bold text-cyan-400 uppercase tracking-wider">
3. Módulos y Temario
</h3>
<div className="space-y-3">
{modules.map((m, idx) => (
<div key={idx} className="flex items-center justify-between p-4 bg-slate-950 border border-slate-800 rounded-xl text-xs">
<span className="font-semibold text-white">{m.title}</span>
<button
type="button"
onClick={() => handleRemoveModule(idx)}
className="p-2 text-slate-500 hover:text-rose-400 transition"
>
<FiTrash2 />
</button>
</div>
))}
<div className="flex gap-2 pt-2">
<input
type="text"
value={newModuleTitle}
onChange={(e) => setNewModuleTitle(e.target.value)}
placeholder="Agregar nuevo título de módulo..."
className="flex-1 px-4 py-2.5 bg-slate-950 border border-slate-700/80 rounded-xl text-xs text-white focus:outline-none focus:ring-2 focus:ring-cyan-500"
/>
<button
type="button"
onClick={handleAddModule}
className="px-4 py-2.5 bg-slate-800 hover:bg-slate-700 text-cyan-400 font-semibold rounded-xl text-xs flex items-center gap-1.5 transition"
>
<FiPlus /> Módulo
</button>
</div>
</div>
</div>
{/* Submit Actions */}
<div className="flex items-center justify-end gap-4 pt-4">
<button
type="button"
onClick={() => navigate('/seller')}
className="px-6 py-3.5 bg-slate-800 hover:bg-slate-700 text-slate-300 font-semibold rounded-xl text-xs transition"
>
Cancelar
</button>
<button
type="submit"
className="px-8 py-3.5 bg-gradient-to-r from-blue-600 to-cyan-500 hover:from-blue-500 hover:to-cyan-400 text-white font-bold rounded-xl text-sm shadow-xl shadow-cyan-500/25 transition-all flex items-center gap-2"
>
<FiUploadCloud />
<span>Publicar Curso en RyCourses</span>
</button>
</div>
</form>
</div>
</div>
);
};