Skip to main content

Achado — Fluxo de criação do SellerStock não tem tela intermediária; detalhe ganha modo "criar"

Decisão do design doc afetada: #3 — Tela de Criação SellerStock — Novo Fluxo (substituída por completo) Requisito relacionado: RF-03 (reescrito por completo, ver requisitos) Status: Resolvido

O que o design doc propunha (ponto de partida)

On sucesso: navega para showCaseDetail OU mostra ShowCaseBottomSheet (ações pós-criação).

O "OU" indicava que a decisão não tinha sido tomada. Investigação inicial partiu do precedente já existente em ShowCaseSearchProductsController.postFastCatalog() (lib/screens/show_case/search/show_case_search_products_controller.dart:393-488), que hoje sempre mostra ShowCaseBottomSheet após criar uma vitrine personalizada (nunca navega direto pro detalhe). Esse precedente motivou o bloqueio original identificado abaixo — mas a decisão final tomada com o usuário seguiu por um caminho diferente e mais simples (ver "Resolução final").

Bloqueio original identificado (superado pela decisão final)

ShowCaseBottomSheet (lib/screens/show_case/show_case_bottom_sheet.dart:34-47) tem viewedEvent, sharedEvent e copiedEvent como parâmetros obrigatórios, do tipo RewardEvent. Só existem classes de evento para o tipo "Store" hoje. A US 196053 (CA-6) exige eventos específicos de Rewards para SellerStock, mas essa integração está fora de escopo desta task (coberta pela task 197192, pendente). Isso bloquearia a construção literal do ShowCaseBottomSheet no fluxo de criação — mas deixou de ser relevante porque a decisão final não usa mais esse widget no fluxo de criação (ver abaixo).

Resolução final

Não existe tela intermediária de criação. Ao tocar em "Vitrine do estoque da loja" no bottom sheet (com hasSellerStock == false), o App navega diretamente para ShowCaseDetailScreen (reaproveitando a rota/tela existente, AppRoutes.storeShowCaseDetail), em um novo modo de criação:

  1. ShowCaseDetailScreenArguments ganha um novo campo de modo (create/view).
  2. POST /api/show-case-new retorna só {id, url} (CreateShowCaseResponse, create_show_case_response.dart:3-18) — não o shape completo de ShowCaseDetailResponse. Por isso, em modo "criar", o controller faz POST primeiro (dados fixos: name='Estoque da loja', showCaseType=4, dateExpiration=hoje+30 dias — limite próprio desta modalidade, ver decisoes-menores-limpeza-e-dtos.md —, showCaseItems=[]), pega o id da resposta, e encadeia com o loadData()/GET normal (GET /api/show-case-new/app/{id}) — populando a tela exatamente como uma vitrine já existente.
  3. Skeleton durante o carregamento: reaproveita o loading existente (_DefaultLoadingState / searchState == SearchState.searching), cobrindo tanto o POST quanto o GET encadeado.
  4. Contrato do POST atualizado (ver context/frontend-contract-diff.md): quando já existe uma vitrine SellerStock ativa para (userId, storeId), a API não retorna erro — retorna 200 OK com os dados da vitrine existente ("get-or-create"). Do ponto de vista do App, criação e "já existia" são o mesmo caminho de sucesso; não há distinção nem mensagem de "duplicata".
  5. Erro (agora só cenários inesperados — rede, 5xx, etc., já que duplicata deixou de ser um erro): tela de detalhe ganha um estado de erro dedicado, mesma dinâmica do UpsellRecommendationScreen (upsell_recommendation_screen.dart:55-67 + upsell_recommendation_controller.dart:32-33,211-217,239-244): flags isLoading/hasError (novas, já que SearchState não tem variante de erro), renderiza ZzErrorState (title, description, retryText: 'TENTE NOVAMENTE', onRetry: () => controller.retry()). Mensagem sempre genérica (não diferencia tipo de erro).
  6. Onde vive a lógica do POST: MyShowCaseController ganha um método novo (chamado a partir do callback do bottom sheet), reaproveitando o acesso que o controller já tem a store/user/loja. Esse método deve seguir o mesmo padrão de goToDetailFastCatalog(): ao voltar da tela de detalhe, resetar _hasNextPage = true e pagingController.value = PagingState(), recarregando a primeira página (lista e hasSellerStock atualizados).

Consequências:

  • Elimina inteiramente os arquivos show_case_seller_stock_screen.dart e show_case_seller_stock_controller.dart, e a rota AppRoutes.showCaseSellerStock — não fazem mais parte do escopo.
  • ShowCaseBottomSheet deixa de ser usado no fluxo de criação SellerStock — não há bottom sheet de ações pós-criação neste fluxo; a tela de detalhe já tem essas 3 ações (Visualizar/Compartilhar/Copiar) nativamente.
  • Reward events nativos do detalhe (viewShowCase/shareShowCase/copyLink, hoje classes "Store"): quando showCaseType == 4, não registrar nenhum reward event (condicionar as chamadas a rewardEventController.register(...) a showCaseType == 1). Evita rotular ações de SellerStock como "Store" nas métricas, até a task 197192 (pendente) definir os eventos específicos.
  • Reward event de criação (CreateShowcaseRewardEvent, hoje registrado em postFastCatalog() para Store): pela mesma consistência, não registrar nenhum evento de criação para SellerStock. MyShowCaseController não precisa ganhar RewardEventController como nova dependência só por causa disso.
  • RF-03 foi reescrito por completo no documento de requisitos para refletir esse fluxo.

Todos os pontos confirmados com o usuário na sessão de grilling.