Formulários Complexos e Upload

Módulo 4: Eventos e Formulários

Aula 4
1

Formulários Multi-Step

22:00

Aprenda a criar formulários com múltiplas etapas

2

Upload de Arquivos e Campos Dinâmicos

Implemente upload de arquivos e formulários que crescem dinamicamente

Upload de Arquivos e Campos Dinâmicos

Upload de Arquivos

Input de Arquivo Básico

function UploadSimples() {
  const [arquivo, setArquivo] = useState(null);
  const [preview, setPreview] = useState('');

  const handleFileChange = (e) => {
    const file = e.target.files[0];
    if (file) {
      setArquivo(file);
      
      // Preview para imagens
      if (file.type.startsWith('image/')) {
        const reader = new FileReader();
        reader.onloadend = () => {
          setPreview(reader.result);
        };
        reader.readAsDataURL(file);
      }
    }
  };

  return (
    <div>
      <input
        type="file"
        onChange={handleFileChange}
        accept="image/*"
      />
      
      {preview && (
        <img 
          src={preview} 
          alt="Preview" 
          style={{ maxWidth: '200px' }}
        />
      )}
      
      {arquivo && (
        <div>
          <p>Nome: {arquivo.name}</p>
          <p>Tamanho: {(arquivo.size / 1024).toFixed(2)} KB</p>
          <p>Tipo: {arquivo.type}</p>
        </div>
      )}
    </div>
  );
}

Upload Múltiplo com Drag & Drop

function UploadMultiplo() {
  const [arquivos, setArquivos] = useState([]);
  const [arrastando, setArrastando] = useState(false);

  const handleDrop = (e) => {
    e.preventDefault();
    setArrastando(false);
    
    const files = Array.from(e.dataTransfer.files);
    processarArquivos(files);
  };

  const handleFileSelect = (e) => {
    const files = Array.from(e.target.files);
    processarArquivos(files);
  };

  const processarArquivos = (files) => {
    const novosArquivos = files.map(file => ({
      id: Date.now() + Math.random(),
      file,
      nome: file.name,
      tamanho: file.size,
      tipo: file.type,
      progresso: 0,
      status: 'pendente'
    }));
    
    setArquivos(prev => [...prev, ...novosArquivos]);
    
    // Simular upload
    novosArquivos.forEach(arquivo => {
      simularUpload(arquivo.id);
    });
  };

  const simularUpload = (id) => {
    let progresso = 0;
    const interval = setInterval(() => {
      progresso += 10;
      
      setArquivos(prev => prev.map(arquivo => {
        if (arquivo.id === id) {
          if (progresso >= 100) {
            clearInterval(interval);
            return { ...arquivo, progresso: 100, status: 'completo' };
          }
          return { ...arquivo, progresso };
        }
        return arquivo;
      }));
    }, 200);
  };

  const removerArquivo = (id) => {
    setArquivos(prev => prev.filter(arquivo => arquivo.id !== id));
  };

  return (
    <div>
      <div
        onDrop={handleDrop}
        onDragOver={(e) => {
          e.preventDefault();
          setArrastando(true);
        }}
        onDragLeave={() => setArrastando(false)}
        style={{
          border: `2px dashed ${arrastando ? '#2196f3' : '#ccc'}`,
          borderRadius: '8px',
          padding: '40px',
          textAlign: 'center',
          backgroundColor: arrastando ? '#e3f2fd' : '#f5f5f5',
          transition: 'all 0.3s'
        }}
      >
        <p>Arraste arquivos aqui ou</p>
        <input
          type="file"
          multiple
          onChange={handleFileSelect}
          style={{ display: 'none' }}
          id="file-input"
        />
        <label htmlFor="file-input" style={{
          cursor: 'pointer',
          color: '#2196f3',
          textDecoration: 'underline'
        }}>
          clique para selecionar
        </label>
      </div>

      <div style={{ marginTop: '20px' }}>
        {arquivos.map(arquivo => (
          <div key={arquivo.id} style={{
            border: '1px solid #ddd',
            padding: '10px',
            marginBottom: '10px',
            borderRadius: '4px'
          }}>
            <div style={{ display: 'flex', justifyContent: 'space-between' }}>
              <span>{arquivo.nome}</span>
              <button onClick={() => removerArquivo(arquivo.id)}>×</button>
            </div>
            <div style={{
              height: '4px',
              backgroundColor: '#e0e0e0',
              borderRadius: '2px',
              marginTop: '5px',
              overflow: 'hidden'
            }}>
              <div style={{
                height: '100%',
                width: `${arquivo.progresso}%`,
                backgroundColor: arquivo.status === 'completo' ? '#4caf50' : '#2196f3',
                transition: 'width 0.3s'
              }} />
            </div>
            <small>
              {arquivo.status === 'completo' ? 'Concluído' : `${arquivo.progresso}%`}
            </small>
          </div>
        ))}
      </div>
    </div>
  );
}

Campos Dinâmicos

Lista de Itens Dinâmica

function ListaDinamica() {
  const [itens, setItens] = useState([
    { id: 1, nome: '', quantidade: 1, preco: 0 }
  ]);

  const adicionarItem = () => {
    const novoItem = {
      id: Date.now(),
      nome: '',
      quantidade: 1,
      preco: 0
    };
    setItens([...itens, novoItem]);
  };

  const removerItem = (id) => {
    if (itens.length > 1) {
      setItens(itens.filter(item => item.id !== id));
    }
  };

  const atualizarItem = (id, campo, valor) => {
    setItens(itens.map(item => {
      if (item.id === id) {
        return { ...item, [campo]: valor };
      }
      return item;
    }));
  };

  const calcularTotal = () => {
    return itens.reduce((total, item) => {
      return total + (item.quantidade * item.preco);
    }, 0);
  };

  return (
    <div>
      <h3>Lista de Compras</h3>
      
      {itens.map((item, index) => (
        <div key={item.id} style={{
          display: 'grid',
          gridTemplateColumns: '3fr 1fr 1fr auto',
          gap: '10px',
          marginBottom: '10px',
          alignItems: 'center'
        }}>
          <input
            type="text"
            placeholder="Nome do item"
            value={item.nome}
            onChange={(e) => atualizarItem(item.id, 'nome', e.target.value)}
          />
          
          <input
            type="number"
            placeholder="Qtd"
            min="1"
            value={item.quantidade}
            onChange={(e) => atualizarItem(item.id, 'quantidade', parseInt(e.target.value))}
          />
          
          <input
            type="number"
            placeholder="Preço"
            min="0"
            step="0.01"
            value={item.preco}
            onChange={(e) => atualizarItem(item.id, 'preco', parseFloat(e.target.value))}
          />
          
          <button
            onClick={() => removerItem(item.id)}
            disabled={itens.length === 1}
          >
            Remover
          </button>
        </div>
      ))}
      
      <button onClick={adicionarItem}>
        + Adicionar Item
      </button>
      
      <div style={{ marginTop: '20px', fontSize: '18px' }}>
        <strong>Total: R$ {calcularTotal().toFixed(2)}</strong>
      </div>
    </div>
  );
}

Formulário de Endereços Múltiplos

