O sistema da sprint01 já permite cadastrar, listar e remover clientes com persistência local. Porém, os usuários precisam digitar o endereço manualmente — o que é lento e propenso a erros. Além disso, quando o sistema está "processando", não há nenhum feedback visual, deixando o usuário confuso.
O objetivo deste sprint é evoluir o sistema para consumir dados de uma API externa, implementar feedback visual de carregamento e orquestrar o fluxo de cadastro com operações assíncronas usando Promises e async/await.
Nesta sprint, o grupo deve aplicar:
fetch()para requisições HTTPasync/awaitpara fluxo linearnew Promise()para criar promessas customizadastry/catchpara tratamento de erros- Controle de estado da UI (desabilitar botão, feedback de carregamento)
- Integração de dados da API ao LocalStorage
Adicionar ao formulário da sprint01:
- CEP (obrigatório, texto)
- Logradouro (preenchido automaticamente, readonly)
- Bairro (preenchido automaticamente, readonly)
- Cidade (preenchido automaticamente, readonly)
- Estado / UF (preenchido automaticamente, readonly)
Ao sair do campo CEP (onblur ou oninput com 8 dígitos):
- Fazer requisição para a URL da ViaCEP informando o CEP
- Preencher automaticamente os campos de endereço com os dados retornados
- Mostrar um texto "Carregando endereço..." enquanto a requisição não finaliza
- Caso o CEP seja inválido (inexistente): exibir mensagem de erro no formulário
- Usar
async/awaitpara a requisição etry/catchpara capturar erros de rede
Ao clicar em "Salvar":
- O botão deve ser desabilitado (
disabled = true) - O texto do botão deve mudar para "Salvando..."
- Após finalizar (sucesso ou erro), o botão deve voltar ao normal
Antes de salvar o cliente, o sistema deve passar por uma etapa de "validação" que simula um processamento assíncrono:
- Criar uma Promise customizada que resolve após 2 segundos (usar
setTimeout) - A promise deve resolver com sucesso sempre (não precisa de rejeição)
- Acoplar esta promise no fluxo de salvamento usando
await
O evento de submit do formulário deve ser uma função async que executa em ordem:
- Validação local: Checar se os campos obrigatórios estão preenchidos (síncrono)
- Feedback visual: Desabilitar botão e mostrar "Salvando..."
- Promise customizada: Aguardar a promise de processamento (2 segundos)
- Salvar dados: Injetar no LocalStorage e no DOM
- Finalizar: Reabilitar o botão, limpar formulário
Cada cliente deve conter: id (numérico), nome, email, plano, cep, logradouro, bairro, cidade, uf (string).
- Se a API do ViaCEP falhar: exibir mensagem "Erro ao consultar CEP"
- Se ocorrer qualquer outro erro no fluxo: mensagem genérica amigável
- Usar
try/catchpara capturar todos os erros - O botão "Salvar" deve ser reabilitado em qualquer cenário (usar
finally)
- Todos os dados do cliente (incluindo endereço) salvos na chave
clientes_dbno LocalStorage - Ao carregar a página, reconstruir os cards automaticamente
- Botão "Remover" no card exclui do DOM e do LocalStorage
Usuário preenche formulário
│
▼
┌───────────────────┐
│ Validação local │ ← síncrono
│ (campos ok?) │
└───────┬───────────┘
│ inválido
▼ (exibe erro)
│ válido
▼
┌───────────────────┐
│ Desabilitar botão │
│ "Salvando..." │ ← UI feedback
└───────┬───────────┘
│
▼
┌───────────────────┐
│ simularProcessa- │ ← await Promise
│ mento() │ (setTimeout 2s)
└───────┬───────────┘
│
▼
┌───────────────────┐
│ Salvar no │
│ LocalStorage │ ← clientes_db
└───────┬───────────┘
│
▼
┌───────────────────┐
│ Atualizar DOM │ ← renderizar cards
│ Limpar formulário │
│ Reabilitar botão │ ← finally
└───────────────────┘
Em caso de erro em qualquer etapa, o fluxo pula direto para o catch, que exibe a mensagem de erro, e o finally reabilita o botão.
- Campos readonly podem ser estilizados com CSS (
input:read-only) - Botão desabilitado pode ter opacidade reduzida (
button:disabled) - Para limpar o CEP antes de buscar, remover caracteres não numéricos usando Expressão Regular
- A URL da ViaCEP segue o padrão:
https://viacep.com.br/ws/CEP_LIMPO/json/ - Verificar se a resposta contém a propriedade
erropara CEPs inválidos
A função que cria a Promise deve ter esta estrutura básica — o corpo (setTimeout e lógica de resolução) fica a cargo dos alunos:
function simularProcessamento() {
return new Promise((resolve) => {
// usar setTimeout para resolver após 2 segundos
});
}
async function buscarEndereco(cep) {
try {
// limpar CEP (remover caracteres não numéricos)
// se CEP não tiver 8 dígitos, sair da função
// setar campos de endereço como "Carregando..."
// fazer fetch para a URL da ViaCEP
// se resposta não for ok, lançar erro
// converter resposta para JSON
// se JSON conter "erro", lançar erro
// preencher campos (logradouro, bairro, localidade, uf)
} catch (erro) {
// exibir mensagem de erro
// limpar campos de endereço
}
}
A API retorna um JSON com esta estrutura. Use estes campos para preencher o formulário:
{
"cep": "01001-000",
"logradouro": "Praça da Sé",
"bairro": "Sé",
"localidade": "São Paulo",
"uf": "SP"
}A resposta também pode conter "erro": true caso o CEP não exista.
- Uso correto de
fetchpara consumir ViaCEP - Uso de
async/awaitno fluxo de cadastro - Criação de Promise customizada com
new Promise - Uso de
try/catch/finallypara tratamento de erros - Botão desabilitado e com feedback textual durante salvamento
- Integração correta do endereço ao LocalStorage
- Interface atualizada dinamicamente (cards, limpeza de formulário)
Ao cadastrar um cliente:
- Preencher CEP → endereço carregado automaticamente via API
- Clicar em "Salvar" → botão desabilita e mostra "Salvando..."
- Passa pela simulação de 2 segundos
- Cliente aparece na lista com endereço completo
- Recarregar a página → cliente continua salvo
- Remover → exclui do DOM e do LocalStorage
O sistema agora não é apenas um CRUD local — ele consome dados reais da internet, orquestra um fluxo assíncrono e dá feedback visual ao usuário durante o processamento.
A apresentação do projeto final acontecerá na última aula, no dia 27/05/2026. Cada grupo deverá demonstrar o funcionamento da aplicação e explicar brevemente as principais funcionalidades desenvolvidas.
O código-fonte do projeto deverá ser enviado por e-mail (rafepel@gmail.com) até 12h00 (meio-dia) do dia 27/05/2026.