react-datosTutorial Paso a Paso COMPLETO - Gestor de Tareas con edicion

 

Tutorial Minimalista de Gestor de Tareas React

Aquí tienes la versión más minimalista del CSS para que el estudiante pueda copiarlo en una hora:

🚀 Paso 1: Configuración Inicial

bash
npx create-react-app gestor-tareas
cd gestor-tareas
npm start

Eliminar: App.test.js, logo.svg, reportWebVitals.js, setupTests.js

Estructura:

text
src/
├── components/
│   ├── TareaList.js
│   ├── TareaForm.js
│   └── TareaItem.js
├── App.js
└── index.js

📄 Paso 2: index.js

jsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);

📦 Paso 3: App.js Básico

jsx
import React from 'react';
import TareaList from './components/TareaList';

function App() {
  return (
    <div style={{ padding: '20px', maxWidth: '1000px', margin: '0 auto' }}>
      <h1 style={{ textAlign: 'center' }}>📝 Gestor de Tareas</h1>
      <TareaList />
    </div>
  );
}

export default App;

📋 Paso 4: TareaList.js

jsx
import React, { useState } from 'react';
import TareaForm from './TareaForm';
import TareaItem from './TareaItem';

function TareaList() {
  const [tareas, setTareas] = useState([
    { id: 1, titulo: 'Comprar leche', descripcion: 'Ir al supermercado', completada: false },
    { id: 2, titulo: 'Estudiar React', descripcion: 'Hacer ejercicios', completada: true },
  ]);

  const [editando, setEditando] = useState(null);

  const crearTarea = (datos) => {
    const nuevaTarea = {
      ...datos,
      id: Date.now(),
    };
    setTareas([...tareas, nuevaTarea]);
  };

  const actualizarTarea = (id, datos) => {
    setTareas(tareas.map(t => t.id === id ? { ...t, ...datos } : t));
    setEditando(null);
  };

  const eliminarTarea = (id) => {
    if (window.confirm('¿Eliminar tarea?')) {
      setTareas(tareas.filter(t => t.id !== id));
    }
  };

  const completarTarea = (id, completada) => {
    setTareas(tareas.map(t => t.id === id ? { ...t, completada } : t));
  };

  return (
    <div style={{ display: 'grid', gridTemplateColumns: '300px 1fr', gap: '20px' }}>
      <TareaForm
        onSubmit={editando ? (datos) => actualizarTarea(editando.id, datos) : crearTarea}
        initialData={editando}
        onCancel={() => setEditando(null)}
      />
      
      <div style={{ border: '1px solid #ccc', padding: '20px' }}>
        <h2>Lista de Tareas ({tareas.length})</h2>
        
        {tareas.map(tarea => (
          <TareaItem
            key={tarea.id}
            tarea={tarea}
            onEdit={setEditando}
            onDelete={eliminarTarea}
            onToggle={completarTarea}
          />
        ))}
      </div>
    </div>
  );
}

export default TareaList;

✏️ Paso 5: TareaForm.js

jsx
import React, { useState } from 'react';

function TareaForm({ onSubmit, initialData = null, onCancel }) {
  const [formData, setFormData] = useState({
    titulo: initialData?.titulo || '',
    descripcion: initialData?.descripcion || '',
    completada: initialData?.completada || false,
  });

  const [error, setError] = useState('');

  const handleChange = (e) => {
    const { name, value, type, checked } = e.target;
    setFormData(prev => ({
      ...prev,
      [name]: type === 'checkbox' ? checked : value,
    }));
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    
    if (!formData.titulo.trim()) {
      setError('El título es obligatorio');
      return;
    }
    
    onSubmit(formData);
    
    if (!initialData) {
      setFormData({ titulo: '', descripcion: '', completada: false });
    }
    
    setError('');
  };

  return (
    <div style={{ border: '1px solid #ccc', padding: '20px' }}>
      <h2>{initialData ? 'Editar Tarea' : 'Nueva Tarea'}</h2>
      
      {error && <p style={{ color: 'red' }}>{error}</p>}
      
      <form onSubmit={handleSubmit}>
        <div style={{ marginBottom: '15px' }}>
          <label style={{ display: 'block', marginBottom: '5px' }}>Título:</label>
          <input
            name="titulo"
            value={formData.titulo}
            onChange={handleChange}
            placeholder="Título de la tarea"
            style={{ width: '100%', padding: '8px', border: '1px solid #ccc' }}
          />
        </div>
        
        <div style={{ marginBottom: '15px' }}>
          <label style={{ display: 'block', marginBottom: '5px' }}>Descripción:</label>
          <textarea
            name="descripcion"
            value={formData.descripcion}
            onChange={handleChange}
            placeholder="Descripción"
            rows="3"
            style={{ width: '100%', padding: '8px', border: '1px solid #ccc' }}
          />
        </div>
        
        <div style={{ marginBottom: '15px' }}>
          <label>
            <input
              type="checkbox"
              name="completada"
              checked={formData.completada}
              onChange={handleChange}
            />
            Completada
          </label>
        </div>
        
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '10px' }}>
          <button type="submit">
            {initialData ? 'Guardar' : 'Crear'}
          </button>
          
          {onCancel && (
            <button type="button" onClick={onCancel}>
              Cancelar
            </button>
          )}
        </div>
      </form>
    </div>
  );
}

export default TareaForm;

📦 Paso 6: TareaItem.js

jsx
import React from 'react';

function TareaItem({ tarea, onEdit, onDelete, onToggle }) {
  return (
    <div style={{ border: '1px solid #ccc', padding: '15px', marginBottom: '10px' }}>
      <h3>{tarea.titulo}</h3>
      <p>{tarea.descripcion}</p>
      <p>Estado: {tarea.completada ? '✅ Completada' : '⏳ Pendiente'}</p>
      
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '10px', marginTop: '10px' }}>
        <button onClick={() => onToggle(tarea.id, !tarea.completada)}>
          {tarea.completada ? 'Desmarcar' : 'Completar'}
        </button>
        <button onClick={() => onEdit(tarea)}>Editar</button>
        <button onClick={() => onDelete(tarea.id)}>Eliminar</button>
      </div>
    </div>
  );
}

export default TareaItem;

🎯 CSS Grid Resumen (Incluido en el código):

  1. Layout principal: grid-template-columns: '300px 1fr' (2 columnas)

  2. Botones del formulario: grid-template-columns: '1fr 1fr' (2 columnas iguales)

  3. Botones de tarea: grid-template-columns: 'repeat(3, 1fr)' (3 columnas iguales)

¡Listo! El estudiante tiene un gestor de tareas funcional con CSS Grid en menos de 1 hora.

Comentarios

Entradas más populares de este blog

0-Sistema de Tareas

13-CRUD en Laravel para Web y API con Rutas Normales (No Resource)

10-Introducción a Blade en Laravel con un Ejemplo Práctico