function EnderecosMultiplos() {
  const [enderecos, setEnderecos] = useState([{
    id: 1,
    tipo: 'residencial',
    cep: '',
    rua: '',
    numero: '',
    complemento: '',
    bairro: '',
    cidade: '',
    estado: '',
    principal: true
  }]);

  const adicionarEndereco = () => {
    const novoEndereco = {
      id: Date.now(),
      tipo: 'residencial',
      cep: '',
      rua: '',
      numero: '',
      complemento: '',
      bairro: '',
      cidade: '',
      estado: '',
      principal: false
    };
    setEnderecos([...enderecos, novoEndereco]);
  };

  const removerEndereco = (id) => {
    const enderecosRestantes = enderecos.filter(end => end.id !== id);
    
    // Se removeu o principal, tornar o primeiro como principal
    if (enderecos.find(e => e.id === id)?.principal && enderecosRestantes.length > 0) {
      enderecosRestantes[0].principal = true;
    }
    
    setEnderecos(enderecosRestantes);
  };

  const atualizarEndereco = (id, campo, valor) => {
    setEnderecos(enderecos.map(endereco => {
      if (endereco.id === id) {
        // Se marcou como principal, desmarcar os outros
        if (campo === 'principal' && valor === true) {
          enderecos.forEach(e => {
            if (e.id !== id) e.principal = false;
          });
        }
        return { ...endereco, [campo]: valor };
      }
      return endereco;
    }));
  };

  const buscarCEP = async (id, cep) => {
    if (cep.length === 8) {
      try {
        const response = await fetch(`https://viacep.com.br/ws/${cep}/json/`);
        const data = await response.json();
        
        if (!data.erro) {
          setEnderecos(enderecos.map(endereco => {
            if (endereco.id === id) {
              return {
                ...endereco,
                rua: data.logradouro,
                bairro: data.bairro,
                cidade: data.localidade,
                estado: data.uf
              };
            }
            return endereco;
          }));
        }
      } catch (error) {
        console.error('Erro ao buscar CEP:', error);
      }
    }
  };

  return (
    <div>
      <h3>Endereços</h3>
      
      {enderecos.map((endereco, index) => (
        <fieldset key={endereco.id} style={{ marginBottom: '20px' }}>
          <legend>
            Endereço {index + 1}
            {endereco.principal && <span> (Principal)</span>}
          </legend>
          
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '10px' }}>
            <div>
              <label>Tipo</label>
              <select
                value={endereco.tipo}
                onChange={(e) => atualizarEndereco(endereco.id, 'tipo', e.target.value)}
              >
                <option value="residencial">Residencial</option>
                <option value="comercial">Comercial</option>
                <option value="outro">Outro</option>
              </select>
            </div>
            
            <div>
              <label>CEP</label>
              <input
                type="text"
                value={endereco.cep}
                onChange={(e) => {
                  const valor = e.target.value.replace(/\D/g, '');
                  atualizarEndereco(endereco.id, 'cep', valor);
                  if (valor.length === 8) {
                    buscarCEP(endereco.id, valor);
                  }
                }}
                maxLength="8"
                placeholder="00000000"
              />
            </div>
            
            <div style={{ gridColumn: 'span 2' }}>
              <label>Rua</label>
              <input
                type="text"
                value={endereco.rua}
                onChange={(e) => atualizarEndereco(endereco.id, 'rua', e.target.value)}
              />
            </div>
            
            <div>
              <label>Número</label>
              <input
                type="text"
                value={endereco.numero}
                onChange={(e) => atualizarEndereco(endereco.id, 'numero', e.target.value)}
              />
            </div>
            
            <div>
              <label>Complemento</label>
              <input
                type="text"
                value={endereco.complemento}
                onChange={(e) => atualizarEndereco(endereco.id, 'complemento', e.target.value)}
              />
            </div>
            
            <div>
              <label>Bairro</label>
              <input
                type="text"
                value={endereco.bairro}
                onChange={(e) => atualizarEndereco(endereco.id, 'bairro', e.target.value)}
              />
            </div>
            
            <div>
              <label>Cidade</label>
              <input
                type="text"
                value={endereco.cidade}
                onChange={(e) => atualizarEndereco(endereco.id, 'cidade', e.target.value)}
              />
            </div>
            
            <div>
              <label>Estado</label>
              <input
                type="text"
                value={endereco.estado}
                onChange={(e) => atualizarEndereco(endereco.id, 'estado', e.target.value)}
                maxLength="2"
              />
            </div>
          </div>
          
          <div style={{ marginTop: '10px', display: 'flex', justifyContent: 'space-between' }}>
            <label>
              <input
                type="checkbox"
                checked={endereco.principal}
                onChange={(e) => atualizarEndereco(endereco.id, 'principal', e.target.checked)}
              />
              Endereço principal
            </label>
            
            {enderecos.length > 1 && (
              <button
                type="button"
                onClick={() => removerEndereco(endereco.id)}
                style={{ color: 'red' }}
              >
                Remover endereço
              </button>
            )}
          </div>
        </fieldset>
      ))}
      
      <button type="button" onClick={adicionarEndereco}>
        + Adicionar Endereço
      </button>
    </div>
  );
}

Formulário Multi-Step Completo

function FormularioMultiStep() {
  const [etapaAtual, setEtapaAtual] = useState(0);
  const [dadosFormulario, setDadosFormulario] = useState({
    // Etapa 1 - Dados Pessoais
    nome: '',
    email: '',
    telefone: '',
    dataNascimento: '',
    
    // Etapa 2 - Endereço
    cep: '',
    endereco: '',
    numero: '',
    cidade: '',
    estado: '',
    
    // Etapa 3 - Preferências
    interesses: [],
    newsletter: false,
    notificacoes: 'email',
    
    // Etapa 4 - Documentos
    documentos: []
  });

  const etapas = [
    { titulo: 'Dados Pessoais', componente: EtapaDadosPessoais },
    { titulo: 'Endereço', componente: EtapaEndereco },
    { titulo: 'Preferências', componente: EtapaPreferencias },
    { titulo: 'Documentos', componente: EtapaDocumentos },
    { titulo: 'Confirmação', componente: EtapaConfirmacao }
  ];

  const proximaEtapa = () => {
    if (etapaAtual < etapas.length - 1) {
      setEtapaAtual(etapaAtual + 1);
    }
  };

  const etapaAnterior = () => {
    if (etapaAtual > 0) {
      setEtapaAtual(etapaAtual - 1);
    }
  };

  const atualizarDados = (novosDados) => {
    setDadosFormulario({ ...dadosFormulario, ...novosDados });
  };

  const enviarFormulario = () => {
    console.log('Formulário enviado:', dadosFormulario);
    // Processar envio
  };

  const EtapaComponente = etapas[etapaAtual].componente;

  return (
    <div style={{ maxWidth: '600px', margin: '0 auto' }}>
      {/* Indicador de Progresso */}
      <div style={{ marginBottom: '30px' }}>
        <div style={{ display: 'flex', justifyContent: 'space-between' }}>
          {etapas.map((etapa, index) => (
            <div
              key={index}
              style={{
                flex: 1,
                textAlign: 'center',
                position: 'relative'
              }}
            >
              <div
                style={{
                  width: '30px',
                  height: '30px',
                  borderRadius: '50%',
                  backgroundColor: index <= etapaAtual ? '#4caf50' : '#e0e0e0',
                  color: 'white',
                  display: 'flex',
                  alignItems: 'center',
                  justifyContent: 'center',
                  margin: '0 auto',
                  fontWeight: 'bold'
                }}
              >
                {index < etapaAtual ? '✓' : index + 1}
              </div>
              <small style={{ marginTop: '5px', display: 'block' }}>
                {etapa.titulo}
              </small>
              
              {index < etapas.length - 1 && (
                <div
                  style={{
                    position: 'absolute',
                    top: '15px',
                    left: '50%',
                    width: '100%',
                    height: '2px',
                    backgroundColor: index < etapaAtual ? '#4caf50' : '#e0e0e0',
                    zIndex: -1
                  }}
                />
              )}
            </div>
          ))}
        </div>
      </div>

      {/* Conteúdo da Etapa */}
      <div style={{ minHeight: '300px' }}>
        <h2>{etapas[etapaAtual].titulo}</h2>
        <EtapaComponente
          dados={dadosFormulario}
          atualizarDados={atualizarDados}
        />
      </div>

      {/* Botões de Navegação */}
      <div style={{
        display: 'flex',
        justifyContent: 'space-between',
        marginTop: '30px'
      }}>
        <button
          onClick={etapaAnterior}
          disabled={etapaAtual === 0}
          style={{
            visibility: etapaAtual === 0 ? 'hidden' : 'visible'
          }}
        >
          Anterior
        </button>
        
        {etapaAtual === etapas.length - 1 ? (
          <button
            onClick={enviarFormulario}
            style={{
              backgroundColor: '#4caf50',
              color: 'white',
              padding: '10px 20px',
              border: 'none',
              borderRadius: '4px'
            }}
          >
            Enviar
          </button>
        ) : (
          <button onClick={proximaEtapa}>
            Próximo
          </button>
        )}
      </div>
    </div>
  );
}

