Skip to main content

Subtask 05 — Criação da Vitrine de Estoque da Loja (sem tela intermediária)

Task pai: 197313 — Ajuste de layout nova vitrine Ordem de execução: 05 de 07 Depende de: 01b, 03, 04 — a tela de detalhe precisa já saber renderizar e tratar ShowCaseType.sellerStock corretamente antes de ganhar um modo de criação que termina exibindo exatamente essa tela.

Objetivo

Implementar o fluxo de criação da Vitrine de Estoque da Loja sem nenhuma tela/controller/rota nova: a própria ShowCaseDetailScreen/ShowCaseDetailController ganham um modo de criação (isCreating), que faz POST (criação) encadeado com GET (carregamento completo), reaproveitando o skeleton de loading e introduzindo um estado de erro com retry (mesma dinâmica do UpsellRecommendationScreen).

Requisitos atendidos

  • RF-03 — Criação da Vitrine de Estoque da Loja: AC1 a AC7.

Relação com o design doc

  • Decisão #3 — Criação da Vitrine de Estoque da Loja — Sem Tela Intermediária (desing-doc.md): contém o código completo de ShowCaseDetailScreenArguments, MyShowCaseController.createSellerStock(), ShowCaseDetailController.onInit()/createAndLoad()/retryCreate().
  • Contrato atualizado (context/frontend-contract-diff.md): o POST não retorna mais erro de duplicata — comportamento "get-or-create" (retorna os dados da vitrine existente com 200 OK). O único caminho de erro tratado aqui é falha inesperada (rede, 5xx).
  • Ver também context/fluxo-pos-criacao-e-dependencia-rewards.md (achado que documenta a decisão completa).

Arquivos a modificar

ArquivoModificação
lib/screens/show_case/show_case_detail/show_case_detail_screen.dartShowCaseDetailScreenArguments ganha catalogId opcional (String?) e isCreating (bool, default false). Tela passa a checar controller.hasError.value (antes de isLoading), renderizando ZzErrorState (title/description genéricos, retryText: 'TENTE NOVAMENTE', onRetry: controller.retryCreate) no lugar do ShowCaseDetailLayout quando hasError == true.
lib/screens/show_case/show_case_detail/show_case_detail_controller.dart+ isLoading (RxBool), + hasError (RxBool), + createAndLoad() (POST com showCaseType: ShowCaseType.sellerStock, name='Estoque da loja', showCaseItems=[], dateExpiration=hoje+30 dias, demais campos obrigatórios; encadeia com loadData() usando o id retornado), + retryCreate(). onInit() ramifica por arguments.isCreating (chama createAndLoad() ou loadData()).
lib/screens/show_case/show_case/my_show_case_controller.dart+ createSellerStock(): navega para AppRoutes.storeShowCaseDetail com ShowCaseDetailScreenArguments(catalogName: 'Estoque da loja', isCreating: true); ao voltar, recarrega a listagem (mesmo padrão de goToDetailFastCatalog()).

Testes unitários a criar

  • test/screens/show_case/show_case_detail/show_case_detail_controller_test.dart (mesma suíte das subtasks 03/04, adicionando)
    • onInit() com arguments.isCreating == true → chama createAndLoad() (não loadData() diretamente)
    • onInit() com arguments.isCreating == false (default) → chama loadData() normalmente (sem regressão do fluxo existente)
    • createAndLoad(): monta CreateShowCaseRequest com showCaseType: ShowCaseType.sellerStock, name: 'Estoque da loja', showCaseItems: [], dateExpiration = hoje + 30 dias
    • createAndLoad() sucesso: extrai id de CreateShowCaseResponse, encadeia loadData() com esse id; ao final, detail.value populado, isLoading == false, hasError == false
    • createAndLoad() sucesso com dados de vitrine já existente (contrato get-or-create) → tratado como sucesso normal, sem diferenciação
    • createAndLoad() erro inesperado (POST falha) → hasError == true, isLoading == false
    • retryCreate() → chama createAndLoad() novamente
    • enableEditButton com detail.value == null (durante loading ou erro) → false (garantindo que nenhuma ação dependente dispare aviso nesse meio-tempo — usado pela subtask 07)
  • test/screens/show_case/show_case/my_show_case_controller_test.dart
    • createSellerStock(): navega para AppRoutes.storeShowCaseDetail com arguments.isCreating == true e catalogId == null
    • createSellerStock(): ao retornar da navegação, _hasNextPage é resetado e a listagem é recarregada (mesmo padrão de goToDetailFastCatalog())

Critérios de aceite (RF-03)

  1. Selecionar Vitrine do estoque da loja no bottom sheet (com hasSellerStock = false) navega diretamente para a tela de detalhe em modo de criação, sem tela intermediária.
  2. A tela de detalhe em modo de criação envia POST /api/show-case-new com showCaseType = "SellerStock", name = "Estoque da loja", showCaseItems = [], dateExpiration = hoje + 30 dias, e os demais campos obrigatórios de CreateShowCaseRequest.
  3. Durante o POST, o App exibe o estado de carregamento (skeleton) já usado na tela de detalhe.
  4. Sucesso no POST (inclusive get-or-create) → usa o id retornado para carregar o detalhe completo via GET, renderizando a tela normalmente.
  5. Erro inesperado no POST → estado de erro genérico com botão de tentar novamente (retryCreate() reenvia o POST).
  6. Nenhuma etapa de busca/seleção de produtos, nem tela intermediária com campos de nome/data.
  7. Nenhum reward event de criação é registrado (aguardando task 197192).

Definição de Pronto (Definition of Done)

  • Nenhuma tela/controller/rota nova criada — apenas adaptação da ShowCaseDetailScreen/Controller e um novo método em MyShowCaseController.
  • Fluxo POST + GET encadeado funcionando, com loading e erro cobertos.
  • flutter analyze sem erros novos.
  • flutter test executando os testes listados acima, 100% verdes.
  • Projeto compila.
  • Fluxo de visualização de vitrine existente (isCreating = false) sem nenhuma regressão.