Skip to main content

Design research — coezzion_vendas_app

Data: 2026-07-09
US: 197021
Repo: /Users/alt-zz/projetos/arezzo/coezzion_vendas_app
Base spike: research-zzapp.md

Pesquisa file-level para implementação do PR2. Nenhum código alterado nesta fase.


1. Resumo executivo

ÁreaGap principalAção design
ZZDateFormFieldSem ação de limpar dataallowClear + onClear
Minhas listShowCaseResponseItem non-null parseNullable + nullExpirationLabel
Minhas updateUpdateShowCaseRequest required + fallback +31Nullable; null explícito no clear
Minhas detailCampo oculto se dateExpiration == nullSempre exibir picker
Recommend create/editToast obrigatório se nullPermitir submit com null
Recommend editSem finalDateRange no pickerAlinhar max +31 com create

2. Widget compartilhado

Arquivo: lib/theme_widgets/date_form_field/zz_date_form_field.dart

AspectoAS-IS
selectedDateDateTime?
onChangedvoid Function(DateTime) — não aceita clear
Clear UXInexistente
Ícone sufixoApenas calendário

Referência UX portal: coezzion-portal/src/routes/Vitrine/ListShowcase/EditShowcase/index.tsx — placeholder "Sem data de expiração".

TO-BE: parâmetros opcionais allowClear, onClear, clearedHint (default "Sem data de expiração"); ícone X ou ação no picker para limpar.


3. Minhas vitrines (Store)

Fluxo create

ArquivoResponsabilidadeGap
show_case/my_show_case_controller.dart L85setCreateMode()OK
search/show_case_search_products_controller.dartexpirationDate, create POSTDefault +31 em create mode
show_case_check_products/widgets/check_fast_catalog_product_list.dart L59–63ZZDateFormFieldmax +31; sem clear
models/show_case/create_show_case_request.dartDateTime? dateExpirationJá serializa null — OK

Fluxo edit

ArquivoGap
show_case_detail/show_case_detail_screen.dart L157–185if (dateExpiration != null) esconde campo
show_case_detail/show_case_detail_controller.dart L243Fallback ?? DateTime.now().add(31d) no update — conflita com clear→never
show_case_detail/show_case_detail_controller.dart L175–177Mesmo fallback no edit mode search

Listagem

ArquivoGap
my_show_case_list/my_show_case_list_screen.dart L89Sem nullExpirationLabel
models/show_case/show_case_response_item.dart L20asDateTimeOrThrow — quebra com null da API

Models

ModelCampoAS-ISTO-BE
UpdateShowCaseRequestdateExpirationDateTime requiredDateTime?
ShowCaseResponseItemexpirationDaterequiredDateTime?
ShowCaseDetailResponsedateExpirationjá nullableOK

4. Histórico de compras (Recommend)

Fluxo create

ArquivoGap
recommend_show_case_check_products_controller.dart L53–61Default +31 — manter
recommend_show_case_check_products_controller.dart L85–87Toast se null — remover
recommend_show_case_check_products_screen.dart L61–67Picker sem clear

Fluxo edit

ArquivoGap
recommend_show_case_detail_controller.dart L148–151Toast se null — remover
recommend_show_case_detail_screen.dart L180–184Sem finalDateRange; sem clear
updateExpirationDateSó aceita DateTime — precisa clearExpirationDate()

Listagem

ArquivoAS-IS
recommend_show_case_list_screen.dart L87–88Já passa nullExpirationLabel: 'Sem data de expiração'

Models

ModelTestes existentes
recommend_show_case_list_item.darttest/.../recommend_show_case_list_item_test.dart — null OK
recommend_show_case_detail_response.darttest/.../recommend_show_case_detail_response_test.dart — null OK
create_recommend_show_case_request.dartTeste só com data — adicionar null
update_recommend_show_case_request.dartTeste só com data — adicionar null

5. Widget de lista (reutilizável)

Arquivo: lib/screens/show_case/widgets/listItem.dart

final showExpiration = expirationDate != null || nullExpirationLabel != null;
final expirationText = expirationDate != null
? 'Data de expiração: ${MaskUtils.formatDateBr(expirationDate!)}'
: nullExpirationLabel ?? '';

CA-4 já suportado — basta passar nullExpirationLabel na lista Minhas.


6. APIs consumidas (sem mudança de endpoint)

Prefixo api/show-case-new via ApiUtils:

FluxoMétodoPayload dateExpiration TO-BE
Minhas createPOST /ISO ou null
Minhas updatePUT /ISO ou null
Recommend createPOST /recommendISO ou null
Recommend updatePUT /recommend/{id}ISO ou null

Dependência: PR1 API publicado antes do merge do app (RF-11).


7. Fallbacks a remover (crítico)

Estes trechos reaplicam +31 no client quando null e conflitam com RF-02/RF-03:

ArquivoLinhaTrecho
show_case_detail_controller.dartL243expirationDate.value ?? detail... ?? now+31
show_case_detail_controller.dartL175–177Idem no setEditMode

TO-BE: se usuário limpou → enviar null; se não alterou campo em vitrine sem prazo → enviar null; se preencheu data → enviar ISO.


8. Arquivos fora do escopo

  • brand_show_case_* — read-only; já usa nullExpirationLabel
  • show_case_screen.dart — hub; sem mudança de expiração
  • Share/copy flows — sem mudança (RF-05)

9. Decisões grill zzapp (2026-07-09)

Ver grill-decisions.md D-APP-8 a D-APP-15: detecção clear Minhas (dois PUT paths), ZZDateFormField parametrizável, JSON null explícito, picker Histórico min amanhã, deploy simultâneo, constantes centralizadas, testes models obrigatórios.


10. Smoke manual sugerido (pós-PR2)

  • Create Minhas sem limpar → expira ~+31
  • Create Minhas com clear → label "Sem data de expiração"
  • Edit Minhas: remover / adicionar data
  • Mesmos cenários Recommend
  • Share link vitrine never-expire