// Componentes das Etapas (exemplos simplificados)
function EtapaDadosPessoais({ dados, atualizarDados }) {
  return (
    <div>
      <input
        type="text"
        placeholder="Nome completo"
        value={dados.nome}
        onChange={(e) => atualizarDados({ nome: e.target.value })}
      />
      {/* Outros campos... */}
    </div>
  );
}

function EtapaEndereco({ dados, atualizarDados }) {
  return (
    <div>
      <input
        type="text"
        placeholder="CEP"
        value={dados.cep}
        onChange={(e) => atualizarDados({ cep: e.target.value })}
      />
      {/* Outros campos... */}
    </div>
  );
}

function EtapaPreferencias({ dados, atualizarDados }) {
  return (
    <div>
      <label>
        <input
          type="checkbox"
          checked={dados.newsletter}
          onChange={(e) => atualizarDados({ newsletter: e.target.checked })}
        />
        Receber newsletter
      </label>
      {/* Outros campos... */}
    </div>
  );
}

function EtapaDocumentos({ dados, atualizarDados }) {
  return (
    <div>
      <p>Upload de documentos...</p>
      {/* Implementar upload */}
    </div>
  );
}

function EtapaConfirmacao({ dados }) {
  return (
    <div>
      <h3>Confirme seus dados:</h3>
      <pre>{JSON.stringify(dados, null, 2)}</pre>
    </div>
  );
}
3

Projeto: Sistema de Inscrição Completo

Crie um sistema de inscrição com todas as técnicas aprendidas

Activity

Projeto: Sistema de Inscrição Completo

Objetivo

Criar um sistema completo de inscrição para um evento/curso com:

  • Formulário multi-step
  • Upload de documentos
  • Campos dinâmicos
  • Validação completa
  • Integração com APIs

Requisitos do Sistema

Etapa 1: Dados Pessoais

  • Nome completo
  • Email
  • CPF
  • Data de nascimento
  • Telefone
  • Foto de perfil (upload)

Etapa 2: Dados Profissionais

  • Empresa atual
  • Cargo
  • Tempo de experiência
  • Habilidades (dinâmicas)
  • LinkedIn
  • Currículo (upload PDF)

Etapa 3: Formação Acadêmica

  • Formações (dinâmicas)
    • Instituição
    • Curso
    • Início/Fim
    • Diploma (upload)

Etapa 4: Preferências

  • Áreas de interesse
  • Disponibilidade de horário
  • Modalidade preferida
  • Necessidades especiais

Etapa 5: Pagamento

  • Tipo de inscrição
  • Cupom de desconto
  • Dados de pagamento
  • Comprovante (upload)

Etapa 6: Confirmação

  • Resumo de todos os dados
  • Termos e condições
  • Enviar inscrição

Template Inicial

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

function SistemaInscricao() {
  const [etapaAtual, setEtapaAtual] = useState(0);
  const [dadosInscricao, setDadosInscricao] = useState({
    // Dados Pessoais
    dadosPessoais: {
      nome: '',
      email: '',
      cpf: '',
      dataNascimento: '',
      telefone: '',
      fotoPerfil: null
    },
    // Dados Profissionais
    dadosProfissionais: {
      empresa: '',
      cargo: '',
      tempoExperiencia: '',
      habilidades: [],
      linkedin: '',
      curriculo: null
    },
    // Formação
    formacoes: [],
    // Preferências
    preferencias: {
      areasInteresse: [],
      disponibilidade: [],
      modalidade: '',
      necessidadesEspeciais: ''
    },
    // Pagamento
    pagamento: {
      tipoInscricao: '',
      cupom: '',
      metodoPagamento: '',
      comprovante: null
    },
    // Controle
    aceitouTermos: false
  });

  // Seu código aqui

  return (
    <div>
      {/* Implemente o sistema aqui */}
    </div>
  );
}

export default SistemaInscricao;

Funcionalidades Esperadas

  1. Navegação entre etapas

    • Botões avançar/voltar
    • Indicador de progresso visual
    • Salvar progresso no localStorage
  2. Validação por etapa

    • Não permitir avançar com erros
    • Mostrar erros específicos
    • Validação de CPF real
  3. Upload de arquivos

    • Preview de imagens
    • Limite de tamanho
    • Tipos permitidos
    • Progress bar
  4. Campos dinâmicos

    • Adicionar/remover formações
    • Adicionar/remover habilidades
    • Mínimo e máximo de itens
  5. Integrações

    • Buscar CEP
    • Validar cupom de desconto
    • Simular processamento de pagamento

Solução Completa

Clique para ver a solução completa
import React, { useState, useEffect } from 'react';

// Hook customizado para persistência
function useLocalStorage(key, initialValue) {
  const [value, setValue] = useState(() => {
    try {
      const item = window.localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      return initialValue;
    }
  });

  useEffect(() => {
    try {
      window.localStorage.setItem(key, JSON.stringify(value));
    } catch (error) {
      console.error('Erro ao salvar no localStorage:', error);
    }
  }, [key, value]);

  return [value, setValue];
}

// Componente Principal
function SistemaInscricao() {
  const [etapaAtual, setEtapaAtual] = useState(0);
  const [dadosInscricao, setDadosInscricao] = useLocalStorage('inscricao', {
    dadosPessoais: {
      nome: '',
      email: '',
      cpf: '',
      dataNascimento: '',
      telefone: '',
      fotoPerfil: null
    },
    dadosProfissionais: {
      empresa: '',
      cargo: '',
      tempoExperiencia: '',
      habilidades: [],
      linkedin: '',
      curriculo: null
    },
    formacoes: [],
    preferencias: {
      areasInteresse: [],
      disponibilidade: [],
      modalidade: '',
      necessidadesEspeciais: ''
    },
    pagamento: {
      tipoInscricao: '',
      cupom: '',
      cupomValidado: false,
      desconto: 0,
      metodoPagamento: '',
      comprovante: null
    },
    aceitouTermos: false
  });

  const [errosEtapa, setErrosEtapa] = useState({});
  const [processando, setProcessando] = useState(false);

  const etapas = [
    { titulo: 'Dados Pessoais', componente: EtapaDadosPessoais },
    { titulo: 'Dados Profissionais', componente: EtapaDadosProfissionais },
    { titulo: 'Formação', componente: EtapaFormacao },
    { titulo: 'Preferências', componente: EtapaPreferencias },
    { titulo: 'Pagamento', componente: EtapaPagamento },
    { titulo: 'Confirmação', componente: EtapaConfirmacao }
  ];

  const validarEtapa = () => {
    const validadores = [
      validarDadosPessoais,
      validarDadosProfissionais,
      validarFormacao,
      validarPreferencias,
      validarPagamento,
      validarConfirmacao
    ];

    const erros = validadores[etapaAtual](dadosInscricao);
    setErrosEtapa(erros);
    return Object.keys(erros).length === 0;
  };

  const proximaEtapa = () => {
    if (validarEtapa() && etapaAtual < etapas.length - 1) {
      setEtapaAtual(etapaAtual + 1);
      setErrosEtapa({});
    }
  };

  const etapaAnterior = () => {
    if (etapaAtual > 0) {
      setEtapaAtual(etapaAtual - 1);
      setErrosEtapa({});
    }
  };

  const atualizarDados = (categoria, dados) => {
    setDadosInscricao(prev => {
      if (categoria) {
        return {
          ...prev,
          [categoria]: { ...prev[categoria], ...dados }
        };
      }
      return { ...prev, ...dados };
    });
  };

  const enviarInscricao = async () => {
    if (!dadosInscricao.aceitouTermos) {
      setErrosEtapa({ termos: 'Você deve aceitar os termos' });
      return;
    }

    setProcessando(true);
    
    // Simular envio
    await new Promise(resolve => setTimeout(resolve, 3000));
    
    console.log('Inscrição enviada:', dadosInscricao);
    alert('Inscrição realizada com sucesso!');
    
    // Limpar dados
    localStorage.removeItem('inscricao');
    window.location.reload();
  };

  const EtapaComponente = etapas[etapaAtual].componente;

  return (
    <div style={{ maxWidth: '800px', margin: '0 auto', padding: '20px' }}>
      <h1>Sistema de Inscrição</h1>

      {/* Progress Bar */}
      <div style={{ marginBottom: '40px' }}>
        <div style={{ 
          display: 'flex', 
          justifyContent: 'space-between',
          position: 'relative'
        }}>
          {etapas.map((etapa, index) => (
            <div key={index} style={{ 
              flex: 1, 
              textAlign: 'center',
              position: 'relative',
              zIndex: 1
            }}>
              <div style={{
                width: '40px',
                height: '40px',
                borderRadius: '50%',
                backgroundColor: index <= etapaAtual ? '#4caf50' : '#e0e0e0',
                color: 'white',
                display: 'flex',
                alignItems: 'center',
                justifyContent: 'center',
                margin: '0 auto',
                fontWeight: 'bold',
                cursor: index < etapaAtual ? 'pointer' : 'default'
              }}
              onClick={() => index < etapaAtual && setEtapaAtual(index)}
              >
                {index < etapaAtual ? '✓' : index + 1}
              </div>
              <small style={{ marginTop: '8px', display: 'block' }}>
                {etapa.titulo}
              </small>
            </div>
          ))}
          
          {/* Linha de progresso */}
          <div style={{
            position: 'absolute',
            top: '20px',
            left: '20px',
            right: '20px',
            height: '2px',
            backgroundColor: '#e0e0e0',
            zIndex: 0
          }}>
            <div style={{
              width: `${(etapaAtual / (etapas.length - 1)) * 100}%`,
              height: '100%',
              backgroundColor: '#4caf50',
              transition: 'width 0.3s'
            }} />
          </div>
        </div>
      </div>

      {/* Conteúdo da Etapa */}
      <div style={{ 
        minHeight: '400px',
        border: '1px solid #ddd',
        borderRadius: '8px',
        padding: '30px',
        marginBottom: '20px'
      }}>
        <h2>{etapas[etapaAtual].titulo}</h2>
        <EtapaComponente
          dados={dadosInscricao}
          atualizarDados={atualizarDados}
          erros={errosEtapa}
        />
      </div>

      {/* Botões de Navegação */}
      <div style={{ display: 'flex', justifyContent: 'space-between' }}>
        <button
          onClick={etapaAnterior}
          disabled={etapaAtual === 0}
          style={{
            padding: '10px 20px',
            visibility: etapaAtual === 0 ? 'hidden' : 'visible'
          }}
        >
          ← Anterior
        </button>

        {etapaAtual === etapas.length - 1 ? (
          <button
            onClick={enviarInscricao}
            disabled={processando}
            style={{
              padding: '10px 30px',
              backgroundColor: '#4caf50',
              color: 'white',
              border: 'none',
              borderRadius: '4px',
              cursor: processando ? 'not-allowed' : 'pointer'
            }}
          >
            {processando ? 'Enviando...' : 'Finalizar Inscrição'}
          </button>
        ) : (
          <button
            onClick={proximaEtapa}
            style={{
              padding: '10px 20px',
              backgroundColor: '#2196f3',
              color: 'white',
              border: 'none',
              borderRadius: '4px'
            }}
          >
            Próximo →
          </button>
        )}
      </div>
    </div>
  );
}

// Etapa 1: Dados Pessoais
function EtapaDadosPessoais({ dados, atualizarDados, erros }) {
  const [previewFoto, setPreviewFoto] = useState('');

  const handleFotoChange = (e) => {
    const file = e.target.files[0];
    if (file) {
      const reader = new FileReader();
      reader.onloadend = () => {
        setPreviewFoto(reader.result);
        atualizarDados('dadosPessoais', { 
          fotoPerfil: reader.result 
        });
      };
      reader.readAsDataURL(file);
    }
  };

  const formatarCPF = (valor) => {
    const numero = valor.replace(/\D/g, '');
    if (numero.length <= 11) {
      return numero.replace(
        /(\d{3})(\d{3})(\d{3})(\d{2})/,
        '$1.$2.$3-$4'
      ).substring(0, 14);
    }
    return valor;
  };

  const formatarTelefone = (valor) => {
    const numero = valor.replace(/\D/g, '');
    if (numero.length <= 11) {
      return numero.replace(
        /(\d{2})(\d{5})(\d{4})/,
        '($1) $2-$3'
      ).substring(0, 15);
    }
    return valor;
  };

  return (
    <div>
      <div style={{ marginBottom: '20px', textAlign: 'center' }}>
        <div style={{
          width: '150px',
          height: '150px',
          borderRadius: '50%',
          backgroundColor: '#f0f0f0',
          margin: '0 auto',
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          overflow: 'hidden',
          border: '2px solid #ddd'
        }}>
          {previewFoto || dados.dadosPessoais.fotoPerfil ? (
            <img 
              src={previewFoto || dados.dadosPessoais.fotoPerfil} 
              alt="Foto de perfil"
              style={{ width: '100%', height: '100%', objectFit: 'cover' }}
            />
          ) : (
            <span style={{ color: '#999' }}>Foto</span>
          )}
        </div>
        <input
          type="file"
          accept="image/*"
          onChange={handleFotoChange}
          style={{ marginTop: '10px' }}
        />
        {erros.fotoPerfil && <span style={{ color: 'red' }}>{erros.fotoPerfil}</span>}
      </div>

      <div style={{ display: 'grid', gap: '15px' }}>
        <div>
          <label>Nome Completo *</label>
          <input
            type="text"
            value={dados.dadosPessoais.nome}
            onChange={(e) => atualizarDados('dadosPessoais', { nome: e.target.value })}
            style={{ width: '100%', padding: '8px' }}
          />
          {erros.nome && <span style={{ color: 'red' }}>{erros.nome}</span>}
        </div>

        <div>
          <label>Email *</label>
          <input
            type="email"
            value={dados.dadosPessoais.email}
            onChange={(e) => atualizarDados('dadosPessoais', { email: e.target.value })}
            style={{ width: '100%', padding: '8px' }}
          />
          {erros.email && <span style={{ color: 'red' }}>{erros.email}</span>}
        </div>

        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '15px' }}>
          <div>
            <label>CPF *</label>
            <input
              type="text"
              value={dados.dadosPessoais.cpf}
              onChange={(e) => atualizarDados('dadosPessoais', { 
                cpf: formatarCPF(e.target.value) 
              })}
              maxLength="14"
              style={{ width: '100%', padding: '8px' }}
            />
            {erros.cpf && <span style={{ color: 'red' }}>{erros.cpf}</span>}
          </div>

          <div>
            <label>Data de Nascimento *</label>
            <input
              type="date"
              value={dados.dadosPessoais.dataNascimento}
              onChange={(e) => atualizarDados('dadosPessoais', { 
                dataNascimento: e.target.value 
              })}
              style={{ width: '100%', padding: '8px' }}
            />
            {erros.dataNascimento && <span style={{ color: 'red' }}>{erros.dataNascimento}</span>}
          </div>
        </div>

        <div>
          <label>Telefone *</label>
          <input
            type="text"
            value={dados.dadosPessoais.telefone}
            onChange={(e) => atualizarDados('dadosPessoais', { 
              telefone: formatarTelefone(e.target.value) 
            })}
            maxLength="15"
            style={{ width: '100%', padding: '8px' }}
          />
          {erros.telefone && <span style={{ color: 'red' }}>{erros.telefone}</span>}
        </div>
      </div>
    </div>
  );
}

// Etapa 2: Dados Profissionais
function EtapaDadosProfissionais({ dados, atualizarDados, erros }) {
  const [novaHabilidade, setNovaHabilidade] = useState('');

  const adicionarHabilidade = () => {
    if (novaHabilidade.trim()) {
      atualizarDados('dadosProfissionais', {
        habilidades: [...dados.dadosProfissionais.habilidades, novaHabilidade.trim()]
      });
      setNovaHabilidade('');
    }
  };

  const removerHabilidade = (index) => {
    const novasHabilidades = dados.dadosProfissionais.habilidades.filter(
      (_, i) => i !== index
    );
    atualizarDados('dadosProfissionais', { habilidades: novasHabilidades });
  };

  return (
    <div>
      <div style={{ display: 'grid', gap: '15px' }}>
        <div>
          <label>Empresa Atual *</label>
          <input
            type="text"
            value={dados.dadosProfissionais.empresa}
            onChange={(e) => atualizarDados('dadosProfissionais', { 
              empresa: e.target.value 
            })}
            style={{ width: '100%', padding: '8px' }}
          />
          {erros.empresa && <span style={{ color: 'red' }}>{erros.empresa}</span>}
        </div>

        <div style={{ display: 'grid', gridTemplateColumns: '2fr 1fr', gap: '15px' }}>
          <div>
            <label>Cargo *</label>
            <input
              type="text"
              value={dados.dadosProfissionais.cargo}
              onChange={(e) => atualizarDados('dadosProfissionais', { 
                cargo: e.target.value 
              })}
              style={{ width: '100%', padding: '8px' }}
            />
            {erros.cargo && <span style={{ color: 'red' }}>{erros.cargo}</span>}
          </div>

          <div>
            <label>Tempo de Experiência *</label>
            <select
              value={dados.dadosProfissionais.tempoExperiencia}
              onChange={(e) => atualizarDados('dadosProfissionais', { 
                tempoExperiencia: e.target.value 
              })}
              style={{ width: '100%', padding: '8px' }}
            >
              <option value="">Selecione</option>
              <option value="0-1">Menos de 1 ano</option>
              <option value="1-3">1 a 3 anos</option>
              <option value="3-5">3 a 5 anos</option>
              <option value="5-10">5 a 10 anos</option>
              <option value="10+">Mais de 10 anos</option>
            </select>
            {erros.tempoExperiencia && <span style={{ color: 'red' }}>{erros.tempoExperiencia}</span>}
          </div>
        </div>

        <div>
          <label>LinkedIn</label>
          <input
            type="url"
            value={dados.dadosProfissionais.linkedin}
            onChange={(e) => atualizarDados('dadosProfissionais', { 
              linkedin: e.target.value 
            })}
            placeholder="https://linkedin.com/in/seu-perfil"
            style={{ width: '100%', padding: '8px' }}
          />
        </div>

        <div>
          <label>Habilidades *</label>
          <div style={{ display: 'flex', gap: '10px', marginBottom: '10px' }}>
            <input
              type="text"
              value={novaHabilidade}
              onChange={(e) => setNovaHabilidade(e.target.value)}
              onKeyPress={(e) => e.key === 'Enter' && adicionarHabilidade()}
              placeholder="Digite uma habilidade"
              style={{ flex: 1, padding: '8px' }}
            />
            <button type="button" onClick={adicionarHabilidade}>
              Adicionar
            </button>
          </div>
          
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px' }}>
            {dados.dadosProfissionais.habilidades.map((habilidade, index) => (
              <span key={index} style={{
                backgroundColor: '#e3f2fd',
                padding: '5px 10px',
                borderRadius: '16px',
                display: 'flex',
                alignItems: 'center',
                gap: '5px'
              }}>
                {habilidade}
                <button
                  type="button"
                  onClick={() => removerHabilidade(index)}
                  style={{
                    background: 'none',
                    border: 'none',
                    color: '#666',
                    cursor: 'pointer',
                    padding: '0 5px'
                  }}
                >
                  ×
                </button>
              </span>
            ))}
          </div>
          {erros.habilidades && <span style={{ color: 'red' }}>{erros.habilidades}</span>}
        </div>

        <div>
          <label>Currículo (PDF) *</label>
          <input
            type="file"
            accept=".pdf"
            onChange={(e) => {
              const file = e.target.files[0];
              if (file) {
                const reader = new FileReader();
                reader.onloadend = () => {
                  atualizarDados('dadosProfissionais', { 
                    curriculo: {
                      nome: file.name,
                      tamanho: file.size,
                      dados: reader.result
                    }
                  });
                };
                reader.readAsDataURL(file);
              }
            }}
          />
          {dados.dadosProfissionais.curriculo && (
            <small>
              Arquivo: {dados.dadosProfissionais.curriculo.nome} 
              ({(dados.dadosProfissionais.curriculo.tamanho / 1024).toFixed(2)} KB)
            </small>
          )}
          {erros.curriculo && <span style={{ color: 'red' }}>{erros.curriculo}</span>}
        </div>
      </div>
    </div>
  );
}

// Etapa 3: Formação Acadêmica
function EtapaFormacao({ dados, atualizarDados, erros }) {
  const adicionarFormacao = () => {
    const novaFormacao = {
      id: Date.now(),
      instituicao: '',
      curso: '',
      nivel: '',
      dataInicio: '',
      dataFim: '',
      emAndamento: false,
      diploma: null
    };
    
    atualizarDados(null, { 
      formacoes: [...dados.formacoes, novaFormacao] 
    });
  };

  const atualizarFormacao = (id, campo, valor) => {
    const formacoesAtualizadas = dados.formacoes.map(formacao => {
      if (formacao.id === id) {
        return { ...formacao, [campo]: valor };
      }
      return formacao;
    });
    
    atualizarDados(null, { formacoes: formacoesAtualizadas });
  };

  const removerFormacao = (id) => {
    const formacoesAtualizadas = dados.formacoes.filter(
      formacao => formacao.id !== id
    );
    atualizarDados(null, { formacoes: formacoesAtualizadas });
  };

  return (
    <div>
      {dados.formacoes.length === 0 && (
        <p style={{ textAlign: 'center', color: '#666' }}>
          Nenhuma formação adicionada ainda.
        </p>
      )}

      {dados.formacoes.map((formacao, index) => (
        <fieldset key={formacao.id} style={{ 
          marginBottom: '20px', 
          padding: '15px',
          border: '1px solid #ddd',
          borderRadius: '4px'
        }}>
          <legend>Formação {index + 1}</legend>
          
          <div style={{ display: 'grid', gap: '15px' }}>
            <div>
              <label>Instituição *</label>
              <input
                type="text"
                value={formacao.instituicao}
                onChange={(e) => atualizarFormacao(formacao.id, 'instituicao', e.target.value)}
                style={{ width: '100%', padding: '8px' }}
              />
            </div>

            <div style={{ display: 'grid', gridTemplateColumns: '2fr 1fr', gap: '15px' }}>
              <div>
                <label>Curso *</label>
                <input
                  type="text"
                  value={formacao.curso}
                  onChange={(e) => atualizarFormacao(formacao.id, 'curso', e.target.value)}
                  style={{ width: '100%', padding: '8px' }}
                />
              </div>

              <div>
                <label>Nível *</label>
                <select
                  value={formacao.nivel}
                  onChange={(e) => atualizarFormacao(formacao.id, 'nivel', e.target.value)}
                  style={{ width: '100%', padding: '8px' }}
                >
                  <option value="">Selecione</option>
                  <option value="tecnico">Técnico</option>
                  <option value="graduacao">Graduação</option>
                  <option value="pos-graduacao">Pós-graduação</option>
                  <option value="mestrado">Mestrado</option>
                  <option value="doutorado">Doutorado</option>
                </select>
              </div>
            </div>

            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '15px' }}>
              <div>
                <label>Data de Início *</label>
                <input
                  type="date"
                  value={formacao.dataInicio}
                  onChange={(e) => atualizarFormacao(formacao.id, 'dataInicio', e.target.value)}
                  style={{ width: '100%', padding: '8px' }}
                />
              </div>

              <div>
                <label>Data de Conclusão</label>
                <input
                  type="date"
                  value={formacao.dataFim}
                  onChange={(e) => atualizarFormacao(formacao.id, 'dataFim', e.target.value)}
                  disabled={formacao.emAndamento}
                  style={{ width: '100%', padding: '8px' }}
                />
              </div>
            </div>

            <label>
              <input
                type="checkbox"
                checked={formacao.emAndamento}
                onChange={(e) => atualizarFormacao(formacao.id, 'emAndamento', e.target.checked)}
              />
              Cursando atualmente
            </label>

            <div>
              <label>Diploma/Certificado</label>
              <input
                type="file"
                accept=".pdf,.jpg,.jpeg,.png"
                onChange={(e) => {
                  const file = e.target.files[0];
                  if (file) {
                    const reader = new FileReader();
                    reader.onloadend = () => {
                      atualizarFormacao(formacao.id, 'diploma', {
                        nome: file.name,
                        dados: reader.result
                      });
                    };
                    reader.readAsDataURL(file);
                  }
                }}
              />
              {formacao.diploma && <small>Arquivo: {formacao.diploma.nome}</small>}
            </div>

            <button
              type="button"
              onClick={() => removerFormacao(formacao.id)}
              style={{ color: 'red' }}
            >
              Remover esta formação
            </button>
          </div>
        </fieldset>
      ))}

      <button type="button" onClick={adicionarFormacao}>
        + Adicionar Formação
      </button>

      {erros.formacoes && <span style={{ color: 'red' }}>{erros.formacoes}</span>}
    </div>
  );
}

// Etapa 4: Preferências
function EtapaPreferencias({ dados, atualizarDados, erros }) {
  const areasDisponiveis = [
    'Desenvolvimento Web',
    'Mobile',
    'Data Science',
    'DevOps',
    'UX/UI Design',
    'Inteligência Artificial',
    'Segurança',
    'Cloud Computing'
  ];

  const horariosDisponiveis = [
    'Manhã (8h-12h)',
    'Tarde (13h-17h)',
    'Noite (18h-22h)',
    'Fins de semana'
  ];

  const toggleArea = (area) => {
    const areas = dados.preferencias.areasInteresse;
    if (areas.includes(area)) {
      atualizarDados('preferencias', {
        areasInteresse: areas.filter(a => a !== area)
      });
    } else {
      atualizarDados('preferencias', {
        areasInteresse: [...areas, area]
      });
    }
  };

  const toggleHorario = (horario) => {
    const horarios = dados.preferencias.disponibilidade;
    if (horarios.includes(horario)) {
      atualizarDados('preferencias', {
        disponibilidade: horarios.filter(h => h !== horario)
      });
    } else {
      atualizarDados('preferencias', {
        disponibilidade: [...horarios, horario]
      });
    }
  };

  return (
    <div>
      <div style={{ marginBottom: '20px' }}>
        <h3>Áreas de Interesse *</h3>
        <p style={{ color: '#666', fontSize: '14px' }}>
          Selecione pelo menos 2 áreas de interesse
        </p>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: '10px' }}>
          {areasDisponiveis.map(area => (
            <label key={area} style={{ display: 'flex', alignItems: 'center' }}>
              <input
                type="checkbox"
                checked={dados.preferencias.areasInteresse.includes(area)}
                onChange={() => toggleArea(area)}
                style={{ marginRight: '8px' }}
              />
              {area}
            </label>
          ))}
        </div>
        {erros.areasInteresse && <span style={{ color: 'red' }}>{erros.areasInteresse}</span>}
      </div>

      <div style={{ marginBottom: '20px' }}>
        <h3>Disponibilidade de Horário *</h3>
        <p style={{ color: '#666', fontSize: '14px' }}>
          Selecione os horários em que você pode participar
        </p>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: '10px' }}>
          {horariosDisponiveis.map(horario => (
            <label key={horario} style={{ display: 'flex', alignItems: 'center' }}>
              <input
                type="checkbox"
                checked={dados.preferencias.disponibilidade.includes(horario)}
                onChange={() => toggleHorario(horario)}
                style={{ marginRight: '8px' }}
              />
              {horario}
            </label>
          ))}
        </div>
        {erros.disponibilidade && <span style={{ color: 'red' }}>{erros.disponibilidade}</span>}
      </div>

      <div style={{ marginBottom: '20px' }}>
        <label>Modalidade Preferida *</label>
        <select
          value={dados.preferencias.modalidade}
          onChange={(e) => atualizarDados('preferencias', { 
            modalidade: e.target.value 
          })}
          style={{ width: '100%', padding: '8px' }}
        >
          <option value="">Selecione</option>
          <option value="presencial">Presencial</option>
          <option value="online">Online</option>
          <option value="hibrido">Híbrido</option>
        </select>
        {erros.modalidade && <span style={{ color: 'red' }}>{erros.modalidade}</span>}
      </div>

      <div>
        <label>Necessidades Especiais</label>
        <textarea
          value={dados.preferencias.necessidadesEspeciais}
          onChange={(e) => atualizarDados('preferencias', { 
            necessidadesEspeciais: e.target.value 
          })}
          placeholder="Descreva se você tem alguma necessidade especial de acessibilidade..."
          rows="4"
          style={{ width: '100%', padding: '8px' }}
        />
      </div>
    </div>
  );
}

// Etapa 5: Pagamento
function EtapaPagamento({ dados, atualizarDados, erros }) {
  const [validandoCupom, setValidandoCupom] = useState(false);

  const tiposInscricao = [
    { id: 'estudante', nome: 'Estudante', valor: 97.00 },
    { id: 'profissional', nome: 'Profissional', valor: 197.00 },
    { id: 'empresa', nome: 'Empresa', valor: 297.00 }
  ];

  const validarCupom = async () => {
    if (!dados.pagamento.cupom) return;
    
    setValidandoCupom(true);
    
    // Simular validação de cupom
    await new Promise(resolve => setTimeout(resolve, 1000));
    
    // Cupons de exemplo
    const cuponsValidos = {
      'DESCONTO10': 10,
      'PRIMEIRA20': 20,
      'ESPECIAL50': 50
    };
    
    const desconto = cuponsValidos[dados.pagamento.cupom.toUpperCase()];
    
    if (desconto) {
      atualizarDados('pagamento', {
        cupomValidado: true,
        desconto: desconto
      });
    } else {
      atualizarDados('pagamento', {
        cupomValidado: false,
        desconto: 0
      });
      alert('Cupom inválido!');
    }
    
    setValidandoCupom(false);
  };

  const calcularValorFinal = () => {
    const tipo = tiposInscricao.find(t => t.id === dados.pagamento.tipoInscricao);
    if (!tipo) return 0;
    
    const valor = tipo.valor;
    const desconto = dados.pagamento.desconto || 0;
    return valor - (valor * desconto / 100);
  };

  return (
    <div>
      <div style={{ marginBottom: '20px' }}>
        <h3>Tipo de Inscrição *</h3>
        <div style={{ display: 'grid', gap: '10px' }}>
          {tiposInscricao.map(tipo => (
            <label 
              key={tipo.id} 
              style={{ 
                display: 'flex', 
                alignItems: 'center',
                padding: '15px',
                border: '2px solid',
                borderColor: dados.pagamento.tipoInscricao === tipo.id ? '#2196f3' : '#ddd',
                borderRadius: '4px',
                cursor: 'pointer'
              }}
            >
              <input
                type="radio"
                name="tipoInscricao"
                value={tipo.id}
                checked={dados.pagamento.tipoInscricao === tipo.id}
                onChange={(e) => atualizarDados('pagamento', { 
                  tipoInscricao: e.target.value 
                })}
                style={{ marginRight: '10px' }}
              />
              <div>
                <strong>{tipo.nome}</strong>
                <span style={{ marginLeft: '10px', color: '#666' }}>
                  R$ {tipo.valor.toFixed(2)}
                </span>
              </div>
            </label>
          ))}
        </div>
        {erros.tipoInscricao && <span style={{ color: 'red' }}>{erros.tipoInscricao}</span>}
      </div>

      <div style={{ marginBottom: '20px' }}>
        <label>Cupom de Desconto</label>
        <div style={{ display: 'flex', gap: '10px' }}>
          <input
            type="text"
            value={dados.pagamento.cupom}
            onChange={(e) => atualizarDados('pagamento', { 
              cupom: e.target.value.toUpperCase() 
            })}
            placeholder="Digite o cupom"
            style={{ flex: 1, padding: '8px' }}
          />
          <button 
            type="button" 
            onClick={validarCupom}
            disabled={validandoCupom || !dados.pagamento.cupom}
          >
            {validandoCupom ? 'Validando...' : 'Aplicar'}
          </button>
        </div>
        {dados.pagamento.cupomValidado && (
          <span style={{ color: 'green' }}>
            Cupom aplicado! {dados.pagamento.desconto}% de desconto
          </span>
        )}
      </div>

      <div style={{ marginBottom: '20px' }}>
        <h3>Método de Pagamento *</h3>
        <div style={{ display: 'grid', gap: '10px' }}>
          <label>
            <input
              type="radio"
              name="metodoPagamento"
              value="boleto"
              checked={dados.pagamento.metodoPagamento === 'boleto'}
              onChange={(e) => atualizarDados('pagamento', { 
                metodoPagamento: e.target.value 
              })}
            />
            Boleto Bancário
          </label>
          <label>
            <input
              type="radio"
              name="metodoPagamento"
              value="cartao"
              checked={dados.pagamento.metodoPagamento === 'cartao'}
              onChange={(e) => atualizarDados('pagamento', { 
                metodoPagamento: e.target.value 
              })}
            />
            Cartão de Crédito
          </label>
          <label>
            <input
              type="radio"
              name="metodoPagamento"
              value="pix"
              checked={dados.pagamento.metodoPagamento === 'pix'}
              onChange={(e) => atualizarDados('pagamento', { 
                metodoPagamento: e.target.value 
              })}
            />
            PIX
          </label>
        </div>
        {erros.metodoPagamento && <span style={{ color: 'red' }}>{erros.metodoPagamento}</span>}
      </div>

      <div style={{ marginBottom: '20px' }}>
        <label>Comprovante de Pagamento</label>
        <input
          type="file"
          accept=".pdf,.jpg,.jpeg,.png"
          onChange={(e) => {
            const file = e.target.files[0];
            if (file) {
              const reader = new FileReader();
              reader.onloadend = () => {
                atualizarDados('pagamento', { 
                  comprovante: {
                    nome: file.name,
                    dados: reader.result
                  }
                });
              };
              reader.readAsDataURL(file);
            }
          }}
        />
        {dados.pagamento.comprovante && (
          <small>Arquivo: {dados.pagamento.comprovante.nome}</small>
        )}
      </div>

      <div style={{ 
        padding: '20px', 
        backgroundColor: '#f5f5f5', 
        borderRadius: '4px',
        marginTop: '20px'
      }}>
        <h3>Resumo do Pagamento</h3>
        {dados.pagamento.tipoInscricao && (
          <div>
            <div style={{ display: 'flex', justifyContent: 'space-between' }}>
              <span>Inscrição:</span>
              <span>
                {tiposInscricao.find(t => t.id === dados.pagamento.tipoInscricao)?.nome}
              </span>
            </div>
            <div style={{ display: 'flex', justifyContent: 'space-between' }}>
              <span>Valor original:</span>
              <span>
                R$ {tiposInscricao.find(t => t.id === dados.pagamento.tipoInscricao)?.valor.toFixed(2)}
              </span>
            </div>
            {dados.pagamento.desconto > 0 && (
              <div style={{ display: 'flex', justifyContent: 'space-between', color: 'green' }}>
                <span>Desconto ({dados.pagamento.desconto}%):</span>
                <span>
                  -R$ {(tiposInscricao.find(t => t.id === dados.pagamento.tipoInscricao)?.valor * dados.pagamento.desconto / 100).toFixed(2)}
                </span>
              </div>
            )}
            <hr />
            <div style={{ display: 'flex', justifyContent: 'space-between', fontWeight: 'bold' }}>
              <span>Total:</span>
              <span>R$ {calcularValorFinal().toFixed(2)}</span>
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

// Etapa 6: Confirmação
function EtapaConfirmacao({ dados, atualizarDados, erros }) {
  return (
    <div>
      <h3>Revise seus dados antes de finalizar:</h3>
      
      <div style={{ marginBottom: '20px' }}>
        <h4>Dados Pessoais</h4>
        <div style={{ backgroundColor: '#f5f5f5', padding: '15px', borderRadius: '4px' }}>
          <p><strong>Nome:</strong> {dados.dadosPessoais.nome}</p>
          <p><strong>Email:</strong> {dados.dadosPessoais.email}</p>
          <p><strong>CPF:</strong> {dados.dadosPessoais.cpf}</p>
          <p><strong>Telefone:</strong> {dados.dadosPessoais.telefone}</p>
          <p><strong>Data de Nascimento:</strong> {dados.dadosPessoais.dataNascimento}</p>
        </div>
      </div>

      <div style={{ marginBottom: '20px' }}>
        <h4>Dados Profissionais</h4>
        <div style={{ backgroundColor: '#f5f5f5', padding: '15px', borderRadius: '4px' }}>
          <p><strong>Empresa:</strong> {dados.dadosProfissionais.empresa}</p>
          <p><strong>Cargo:</strong> {dados.dadosProfissionais.cargo}</p>
          <p><strong>Experiência:</strong> {dados.dadosProfissionais.tempoExperiencia}</p>
          <p><strong>Habilidades:</strong> {dados.dadosProfissionais.habilidades.join(', ')}</p>
        </div>
      </div>

      <div style={{ marginBottom: '20px' }}>
        <h4>Formação Acadêmica</h4>
        <div style={{ backgroundColor: '#f5f5f5', padding: '15px', borderRadius: '4px' }}>
          {dados.formacoes.map((formacao, index) => (
            <div key={formacao.id} style={{ marginBottom: '10px' }}>
              <p><strong>Formação {index + 1}:</strong></p>
              <p>{formacao.curso} - {formacao.instituicao}</p>
              <p>{formacao.nivel} ({formacao.emAndamento ? 'Em andamento' : `Concluído em ${formacao.dataFim}`})</p>
            </div>
          ))}
        </div>
      </div>

      <div style={{ marginBottom: '20px' }}>
        <h4>Preferências</h4>
        <div style={{ backgroundColor: '#f5f5f5', padding: '15px', borderRadius: '4px' }}>
          <p><strong>Áreas de Interesse:</strong> {dados.preferencias.areasInteresse.join(', ')}</p>
          <p><strong>Disponibilidade:</strong> {dados.preferencias.disponibilidade.join(', ')}</p>
          <p><strong>Modalidade:</strong> {dados.preferencias.modalidade}</p>
        </div>
      </div>

      <div style={{ marginBottom: '20px' }}>
        <h4>Pagamento</h4>
        <div style={{ backgroundColor: '#f5f5f5', padding: '15px', borderRadius: '4px' }}>
          <p><strong>Tipo de Inscrição:</strong> {dados.pagamento.tipoInscricao}</p>
          <p><strong>Método de Pagamento:</strong> {dados.pagamento.metodoPagamento}</p>
          {dados.pagamento.cupom && <p><strong>Cupom:</strong> {dados.pagamento.cupom} ({dados.pagamento.desconto}% desconto)</p>}
        </div>
      </div>

      <div style={{ 
        marginTop: '30px', 
        padding: '20px', 
        backgroundColor: '#fff3cd', 
        borderRadius: '4px' 
      }}>
        <label>
          <input
            type="checkbox"
            checked={dados.aceitouTermos}
            onChange={(e) => atualizarDados(null, { aceitouTermos: e.target.checked })}
          />
          Li e aceito os termos e condições de inscrição
        </label>
        {erros.termos && <span style={{ color: 'red', display: 'block' }}>{erros.termos}</span>}
      </div>
    </div>
  );
}

// Funções de Validação
function validarCPF(cpf) {
  const cpfLimpo = cpf.replace(/\D/g, '');
  
  if (cpfLimpo.length !== 11) return false;
  if (/^(\d)\1{10}$/.test(cpfLimpo)) return false;
  
  let soma = 0;
  for (let i = 0; i < 9; i++) {
    soma += parseInt(cpfLimpo.charAt(i)) * (10 - i);
  }
  
  let resto = 11 - (soma % 11);
  if (resto === 10 || resto === 11) resto = 0;
  if (resto !== parseInt(cpfLimpo.charAt(9))) return false;
  
  soma = 0;
  for (let i = 0; i < 10; i++) {
    soma += parseInt(cpfLimpo.charAt(i)) * (11 - i);
  }
  
  resto = 11 - (soma % 11);
  if (resto === 10 || resto === 11) resto = 0;
  if (resto !== parseInt(cpfLimpo.charAt(10))) return false;
  
  return true;
}

function validarDadosPessoais(dados) {
  const erros = {};
  
  if (!dados.dadosPessoais.nome) {
    erros.nome = 'Nome obrigatório';
  }
  
  if (!dados.dadosPessoais.email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(dados.dadosPessoais.email)) {
    erros.email = 'Email inválido';
  }
  
  if (!dados.dadosPessoais.cpf || !validarCPF(dados.dadosPessoais.cpf)) {
    erros.cpf = 'CPF inválido';
  }
  
  if (!dados.dadosPessoais.dataNascimento) {
    erros.dataNascimento = 'Data de nascimento obrigatória';
  }
  
  if (!dados.dadosPessoais.telefone) {
    erros.telefone = 'Telefone obrigatório';
  }
  
  if (!dados.dadosPessoais.fotoPerfil) {
    erros.fotoPerfil = 'Foto obrigatória';
  }
  
  return erros;
}

function validarDadosProfissionais(dados) {
  const erros = {};
  
  if (!dados.dadosProfissionais.empresa) {
    erros.empresa = 'Empresa obrigatória';
  }
  
  if (!dados.dadosProfissionais.cargo) {
    erros.cargo = 'Cargo obrigatório';
  }
  
  if (!dados.dadosProfissionais.tempoExperiencia) {
    erros.tempoExperiencia = 'Tempo de experiência obrigatório';
  }
  
  if (dados.dadosProfissionais.habilidades.length < 3) {
    erros.habilidades = 'Adicione pelo menos 3 habilidades';
  }
  
  if (!dados.dadosProfissionais.curriculo) {
    erros.curriculo = 'Currículo obrigatório';
  }
  
  return erros;
}

function validarFormacao(dados) {
  const erros = {};
  
  if (dados.formacoes.length === 0) {
    erros.formacoes = 'Adicione pelo menos uma formação';
  }
  
  return erros;
}

function validarPreferencias(dados) {
  const erros = {};
  
  if (dados.preferencias.areasInteresse.length < 2) {
    erros.areasInteresse = 'Selecione pelo menos 2 áreas';
  }
  
  if (dados.preferencias.disponibilidade.length === 0) {
    erros.disponibilidade = 'Selecione pelo menos um horário';
  }
  
  if (!dados.preferencias.modalidade) {
    erros.modalidade = 'Selecione uma modalidade';
  }
  
  return erros;
}

function validarPagamento(dados) {
  const erros = {};
  
  if (!dados.pagamento.tipoInscricao) {
    erros.tipoInscricao = 'Selecione um tipo de inscrição';
  }
  
  if (!dados.pagamento.metodoPagamento) {
    erros.metodoPagamento = 'Selecione um método de pagamento';
  }
  
  return erros;
}

function validarConfirmacao(dados) {
  const erros = {};
  
  if (!dados.aceitouTermos) {
    erros.termos = 'Você deve aceitar os termos';
  }
  
  return erros;
}

export default SistemaInscricao;

Desafios Extras

  1. Integração Real com APIs

    • Busca de CEP real
    • Upload para servidor
    • Validação de cupom via API
  2. Melhorias de UX

    • Animações entre etapas
    • Preview de PDF
    • Crop de imagem de perfil
  3. Segurança

    • Criptografia de dados sensíveis
    • Validação no servidor
    • Rate limiting
  4. Acessibilidade

    • Navegação por teclado
    • Screen reader friendly
    • Alto contraste
  5. Mobile

    • Design responsivo
    • Touch friendly
    • Câmera para uploads
3 content items