From 9ac623a433fddb6ea0fafa4d1fa97f971f440821 Mon Sep 17 00:00:00 2001 From: nala Date: Thu, 22 Oct 2026 12:52:52 +0200 Subject: [PATCH] fix: preserve territorial search across investment catalogues --- .../unification/traceability-and-manual.md | 27 +++++++++++++++++++ .../v2/auditoria-portal/matriz-requisitos.csv | 4 +-- .../js/components/catalogue-navigation.tsx | 3 ++- .../js/components/portal-grouped-menu.tsx | 3 ++- resources/js/layouts/portal-navigation.tsx | 3 ++- resources/js/lib/catalogue-context.ts | 3 ++- resources/js/lib/search-territory.ts | 24 +++++++++++++++++ resources/js/pages/investment/catalogue.tsx | 6 +++-- resources/js/pages/investment/detail.tsx | 5 ++-- resources/js/pages/investment/zone.tsx | 5 ++-- resources/js/pages/investment/zones.tsx | 15 +++++++---- resources/js/pages/portfolio/index.tsx | 10 ++++--- resources/js/pages/portfolio/show.tsx | 7 ++--- tests/frontend/search-territory.test.mjs | 27 +++++++++++++++++++ 14 files changed, 118 insertions(+), 24 deletions(-) create mode 100644 resources/js/lib/search-territory.ts create mode 100644 tests/frontend/search-territory.test.mjs diff --git a/docs/investmoz/unification/traceability-and-manual.md b/docs/investmoz/unification/traceability-and-manual.md index 19bc9854..4eb4f4bc 100644 --- a/docs/investmoz/unification/traceability-and-manual.md +++ b/docs/investmoz/unification/traceability-and-manual.md @@ -2151,3 +2151,30 @@ Autorização expressa da Tempo executada. Main passou de `57fc9148` por avanço **Estado fiscal preservado:** nenhuma publicação/activação de nova regra e nenhuma operação na base activa. O consumidor IVA geral previamente autorizado manteve a mesma disponibilidade, cobertura2026 e mensagem antes/depois. As exclusões sectoriais, forma indirecta/dimensão monetária não determinada, benefícios territoriais e apuramento fiscal completo continuam explícitos e não bloqueiam o lote procedimental concluído. **Suspensão/recuperação:** desligar somente a chave do novo percurso e reconstruir cache/reiniciar graciosamente os workers mantém dossiers, documentos, respostas, versões, relatórios e históricos. Para reverter configuração, usar o valor anterior apenas depois de conferir o hash actual e preservar alterações posteriores; não substituir todo o .env sem conferir concorrência. A reversão de código/build segue o procedimento de releases já existente, sem restaurar dados antigos. A release anterior foi efectivamente conservada na primeira tentativa recusada. Recibo completo local em `outputs/investmoz-adaptive-path-delivery-20261022/delivery-receipt.json`; a presente actualização documental fica na branch de registo, sem novo push main ou nova disponibilização desnecessária. + + +## Revis?o das 30 fichas de Inhambane e cat?logo vazio ? 22/10/2026 + +Leitura remota autenticada, transac??o READ ONLY, base teste_investidor: 30 oportunidades em draft; zero publicadas em toda a base. As consultas independentes de Cabo Delgado e Inhambane e a consulta exacta Inhambane/Vilankulo devolveram zero sem falha de consulta. A alega??o de oportunidades publicadas de Cabo Delgado n?o se confirma neste destino; n?o inventar associa??es para preencher a lista. + +As 30 localiza??es permanecem nos recursos privados opportunity_location_drafts, referidos no cadastro can?nico; os campos e v?nculos p?blicos ainda n?o s?o a projec??o dessas fichas. A inexist?ncia desses v?nculos p?blicos em rascunhos n?o prova perda da localiza??o. Na publica??o, projectar somente a abrang?ncia documentada e conferir a pesquisa territorial. + +Decis?o Tempo nesta conversa: incompletude e autoriza??es necess?rias ? execu??o n?o s?o impedimentos autom?ticos ? divulga??o como oportunidade em prepara??o. Proposta: divulgar resumos das 30 fichas em prepara??o com fonte, edi??o, data-base e lacunas vis?veis; n?o declarar financiamento, terreno, licen?as, promotor autorizado ou execu??o confirmados. Valores hist?ricos, agregados e divergentes devem ser identificados sem somas indevidas. Nenhum impedimento concreto de divulga??o do resumo foi demonstrado nesta leitura. Isto n?o declara o conte?do privado integral public?vel: originais, contactos e evid?ncias continuam separados. N?o houve publica??o, altera??o de pap?is ou escrita remota. + +Prepara??o por ficha: outputs/investmoz-territory-recovery-20261022/publication-review.json (30 identidades reais, localiza??o privada, lacunas e valores). Evid?ncia: read-catalogue-remote.py e remote-read.log no mesmo direct?rio. A tabela hist?rica de lacunas de prepara??o ? reutilizada, sem a converter em bloqueios legais. A prepara??o t?cnica do fluxo de publica??o ainda deve reconciliar essas condi??es com o contrato existente; n?o marcar publica??o como pronta ou executada. + +O URL recebido ? do cat?logo/iniciar por territ?rio, n?o do dossier afectado. N?o permite ler o contexto inicial, a altera??o e a ?ltima ac??o desse processo. A falha da pr?via territorial e do t?rmino sem resposta continua aberta e ainda n?o foi reproduzida no dossier real; n?o encerrar pela disponibiliza??o anterior ou por esta leitura de cat?logo. + +## Continuidade territorial da pesquisa — correcção em QA, 22/10/2026 + +Esclarecimento da Tempo: o percurso reportado foi navegação pública entre carteira e catálogo, sem clicar em iniciar/continuar ideia. Não existe evidência de alteração de um dossier pessoal neste caso. Retira-se a exigência de URL do dossier e de confirmação de impacto; a alteração é de filtros de pesquisa. + +Causa verificada: ligações da carteira para oportunidades e zonas e ligações dos menus públicos usavam destinos sem província/distrito. O contexto transportado para detalhes por `catalogue_query` também não acompanhava as ligações cruzadas. No ecrã de zonas, os parâmetros de exportação/detalhe omitiam a hierarquia territorial. + +Correcção: `searchTerritoryHref` transporta exclusivamente os quatro níveis territoriais na URL entre carteira, oportunidades, zonas e educação, incluindo os respectivos detalhes. Reutiliza o `catalogue_query` existente e preserva os filtros próprios do destino. Uma selecção explícita de outro ascendente não herda descendentes incompatíveis. Sem armazenamento global, mistura de contas ou alteração de dossiers. Menus, navegação relacionada, breadcrumbs e ligações cruzadas usam a mesma função. O selector partilhado mantém a limpeza dos descendentes; não há confirmação adicional para pesquisar. + +Verificação dirigida: seis testes Node (incluindo o selector partilhado), TypeScript e build isolado. No navegador QA: carteira Cabo Delgado → selecção Inhambane/Vilankulo → pesquisar → catálogo com ambos os campos preenchidos; recarregamento e regresso preservam a selecção; zonas herdam os dois níveis; mudar para Cabo Delgado limpa Vilankulo. Contagem zero, filtros activos e mensagem de ausência coerentes na base QA consultada. Não foram repetidos cálculos ou exportadores fiscais nem publicados registos para produzir resultados artificiais. + +Provas: `outputs/investmoz-territory-recovery-20261022/before-carteira.png` e `after-catalogue.png` no workspace de entrega; testes em `tests/frontend/search-territory.test.mjs` e `territory-path.test.mjs`; logs QA `outputs/territory-types.log` e `territory-build.log`. O router privado QA selecciona o build isolado; não integra a candidata. + +Entrega limitada a branch/QA. A homologação não foi alterada por esta correcção. Publicação das 30 fichas de Inhambane permanece separada: revisão por ficha preparada, nenhuma publicação executada; ainda por reconciliar a preparação técnica da divulgação em preparação com o fluxo existente. A correcção da pesquisa não depende dessa publicação. diff --git a/docs/investmoz/v2/auditoria-portal/matriz-requisitos.csv b/docs/investmoz/v2/auditoria-portal/matriz-requisitos.csv index d7e0bd14..c6763943 100644 --- a/docs/investmoz/v2/auditoria-portal/matriz-requisitos.csv +++ b/docs/investmoz/v2/auditoria-portal/matriz-requisitos.csv @@ -4774,7 +4774,7 @@ AUD-OP-01,Guardar e recuperar rascunho incompleto; exclusão/arquivo/restauro,"P [RECONCILIACAO-43-20261019] Código e critérios confrontados com leitura READ ONLY fresca; PROVA-RECONCILIACAO-43-LEITURA.json, RECONCILIACAO-43-QA-FONTES.json, RECONCILIACAO-43-SCHEMA-QA.json. Não encerra critério funcional por inventário. -[PLANO-P1-P6-20261019] Plano Tempo: 27–46 h disponibilização; P7 e desenvolvimento separados. Inclusão 36–39 expressa para decisão; sem publicação automática. Revisão de proposta d87970e701f0. Roteiro no manual existente; não encerra critério por instalação.","oportunidades +[PLANO-P1-P6-20261019] Plano Tempo: 27–46 h disponibilização; P7 e desenvolvimento separados. Inclusão 36–39 expressa para decisão; sem publicação automática. Revisão de proposta d87970e701f0. Roteiro no manual existente; não encerra critério por instalação. | 22/10/2026 READ ONLY: 30 Inhambane draft; zero publicadas em teste_investidor. publication-review.json em outputs/investmoz-territory-recovery-20261022. Lacunas de estudos/licenciamento/financiamento nao impedem automaticamente divulgar em preparacao (Tempo). Nenhuma publicacao executada; fluxo de publicacao em preparacao ainda por reconciliar.","oportunidades [B QA 13/10/2026] Opção B aprovada em QA: ambito-B-aceitacao-QA.md. Sem nova ativação, regra ou módulo.",12/10/2026 — reconciliação e HTTP; nova inspeção visual bloqueada,,,"Restauro de oportunidade proposta R-ARCHIVE/R-DRAFT, sem implementação antecipada. Variantes por modalidade e contratos §25 ainda por critério, conforme tabela por categoria; Response§27 de compatibilidade com normative_response_complete=false (IDs/história/estados preservados). Interesse no anúncio público de negócio existente e outras variantes de país/estatística/mapa/documento têm consumidores separados.173correspondências eMandie/Guro; partilha individual de documentos de oportunidade não criada. Leitor de ecrã, PDF etiquetado e dispositivos reais pendentes. Sem fecho global por contagem de testes. @@ -10528,7 +10528,7 @@ AUD-LEG-06,"Preservar contexto ao entrar/regressar ao percurso, URLs existentes [RECONCILIACAO-43-20261019] Código e critérios confrontados com leitura READ ONLY fresca; PROVA-RECONCILIACAO-43-LEITURA.json, RECONCILIACAO-43-QA-FONTES.json, RECONCILIACAO-43-SCHEMA-QA.json. Não encerra critério funcional por inventário. -[PLANO-P1-P6-20261019] Plano Tempo: 27–46 h disponibilização; P7 e desenvolvimento separados. Inclusão 36–39 expressa para decisão; sem publicação automática. Revisão de proposta d87970e701f0. Roteiro no manual existente; não encerra critério por instalação. | 22/10/2026: primeiro incremento QA na branch codex/project-context-continuity-QA; contexto único por dossier/conta, herança com edições preservadas, moeda/IVA mensal e análise territorial explícita. Ver traceability-and-manual.md, secção Continuidade e adaptação contextual. 4 HTTP/74 asserções; 8 frontend; percurso visual A/B e nova sessão. Não encerra adaptação jurídica integral. | 22/10: revisão de a76369eb concluída no âmbito aceite por prova equivalente do regresso; A/B não repetidos. Tabela do primeiro percurso de investimento privado no manual: condições, artigos/período e efeitos; preparação documental, sem ligação executável nova. | 22/10/2026 — percurso privado executável em QA (base52fbb146): condições oficiais seleccionam mero registo/autorização, alternativas documentais e próximos passos; contexto C v4 mero registo após distinção directo/indirecto (Lei14/R13); prévia visual, vínculo inactivo preservado e relatório v3 por autorização conservado como histórico. 3 testes/96 asserções e um teste do novo relatório, tipos/build aprovados. Sem validação jurídica genérica adicional; orientação permanente Tempo em AGENTS. Branch codex/private-investment-path-executable-QA; sem integração main/alteração da homologação/activação fiscal. | 22/10/2026 — prova complementar exclusiva do relatório: recuperação UI do contexto v4, rascunho v5 e Word novo por mero registo; estudo/capacidade não aplicáveis. Word v3 preservado/identificado como histórico, hash inalterado. Sem alteração funcional ou repetição dos ensaios aceites. Dependências Git: a76369eb → 52fbb146 documental → a1fbda06; integrar após decisão, preservando main concorrente. | 22/10/2026 — disponibilizado por autorização Tempo: revisão servida042ffbde (inclui a76369eb/a1fbda06/064296e1 e correcção dirigida da recuperação legada). Percurso habilitado na homologação, versão private-investment-preparation-2026-v1; main ancestral preservado, sem conflitos/force-push. Zero migrations/importações/fixtures; nenhuma nova regra fiscal publicada/activada. Revisão/configuração/rotas conferidas; provas funcionais QA reutilizadas.",documentos e legado,15/10/2026 — fecho do piloto ativo e preparação por leitura dos restantes setores; sem novos testes funcionais.,,,"[Visual QA 10/10/2026] Cobertura integral, mais perfis/dispositivos, leitor de ecrã e editor administrativoC74 não demonstrados. Mercado Financeiro permanece privado/corpo vazio confirmado na origem; rotas404. Sem associação automática Turismo→cadastro territorial, sem fundir Energia/Mineração. | Histórico preservado: [Visual QA 10 /10/2026 ] Cobertura integral, mais perfis /dispositivos , leitor de ecrã e editor administrativo C74 não demonstrados. Mercado Financeiro permanece privado /corpo vazio confirmado na origem; rotas 404. Sem associação automática Turismo→cadastro territorial, sem fundir Energia /Mineração. | Histórico preservado: 17 caminhos com texto preservados incluindo agronegócio e 4 novos retornos; restante mapa URL /aliases/acervo ainda incompleto. C37 /QA18 e A /B não encerrados. | Histórico anterior: Contexto /retorno do piloto observados; mapa de migração dos restantes URL s ainda pendente. C37 /QA18 e cenários A /B completos não foram executados neste ensaio.",Biblioteca/documentos existentes; Balcão+09/190000 para dossier. Expansão cartográfica exige correspondências fundamentadas. C37/A-B/SLA/perfis e ativação mantêm âmbito próprio.,Mantido /agronegocio; /explorar/agronegocio novo. Referência comID/hash/versão/ator/data e retorno autorizado ao mesmo dossier; replay sem duplicação; cinco fases/19etapas conservadas.,"[Interface legado QA 10 /10/2026 ] Chromium instalado, contextos isolados, desktop 1440 px / móvel 390 px: fotografia /fontes/paleta , pesquisa hit /miss , Enter /foco de 3 px, links carteira /zonas/biblioteca/oportunidade. Promotor QA21 : login→MFA→dossier→fonte→retorno→logout→novo contexto /MFA →recuperação /F5 →associação repetida. Conta 23:403 e artigo público sem título privado; anónimo sem contexto privado. UI observada; referência /evento únicos e originais /hash/scan confirmados em leitura QA. legacy-content-browser-qa.json ; legacy-content-browser-persistence-qa.json ; legado-piloto-qa.md . | Evidência anterior preservada: legado-piloto-qa.md ; legacy-content-http-qa.json : recursos 6 /5 públicos, hashes verificados, pesquisa, login /MFA21 , criação /continuação , logout /nova sessão, recuperação, replay único e isolamento. Interface não observada. | [Confirmação manual recebida 10 /10/2026 ] Responsável confirmou leitura pública → autenticação → criar /escolher dossier → guardar referência → nova sessão → recuperar dossier e abrir artigo. Confirmação declarada, sem conta /perfil/dispositivo/data de execução identificados. Não comprova MFA específico, ensaios móveis, acessibilidade, outros perfis, deduplicação, C37 /QA18 ou A /B. Ver legado-piloto-qa.md , confirmação manual. | [Setores QA após C71 10 /10/2026 ] 22 originais importados privadamente após prévia renovada, hashes recuperados,22 scans ClamD reais e replay sem novos documentos /recursos/auditoria/scans. Divulgação autenticada separada:16 artigos com texto+5 imagens públicos; Mercado Financeiro privado, vazio confirmado na origem HTML e Inertia 200. Chromium desktop:16 artigos, pesquisa /imagens , Energia e Mineração distintas, C72 título preservado; QA21 criou 4 dossiers, retorno, logout /novaMFA/F5/replay ; QA23 negado 403 e anónimo sem contexto. Persistência READ ONLY:8 dossiers HTTP /Chromium , uma referência /evento cada,22 hashes únicos,0 relações geográficas automáticas. legacy-sectors-{apply,replay,http,browser,persistence} -qa.json ; legacy-financial-origin-20261010 /proof.json. C37 /QA18 ,A /B ,móvel /acessibilidade/cobertura integral não encerrados. | [Visual QA 10 /10/2026 ] Falhas C77 – C83 corrigidas em QA: landmarks, nome ARIA do mapa, hierarquia de títulos do texto legado sem alteraroriginal /hash , tabelas financeiras focáveis por teclado, reflow de tarefas /select/data no dossier, langpt-MZ apenas no router QA e proteção da recuperação assíncrona do simulador. Após correções 15 execuções axe /390 –320–1440 px,0 violações automáticas /0overflow e idioma PT; skiplink primeiro Tab→conteúdo em 3 páginas; tabelas financeiras focadas /teclas no Chromium . Não equivale a leitor de ecrã, zoom /dispositivo real ou cobertura de todo oportal. Legacy Content Test 5 /84 e rastreio MFA 1 /14 são provas específicas, não contagem substituta de percursos. visual-followup-chromium-20261010.json e screenshots; históricos de falhas mantidos. | [Visual QA 10/10/2026] FalhasC77–C83 corrigidas emQA: landmarks, nomeARIA do mapa, hierarquia de títulos do texto legado sem alteraroriginal/hash, tabelas financeiras focáveis por teclado, reflow de tarefas/select/data no dossier, langpt-MZ apenas no routerQA e proteção da recuperação assíncrona do simulador. Após correções15execuções axe/390–320–1440px,0violações automáticas/0overflow e idiomaPT; skiplink primeiroTab→conteúdo em3páginas; tabelas financeiras focadas/teclas no Chromium. Não equivale a leitor de ecrã, zoom/dispositivo real ou cobertura de todo oportal. LegacyContentTest5/84 e rastreioMFA1/14 são provas específicas, não contagem substituta de percursos. visual-followup-chromium-20261010.json e screenshots; históricos de falhas mantidos.","GET públicos e escritas autenticadas no servidor18097, alvo real55441 confirmado; publicação separada do importador. | [Setores QA após C71 10/10/2026] 22 originais importados privadamente após prévia renovada, hashes recuperados,22 scans ClamD reais e replay sem novos documentos/recursos/auditoria/scans. Divulgação autenticada separada:16 artigos com texto+5 imagens públicos; Mercado Financeiro privado, vazio confirmado na origem HTML e Inertia200. Chromium desktop:16 artigos, pesquisa/imagens, Energia e Mineração distintas, C72 título preservado; QA21 criou4 dossiers, retorno, logout/novaMFA/F5/replay; QA23 negado403 e anónimo sem contexto. Persistência READ ONLY:8 dossiers HTTP/Chromium, uma referência/evento cada,22 hashes únicos,0 relações geográficas automáticas. legacy-sectors-{apply,replay,http,browser,persistence}-qa.json; legacy-financial-origin-20261010/proof.json. C37/QA18,A/B,móvel/acessibilidade/cobertura integral não encerrados.",,,"Fecho exclusivo do piloto agronegócio; não cobre todo o acervo, versões, URLs, anexos ou setores. Mercado Financeiro vazio continua separado. | Catálogo visual sintético QA; ZEE/ZFI apenas controlos HTTP revertidos; condições/benefícios não executáveis indeterminados; sem ensaio visual integral dos outros consumidores. | C exclusivamente sintético; ZEE/ZFI encaminhamento por predicados, sem reconhecimento de zona real; download concluído apesar de perda da ferramenta. Provas A/B/cálculos/exportadores aceites não repetidas.","2–8 h de reconciliação/ensaio por consumidor agrupado, pressupondo dados sintéticos/perfis preparados. Alteração: estimar após reprodução concreta; variante integral pode exceder esta faixa.",,,"Recorte adaptativo de preparação disponibilizado/habilitado na homologação, revisão042ffbde. Limitações globais/sectoriais/fiscais mantêm âmbito próprio." +[PLANO-P1-P6-20261019] Plano Tempo: 27–46 h disponibilização; P7 e desenvolvimento separados. Inclusão 36–39 expressa para decisão; sem publicação automática. Revisão de proposta d87970e701f0. Roteiro no manual existente; não encerra critério por instalação. | 22/10/2026: primeiro incremento QA na branch codex/project-context-continuity-QA; contexto único por dossier/conta, herança com edições preservadas, moeda/IVA mensal e análise territorial explícita. Ver traceability-and-manual.md, secção Continuidade e adaptação contextual. 4 HTTP/74 asserções; 8 frontend; percurso visual A/B e nova sessão. Não encerra adaptação jurídica integral. | 22/10: revisão de a76369eb concluída no âmbito aceite por prova equivalente do regresso; A/B não repetidos. Tabela do primeiro percurso de investimento privado no manual: condições, artigos/período e efeitos; preparação documental, sem ligação executável nova. | 22/10/2026 — percurso privado executável em QA (base52fbb146): condições oficiais seleccionam mero registo/autorização, alternativas documentais e próximos passos; contexto C v4 mero registo após distinção directo/indirecto (Lei14/R13); prévia visual, vínculo inactivo preservado e relatório v3 por autorização conservado como histórico. 3 testes/96 asserções e um teste do novo relatório, tipos/build aprovados. Sem validação jurídica genérica adicional; orientação permanente Tempo em AGENTS. Branch codex/private-investment-path-executable-QA; sem integração main/alteração da homologação/activação fiscal. | 22/10/2026 — prova complementar exclusiva do relatório: recuperação UI do contexto v4, rascunho v5 e Word novo por mero registo; estudo/capacidade não aplicáveis. Word v3 preservado/identificado como histórico, hash inalterado. Sem alteração funcional ou repetição dos ensaios aceites. Dependências Git: a76369eb → 52fbb146 documental → a1fbda06; integrar após decisão, preservando main concorrente. | 22/10/2026 — disponibilizado por autorização Tempo: revisão servida042ffbde (inclui a76369eb/a1fbda06/064296e1 e correcção dirigida da recuperação legada). Percurso habilitado na homologação, versão private-investment-preparation-2026-v1; main ancestral preservado, sem conflitos/force-push. Zero migrations/importações/fixtures; nenhuma nova regra fiscal publicada/activada. Revisão/configuração/rotas conferidas; provas funcionais QA reutilizadas. | 22/10/2026 READ ONLY: catalogo Inhambane/Vilankulo vazio sem erro; zero publicadas tambem em Cabo Delgado. URL recebido nao identifica dossier. Falha da previa territorial e termino sem resposta continuam abertos; falta URL do dossier para leitura historica sem recriacao. | 22/10/2026 esclarecimento Tempo: pesquisa publica sem dossier; retirada dependencia de URL pessoal/confirmacao de impacto. Correcao QA: search-territory.ts em links carteira/catalogo/zonas, menus e detalhes. Seis testes Node, types e build isolado; prova visual carteira->Inhambane/Vilankulo->catalogo, recarregar, voltar e zonas. Mudanca de provincia limpa distrito. Nenhuma publicacao. Manual: Continuidade territorial da pesquisa.",documentos e legado,15/10/2026 — fecho do piloto ativo e preparação por leitura dos restantes setores; sem novos testes funcionais.,,,"[Visual QA 10/10/2026] Cobertura integral, mais perfis/dispositivos, leitor de ecrã e editor administrativoC74 não demonstrados. Mercado Financeiro permanece privado/corpo vazio confirmado na origem; rotas404. Sem associação automática Turismo→cadastro territorial, sem fundir Energia/Mineração. | Histórico preservado: [Visual QA 10 /10/2026 ] Cobertura integral, mais perfis /dispositivos , leitor de ecrã e editor administrativo C74 não demonstrados. Mercado Financeiro permanece privado /corpo vazio confirmado na origem; rotas 404. Sem associação automática Turismo→cadastro territorial, sem fundir Energia /Mineração. | Histórico preservado: 17 caminhos com texto preservados incluindo agronegócio e 4 novos retornos; restante mapa URL /aliases/acervo ainda incompleto. C37 /QA18 e A /B não encerrados. | Histórico anterior: Contexto /retorno do piloto observados; mapa de migração dos restantes URL s ainda pendente. C37 /QA18 e cenários A /B completos não foram executados neste ensaio.",Biblioteca/documentos existentes; Balcão+09/190000 para dossier. Expansão cartográfica exige correspondências fundamentadas. C37/A-B/SLA/perfis e ativação mantêm âmbito próprio.,Mantido /agronegocio; /explorar/agronegocio novo. Referência comID/hash/versão/ator/data e retorno autorizado ao mesmo dossier; replay sem duplicação; cinco fases/19etapas conservadas.,"[Interface legado QA 10 /10/2026 ] Chromium instalado, contextos isolados, desktop 1440 px / móvel 390 px: fotografia /fontes/paleta , pesquisa hit /miss , Enter /foco de 3 px, links carteira /zonas/biblioteca/oportunidade. Promotor QA21 : login→MFA→dossier→fonte→retorno→logout→novo contexto /MFA →recuperação /F5 →associação repetida. Conta 23:403 e artigo público sem título privado; anónimo sem contexto privado. UI observada; referência /evento únicos e originais /hash/scan confirmados em leitura QA. legacy-content-browser-qa.json ; legacy-content-browser-persistence-qa.json ; legado-piloto-qa.md . | Evidência anterior preservada: legado-piloto-qa.md ; legacy-content-http-qa.json : recursos 6 /5 públicos, hashes verificados, pesquisa, login /MFA21 , criação /continuação , logout /nova sessão, recuperação, replay único e isolamento. Interface não observada. | [Confirmação manual recebida 10 /10/2026 ] Responsável confirmou leitura pública → autenticação → criar /escolher dossier → guardar referência → nova sessão → recuperar dossier e abrir artigo. Confirmação declarada, sem conta /perfil/dispositivo/data de execução identificados. Não comprova MFA específico, ensaios móveis, acessibilidade, outros perfis, deduplicação, C37 /QA18 ou A /B. Ver legado-piloto-qa.md , confirmação manual. | [Setores QA após C71 10 /10/2026 ] 22 originais importados privadamente após prévia renovada, hashes recuperados,22 scans ClamD reais e replay sem novos documentos /recursos/auditoria/scans. Divulgação autenticada separada:16 artigos com texto+5 imagens públicos; Mercado Financeiro privado, vazio confirmado na origem HTML e Inertia 200. Chromium desktop:16 artigos, pesquisa /imagens , Energia e Mineração distintas, C72 título preservado; QA21 criou 4 dossiers, retorno, logout /novaMFA/F5/replay ; QA23 negado 403 e anónimo sem contexto. Persistência READ ONLY:8 dossiers HTTP /Chromium , uma referência /evento cada,22 hashes únicos,0 relações geográficas automáticas. legacy-sectors-{apply,replay,http,browser,persistence} -qa.json ; legacy-financial-origin-20261010 /proof.json. C37 /QA18 ,A /B ,móvel /acessibilidade/cobertura integral não encerrados. | [Visual QA 10 /10/2026 ] Falhas C77 – C83 corrigidas em QA: landmarks, nome ARIA do mapa, hierarquia de títulos do texto legado sem alteraroriginal /hash , tabelas financeiras focáveis por teclado, reflow de tarefas /select/data no dossier, langpt-MZ apenas no router QA e proteção da recuperação assíncrona do simulador. Após correções 15 execuções axe /390 –320–1440 px,0 violações automáticas /0overflow e idioma PT; skiplink primeiro Tab→conteúdo em 3 páginas; tabelas financeiras focadas /teclas no Chromium . Não equivale a leitor de ecrã, zoom /dispositivo real ou cobertura de todo oportal. Legacy Content Test 5 /84 e rastreio MFA 1 /14 são provas específicas, não contagem substituta de percursos. visual-followup-chromium-20261010.json e screenshots; históricos de falhas mantidos. | [Visual QA 10/10/2026] FalhasC77–C83 corrigidas emQA: landmarks, nomeARIA do mapa, hierarquia de títulos do texto legado sem alteraroriginal/hash, tabelas financeiras focáveis por teclado, reflow de tarefas/select/data no dossier, langpt-MZ apenas no routerQA e proteção da recuperação assíncrona do simulador. Após correções15execuções axe/390–320–1440px,0violações automáticas/0overflow e idiomaPT; skiplink primeiroTab→conteúdo em3páginas; tabelas financeiras focadas/teclas no Chromium. Não equivale a leitor de ecrã, zoom/dispositivo real ou cobertura de todo oportal. LegacyContentTest5/84 e rastreioMFA1/14 são provas específicas, não contagem substituta de percursos. visual-followup-chromium-20261010.json e screenshots; históricos de falhas mantidos.","GET públicos e escritas autenticadas no servidor18097, alvo real55441 confirmado; publicação separada do importador. | [Setores QA após C71 10/10/2026] 22 originais importados privadamente após prévia renovada, hashes recuperados,22 scans ClamD reais e replay sem novos documentos/recursos/auditoria/scans. Divulgação autenticada separada:16 artigos com texto+5 imagens públicos; Mercado Financeiro privado, vazio confirmado na origem HTML e Inertia200. Chromium desktop:16 artigos, pesquisa/imagens, Energia e Mineração distintas, C72 título preservado; QA21 criou4 dossiers, retorno, logout/novaMFA/F5/replay; QA23 negado403 e anónimo sem contexto. Persistência READ ONLY:8 dossiers HTTP/Chromium, uma referência/evento cada,22 hashes únicos,0 relações geográficas automáticas. legacy-sectors-{apply,replay,http,browser,persistence}-qa.json; legacy-financial-origin-20261010/proof.json. C37/QA18,A/B,móvel/acessibilidade/cobertura integral não encerrados.",,,"Fecho exclusivo do piloto agronegócio; não cobre todo o acervo, versões, URLs, anexos ou setores. Mercado Financeiro vazio continua separado. | Catálogo visual sintético QA; ZEE/ZFI apenas controlos HTTP revertidos; condições/benefícios não executáveis indeterminados; sem ensaio visual integral dos outros consumidores. | C exclusivamente sintético; ZEE/ZFI encaminhamento por predicados, sem reconhecimento de zona real; download concluído apesar de perda da ferramenta. Provas A/B/cálculos/exportadores aceites não repetidas.","2–8 h de reconciliação/ensaio por consumidor agrupado, pressupondo dados sintéticos/perfis preparados. Alteração: estimar após reprodução concreta; variante integral pode exceder esta faixa.",,,"Recorte adaptativo de preparação disponibilizado/habilitado na homologação, revisão042ffbde. Limitações globais/sectoriais/fiscais mantêm âmbito próprio." AUD-LEG-07,"Verificar imagens, anexos, links, pesquisa, permissões e duplicações, registando aceitação visual separadamente","Pedido direto do responsável,10/10/2026, integração do legado emQA §7; https://investemoz.tempo.co.mz/; legado-piloto-qa.md",biblioteca / conteúdo público / percurso do investidor,/explorar/agronegocio; /agronegocio; /documentos/6; /investimentos/a-partir-de/agronegocio; /investimentos/{id}/conteudos,"documents, biblioteca, importação autenticada, VerifiedDocumentBinary, jobs/derivadas. Capacidade existente associada ao domínio; correspondência integral desta cláusula só quando demonstrada na prova individual.","Disponibilizado em 15/10/2026, setores-fintech-QA-d5b4dc354265 DOC01: 16 fontes e compilação; sete entradas setoriais e especialização Fintech no dossier; três artigos publicados (recursos reais 27/28/29), imagem 24 reutilizada por identidade/hash. Flags existentes preservadas; sem migrations/categorias novas. B e COUNTRY02 preservados.","QA aceite reutilizada; execução ativa com backup/restauro, scan real, publicação expressa e HTTP anónimo200. Sem repetir percurso. outputs/investmoz-legado-ativacao-20261015/RESULTADO-FINAL.json; FINAL-READONLY.json; ANONYMOUS-HTTP.json; RECIBO-INTEGRIDADE-FINAL.json; outputs/investmoz-legado-restantes-setores-preparacao-20261015/INVENTARIO-E-RECORTE.json",Implementado parcialmente — entradas setoriais e três artigos ativos,"Inventário reconciliado: 17 artigos e cinco imagens publicados; 31 artigos com corpo por integrar (5 setoriais, 8 trabalho doméstico, 18 históricos/noticiosos); Mercado Financeiro vazio e post 74364 sem título separados. Onze variantes de URL e 43 capturas adicionais de artigos já cobertas, sem novas identidades. Demais referências, anexos técnicos e sitemap misto conservam recorte próprio.",Scanner/worker/GD/WebP e originais privados; ACL por oportunidade/sala diferente de partilha individual não implementada. LegadoOFF. Nenhuma nova decisão identificada para reconciliar/demonstrar esta cláusula. Decisões específicas só após localizar a regra correspondente.,Cada consumidor apresenta ficheiro/link/resultado íntegro; importação/pesquisa/recuperação/permissões verificadas e resultados visuais registados por ação.,P1,"Legado post171985 modificado2026-04-20; categoria Oportunidades preservada como metadado, entidade guia. Metadados/sitemapInfopublica e área de investimento distintos; não remapear por nome.",USR-LEG-20261010-07,1,"[{""id"":""USR-LEG-20261010-07"",""pedido"":""Verificar imagens, anexos, links, pesquisa, permissões e duplicações, registando aceitação visual separadamente"",""fontes"":[""Pedido direto10/10/2026 §7""],""aceitacao"":""Cada consumidor apresenta ficheiro/link/resultado íntegro; importação/pesquisa/recuperação/permissões verificadas e resultados visuais registados por ação."",""estado"":""parcial"",""variantes"":""IntegraçãoprogressivaQA, sem substituição de pendências anteriores"",""modulo"":""legado/biblioteca/percurso"",""confirmacao_manual"":{""recebida_em"":""2026-10-10"",""fonte"":""Mensagem do responsável nesta conversa"",""conta"":""não indicada"",""perfil"":""não indicado"",""dispositivo"":""não indicado"",""criterios"":[{""criterio"":""guardar_referencia"",""estado"":""confirmado manualmente"",""ambito"":""piloto agronegócio QA""},{""criterio"":""recuperar_dossier"",""estado"":""confirmado manualmente"",""ambito"":""piloto agronegócio QA""},{""criterio"":""abrir_artigo"",""estado"":""confirmado manualmente"",""ambito"":""piloto agronegócio QA""}],""exclusoes"":[""móvel"",""acessibilidade"",""outros perfis"",""C37 conta18"",""cenários A/B"",""cobertura integral""]},""incremento_setores_qa_20261010"":{""atualizado_em"":""2026-10-10T16:23:25.695297+00:00"",""ambito"":""QA18097;base55441isolada"",""evidencia"":""22 originais importados privadamente após prévia renovada, hashes recuperados,22 scans ClamD reais e replay sem novos documentos/recursos/auditoria/scans. Divulgação autenticada separada:16 artigos com texto+5 imagens públicos; Mercado Financeiro privado, vazio confirmado na origem HTML e Inertia200. Chromium desktop:16 artigos, pesquisa/imagens, Energia e Mineração distintas, C72 título preservado; QA21 criou4 dossiers, retorno, logout/novaMFA/F5/replay; QA23 negado403 e anónimo sem contexto. Persistência READ ONLY:8 dossiers HTTP/Chromium, uma referência/evento cada,22 hashes únicos,0 relações geográficas automáticas. legacy-sectors-{apply,replay,http,browser,persistence}-qa.json; legacy-financial-origin-20261010/proof.json. C37/QA18,A/B,móvel/acessibilidade/cobertura integral não encerrados."",""estado_requisito_atual"":""parcial"",""exclusoes"":[""ativação"",""C37/QA18"",""A/B"",""móvel"",""acessibilidade"",""cobertura integral""]},""incremento_visual_qa_20261010"":{""atualizado_em"":""2026-10-10T17:57:54.604301+00:00"",""ambito"":""QA18097/55441 exclusivamente"",""evidencia"":""FalhasC77–C83 corrigidas emQA: landmarks, nomeARIA do mapa, hierarquia de títulos do texto legado sem alteraroriginal/hash, tabelas financeiras focáveis por teclado, reflow de tarefas/select/data no dossier, langpt-MZ apenas no routerQA e proteção da recuperação assíncrona do simulador. Após correções15execuções axe/390–320–1440px,0violações automáticas/0overflow e idiomaPT; skiplink primeiroTab→conteúdo em3páginas; tabelas financeiras focadas/teclas no Chromium. Não equivale a leitor de ecrã, zoom/dispositivo real ou cobertura de todo oportal. LegacyContentTest5/84 e rastreioMFA1/14 são provas específicas, não contagem substituta de percursos. visual-followup-chromium-20261010.json e screenshots; históricos de falhas mantidos."",""lacuna_atual"":""Cobertura integral, mais perfis/dispositivos, leitor de ecrã e editor administrativoC74 não demonstrados. Mercado Financeiro permanece privado/corpo vazio confirmado na origem; rotas404. Sem associação automática Turismo→cadastro territorial, sem fundir Energia/Mineração."",""estado_global_preservado"":""parcial"",""ativacao"":false}}]","[Interface legado QA 10 /10/2026 ] Render /cliques observados no Chromium QA, com recuperação noutra sessão /F5 e negação à conta 23. Não é o navegador pessoal do utilizador nem o ensaio C37 /QA18. | Evidência anterior preservada: React preparado e build QA; dados Inertia recuperados. Navegador indisponível; roteiro manual em legado-piloto-qa.md . Aceitação visual pendente. | [Confirmação manual recebida 10 /10/2026 ] Responsável confirmou leitura pública → autenticação → criar /escolher dossier → guardar referência → nova sessão → recuperar dossier e abrir artigo. Confirmação declarada, sem conta /perfil/dispositivo/data de execução identificados. Não comprova MFA específico, ensaios móveis, acessibilidade, outros perfis, deduplicação, C37 /QA18 ou A /B. Ver legado-piloto-qa.md , confirmação manual. | [Setores QA após C71 10 /10/2026 ] 22 originais importados privadamente após prévia renovada, hashes recuperados,22 scans ClamD reais e replay sem novos documentos /recursos/auditoria/scans. Divulgação autenticada separada:16 artigos com texto+5 imagens públicos; Mercado Financeiro privado, vazio confirmado na origem HTML e Inertia 200. Chromium desktop:16 artigos, pesquisa /imagens , Energia e Mineração distintas, C72 título preservado; QA21 criou 4 dossiers, retorno, logout /novaMFA/F5/replay ; QA23 negado 403 e anónimo sem contexto. Persistência READ ONLY:8 dossiers HTTP /Chromium , uma referência /evento cada,22 hashes únicos,0 relações geográficas automáticas. legacy-sectors-{apply,replay,http,browser,persistence} -qa.json ; legacy-financial-origin-20261010 /proof.json. C37 /QA18 ,A /B ,móvel /acessibilidade/cobertura integral não encerrados. | [Visual QA 10 /10/2026 ] Leitura pública /móvel dirigida, teclado e 4 consumidores do mapa demonstrados;15 execuções de acessibilidade sem violação automática. | [Visual QA 10/10/2026] Leitura pública/móvel dirigida, teclado e4consumidores do mapa demonstrados;15execuções de acessibilidade semviolação automática.","GET públicos e escritas autenticadas no servidor18097, alvo real55441 confirmado; publicação separada do importador. | [Setores QA após C71 10/10/2026] 22 originais importados privadamente após prévia renovada, hashes recuperados,22 scans ClamD reais e replay sem novos documentos/recursos/auditoria/scans. Divulgação autenticada separada:16 artigos com texto+5 imagens públicos; Mercado Financeiro privado, vazio confirmado na origem HTML e Inertia200. Chromium desktop:16 artigos, pesquisa/imagens, Energia e Mineração distintas, C72 título preservado; QA21 criou4 dossiers, retorno, logout/novaMFA/F5/replay; QA23 negado403 e anónimo sem contexto. Persistência READ ONLY:8 dossiers HTTP/Chromium, uma referência/evento cada,22 hashes únicos,0 relações geográficas automáticas. legacy-sectors-{apply,replay,http,browser,persistence}-qa.json; legacy-financial-origin-20261010/proof.json. C37/QA18,A/B,móvel/acessibilidade/cobertura integral não encerrados.","Dois recursos na biblioteca existente e referências no payload cifrado do dossier; sem nova tabela/cadastro paralelo. | [Confirmação manual recebida 10/10/2026] Responsável confirmou leitura pública → autenticação → criar/escolher dossier → guardar referência → nova sessão → recuperar dossier e abrir artigo. Confirmação declarada, sem conta/perfil/dispositivo/data de execução identificados. Não comprova MFA específico, ensaios móveis, acessibilidade, outros perfis, deduplicação, C37/QA18 ou A/B. Ver legado-piloto-qa.md, confirmação manual. | [Setores QA após C71 10/10/2026] 22 originais importados privadamente após prévia renovada, hashes recuperados,22 scans ClamD reais e replay sem novos documentos/recursos/auditoria/scans. Divulgação autenticada separada:16 artigos com texto+5 imagens públicos; Mercado Financeiro privado, vazio confirmado na origem HTML e Inertia200. Chromium desktop:16 artigos, pesquisa/imagens, Energia e Mineração distintas, C72 título preservado; QA21 criou4 dossiers, retorno, logout/novaMFA/F5/replay; QA23 negado403 e anónimo sem contexto. Persistência READ ONLY:8 dossiers HTTP/Chromium, uma referência/evento cada,22 hashes únicos,0 relações geográficas automáticas. legacy-sectors-{apply,replay,http,browser,persistence}-qa.json; legacy-financial-origin-20261010/proof.json. C37/QA18,A/B,móvel/acessibilidade/cobertura integral não encerrados.","[Interface legado QA 10/10/2026] Render/cliques observados no Chromium QA, com recuperação noutra sessão/F5 e negação à conta23. Não é o navegador pessoal do utilizador nem o ensaio C37/QA18. | Evidência anterior preservada: Logout/nova sessão FortifyMFA21: fonte/versão/hashes recuperados; outra conta negada e projeto independente sem referência. | [Confirmação manual recebida 10/10/2026] Responsável confirmou leitura pública → autenticação → criar/escolher dossier → guardar referência → nova sessão → recuperar dossier e abrir artigo. Confirmação declarada, sem conta/perfil/dispositivo/data de execução identificados. Não comprova MFA específico, ensaios móveis, acessibilidade, outros perfis, deduplicação, C37/QA18 ou A/B. Ver legado-piloto-qa.md, confirmação manual. | [Setores QA após C71 10/10/2026] 22 originais importados privadamente após prévia renovada, hashes recuperados,22 scans ClamD reais e replay sem novos documentos/recursos/auditoria/scans. Divulgação autenticada separada:16 artigos com texto+5 imagens públicos; Mercado Financeiro privado, vazio confirmado na origem HTML e Inertia200. Chromium desktop:16 artigos, pesquisa/imagens, Energia e Mineração distintas, C72 título preservado; QA21 criou4 dossiers, retorno, logout/novaMFA/F5/replay; QA23 negado403 e anónimo sem contexto. Persistência READ ONLY:8 dossiers HTTP/Chromium, uma referência/evento cada,22 hashes únicos,0 relações geográficas automáticas. legacy-sectors-{apply,replay,http,browser,persistence}-qa.json; legacy-financial-origin-20261010/proof.json. C37/QA18,A/B,móvel/acessibilidade/cobertura integral não encerrados.",Piloto ativo encerrado; restante legado pendente.,Piloto agronegócio: ativo e entrega encerrada. Integração integral do legado: pendente nos mesmos IDs.,parcial,Não disponibilizado; guarda QA/flagfalse. Nenhuma escrita ou divulgação ativa autorizada.,"15/10/2026: entrega do piloto encerrada; dados/B/COUNTRY02/build preservados. Não equivale a integração integral do legado. | Lote setorial disponibilizado por autorização expressa da Tempo; integração integral continua pendente. | QA 15/10/2026: setores-fintech-QA-d5b4dc354265; sete entradas comerciais/contexto no dossier e três artigos preparados. B/COUNTRY02/aceitações preservados; sem disponibilização ativa. | Disponibilização expressamente autorizada pela Tempo: «Autorizo a disponibilizar». Executada com backup/restauro fresco verificado; apenas conferência operacional, sem repetir aceitação QA. [RECONCILIACAO-43-20261019] 5: Sem saldo de código no recorte visual aceite. | 8: Outras identidades do legado exigem lotes e eventual adaptação por tipo. Não há autorização genérica para publicar todo o acervo.","Inventário reconciliado: 20 artigos e cinco imagens publicados; 28 artigos com corpo por integrar (2 setoriais, 8 trabalho doméstico, 18 históricos/noticiosos); Mercado Financeiro vazio e post 74364 sem título separados. Onze variantes de URL e 43 capturas adicionais de artigos já cobertas, sem novas identidades. Demais referências, anexos técnicos e sitemap misto conservam recorte próprio. | Entrega operacional deste delta concluída. Mercado Financeiro geral vazio e restante acervo mantêm os seus estados. Licenças, requisitos e documentos específicos Fintech por atividade permanecem por determinar; não bloqueiam a preparação independente nem se consideram concluídos. | Recorte QA demonstrado, sem encerrar critérios globais. Histórico económico combinado conservado, fora de novas escolhas; oportunidade6 não inferida como Fintech. Sem fusões por nome. Recuperação existente conferida por leitura e hashes; outra sessão/dispositivo e percursos aceites não reensaiados. Conferência dos anexos pelo utilizador pendente. | Recorte aprovado disponibilizado; requisitos globais permanecem abertos. Atividade historica combinada e oportunidade6 sem reclassificacao. Conferencia dos anexos finais pelo utilizador pendente. Sem repetir testes aceites, formularios ou L1. diff --git a/resources/js/components/catalogue-navigation.tsx b/resources/js/components/catalogue-navigation.tsx index 94e82a24..e768a50b 100644 --- a/resources/js/components/catalogue-navigation.tsx +++ b/resources/js/components/catalogue-navigation.tsx @@ -1,4 +1,5 @@ import { Link, usePage } from '@inertiajs/react'; +import { searchTerritoryHref } from '@/lib/search-territory'; export default function CatalogueNavigation({ dimensionUrl, }: { @@ -21,7 +22,7 @@ export default function CatalogueNavigation({ ) return dimensionUrl(u.searchParams.get('dimension')!); if (context) u.searchParams.set('context', context); - return u.pathname + u.search; + return searchTerritoryHref(u.pathname + u.search, url); }; const sections = { 'Enquadramento e filtros': [ diff --git a/resources/js/components/portal-grouped-menu.tsx b/resources/js/components/portal-grouped-menu.tsx index d963fb42..9e24c967 100644 --- a/resources/js/components/portal-grouped-menu.tsx +++ b/resources/js/components/portal-grouped-menu.tsx @@ -1,4 +1,5 @@ import PortalProductIdentity from '@/components/portal-product-identity'; +import { searchTerritoryHref } from '@/lib/search-territory'; import { Link, router, usePage } from '@inertiajs/react'; import { ChevronDown, @@ -110,7 +111,7 @@ export function PortalGroupedMenu() { className="tempo-menu-item" > {names[parent]} diff --git a/resources/js/lib/catalogue-context.ts b/resources/js/lib/catalogue-context.ts index 90709387..2f6da8fd 100644 --- a/resources/js/lib/catalogue-context.ts +++ b/resources/js/lib/catalogue-context.ts @@ -1,3 +1,4 @@ +import { searchTerritoryHref } from './search-territory'; /** Only a query string is carried; the return destination is always local. */ export function catalogueDetailHref(path: string, query: string): string { return query @@ -8,5 +9,5 @@ export function catalogueReturnHref(base: string, pageUrl: string): string { const query = new URL(pageUrl, 'https://portal.invalid').searchParams.get( 'catalogue_query', ); - return base + (query ? `?${new URLSearchParams(query).toString()}` : ''); + return searchTerritoryHref(base + (query ? `?${new URLSearchParams(query).toString()}` : ''), pageUrl); } diff --git a/resources/js/lib/search-territory.ts b/resources/js/lib/search-territory.ts new file mode 100644 index 00000000..6bcbbf65 --- /dev/null +++ b/resources/js/lib/search-territory.ts @@ -0,0 +1,24 @@ +const levels = ['province_id', 'district_id', 'admin_post_id', 'locality_id']; +const searchRoutes = ['/carteira', '/oportunidades', '/zonas', '/educacao']; + +/** URL-scoped search context, never a saved investment or another browser tab. */ +export function searchTerritoryHref(href: string, pageUrl: string): string { + const base = 'https://portal.invalid'; + const source = new URL(pageUrl, base); + const target = new URL(href, base); + const supported = (path: string) => searchRoutes.some((route) => path === route || path.startsWith(`${route}/`)); + if (target.origin !== base || !supported(source.pathname) || !supported(target.pathname)) return href; + const inherited = source.searchParams.has('catalogue_query') + ? new URLSearchParams(source.searchParams.get('catalogue_query')!) + : source.searchParams; + // An explicit ancestor, including an explicit empty value, overrides its descendants. + let changed = false; + for (const field of levels) { + if (target.searchParams.has(field)) { + changed ||= target.searchParams.get(field) !== inherited.get(field); + } else if (!changed && inherited.get(field)) { + target.searchParams.set(field, inherited.get(field)!); + } + } + return target.pathname + target.search + target.hash; +} diff --git a/resources/js/pages/investment/catalogue.tsx b/resources/js/pages/investment/catalogue.tsx index 830edfec..1654a7fc 100644 --- a/resources/js/pages/investment/catalogue.tsx +++ b/resources/js/pages/investment/catalogue.tsx @@ -1,4 +1,5 @@ import EducationalGuides from '@/components/educational-guides'; +import { searchTerritoryHref } from '@/lib/search-territory'; import type { EducationalArticle } from '@/components/educational-article-card'; import OpportunitySearchFilters from '@/components/opportunity-search-filters'; import SearchState from '@/components/search-state'; @@ -46,7 +47,8 @@ export default function Catalogue({ corridor_id: string | null; }[]; }) { - const { auth } = usePage<{ auth: { user: unknown } }>().props; + const page = usePage<{ auth: { user: unknown } }>(); + const { auth } = page.props; const form = useForm({ association_type: String(filters.association_type ?? ''), association_target: String(filters.association_target ?? ''), @@ -696,7 +698,7 @@ export default function Catalogue({
{territorial.map((d) => ( diff --git a/resources/js/pages/investment/detail.tsx b/resources/js/pages/investment/detail.tsx index 661e3dbc..95468ad5 100644 --- a/resources/js/pages/investment/detail.tsx +++ b/resources/js/pages/investment/detail.tsx @@ -1,4 +1,5 @@ import EducationalGuides from '@/components/educational-guides'; +import { searchTerritoryHref } from '@/lib/search-territory'; import type { EducationalArticle } from '@/components/educational-article-card'; import { ClassificationSummary } from '@/components/opportunity-classification'; import { Link, router, usePage } from '@inertiajs/react'; @@ -45,7 +46,7 @@ export default function Detail({

Voltar ao dossier: {dossierOrigin.title} @@ -253,7 +254,7 @@ export default function Detail({ Consultar dossier: {dossier.title} diff --git a/resources/js/pages/investment/zone.tsx b/resources/js/pages/investment/zone.tsx index ff485423..39a972d8 100644 --- a/resources/js/pages/investment/zone.tsx +++ b/resources/js/pages/investment/zone.tsx @@ -5,6 +5,7 @@ import ParkDetailsEditor, { } from '@/components/investment-zone-operational-details'; import { Link, router, useForm, usePage } from '@inertiajs/react'; import { catalogueReturnHref } from '@/lib/catalogue-context'; +import { searchTerritoryHref } from '@/lib/search-territory'; import InvestmentTerritory from '@/components/investment-territory'; import InvestmentMapPanel from '@/components/investment-map-panel'; import { @@ -1772,7 +1773,7 @@ function Editor({

{o.title} @@ -1829,7 +1830,7 @@ function Editor({

{r.title} diff --git a/resources/js/pages/investment/zones.tsx b/resources/js/pages/investment/zones.tsx index f18720ed..fee63477 100644 --- a/resources/js/pages/investment/zones.tsx +++ b/resources/js/pages/investment/zones.tsx @@ -1,7 +1,8 @@ import InvestmentZoneInstallation, { type ParkInstallationPlan, } from '@/components/investment-zone-installation'; -import { Link, router } from '@inertiajs/react'; +import { Link, router, usePage } from '@inertiajs/react'; +import { searchTerritoryHref } from '@/lib/search-territory'; import { useState } from 'react'; import { catalogueDetailHref } from '@/lib/catalogue-context'; import { @@ -90,9 +91,13 @@ export default function Zones({ zoneExtensionsAvailable?: boolean; territorySelection?: TerritoryOption[]; }) { + const pageUrl = usePage().url; const [error, setError] = useState(''); const [busy, setBusy] = useState(false); const exportParams = new URLSearchParams(); + ['province_id', 'district_id', 'admin_post_id', 'locality_id'].forEach((field, index) => { + if (territorySelection[index]) exportParams.set(field, territorySelection[index].id); + }); for (const key of [ 'q', 'category', @@ -148,9 +153,9 @@ export default function Zones({ > Por Cluster Por Corredor - Por ZEE - Por ZFI - + Por ZEE + Por ZFI + Parques industriais @@ -343,7 +348,7 @@ export default function Zones({ {!management && ( Ver oportunidades associadas diff --git a/resources/js/pages/portfolio/index.tsx b/resources/js/pages/portfolio/index.tsx index f7f5fa2a..1d3ea2f0 100644 --- a/resources/js/pages/portfolio/index.tsx +++ b/resources/js/pages/portfolio/index.tsx @@ -1,4 +1,5 @@ -import { Link, useForm } from '@inertiajs/react'; +import { Link, useForm, usePage } from '@inertiajs/react'; +import { searchTerritoryHref } from '@/lib/search-territory'; import { catalogueDetailHref } from '@/lib/catalogue-context'; import { Management } from '../management/shared'; import type { Paginated } from '../management/shared'; @@ -35,6 +36,7 @@ export default function Index({ locality_id: filters.locality_id ?? '', }); const base = management ? '/management/portfolio' : '/carteira'; + const { url } = usePage(); const Frame = management ? Management : Layout; return ( @@ -151,7 +153,7 @@ export default function Index({ (r.corridor_id || r.cluster_id || r.project_id) && ( Ver oportunidades associadas @@ -174,10 +176,10 @@ export default function Index({ aria-label="Alternativas de exploração" className="flex flex-wrap gap-4" > - + Ver oportunidades publicadas - + Consultar ZEE, ZFI e parques diff --git a/resources/js/pages/portfolio/show.tsx b/resources/js/pages/portfolio/show.tsx index 6ac8ee87..895555bc 100644 --- a/resources/js/pages/portfolio/show.tsx +++ b/resources/js/pages/portfolio/show.tsx @@ -1,6 +1,7 @@ import { Link, useForm, router, usePage } from '@inertiajs/react'; import { useState } from 'react'; import { catalogueReturnHref } from '@/lib/catalogue-context'; +import { searchTerritoryHref } from '@/lib/search-territory'; import InvestmentMapPanel from '@/components/investment-map-panel'; import StructureGeographyPanel, { type StructureGeography, @@ -190,7 +191,7 @@ function Editor({ {zones.map((z) => (

- + {z.name} {' '} · {z.association_type} · Fonte: {z.source_reference} @@ -297,7 +298,7 @@ function Editor({

{opportunity.title} @@ -485,7 +486,7 @@ function Editor({ {kind(r)}:{' '} {r.title} diff --git a/tests/frontend/search-territory.test.mjs b/tests/frontend/search-territory.test.mjs new file mode 100644 index 00000000..1cac6baf --- /dev/null +++ b/tests/frontend/search-territory.test.mjs @@ -0,0 +1,27 @@ +import assert from 'node:assert/strict'; +import test from 'node:test'; +import { searchTerritoryHref } from '../../resources/js/lib/search-territory.ts'; + +test('portfolio to catalogue to related screen retains only territorial search filters', () => { + const start = '/carteira?province_id=inh&district_id=vil&q=airport&kind=project'; + const catalogue = searchTerritoryHref('/oportunidades?view=grid', start); + assert.equal(catalogue, '/oportunidades?view=grid&province_id=inh&district_id=vil'); + const detail = searchTerritoryHref('/carteira/id', catalogue); + assert.equal(searchTerritoryHref('/carteira', detail), '/carteira?province_id=inh&district_id=vil'); + assert.equal(searchTerritoryHref('/zonas?category=zee', start), '/zonas?category=zee&province_id=inh&district_id=vil'); +}); +test('nested historical return query restores territory without importing unrelated filters', () => { + assert.equal(searchTerritoryHref('/oportunidades', '/carteira/id?catalogue_query='+encodeURIComponent('province_id=inh&district_id=vil&q=airport')), '/oportunidades?province_id=inh&district_id=vil'); +}); +test('explicit parent changes or clearing never import incompatible descendants', () => { + const current = '/oportunidades?province_id=inh&district_id=vil&admin_post_id=post&locality_id=loc'; + assert.equal(searchTerritoryHref('/carteira?province_id=cabo', current), '/carteira?province_id=cabo'); + assert.equal(searchTerritoryHref('/carteira?district_id=other', current), '/carteira?district_id=other&province_id=inh'); + assert.equal(searchTerritoryHref('/carteira?province_id=', current), '/carteira?province_id='); +}); +test('no cross-tab, project, account, external or unrelated route inheritance', () => { + assert.equal(searchTerritoryHref('/oportunidades','/carteira'), '/oportunidades'); + assert.equal(searchTerritoryHref('/oportunidades','/investimentos/id?province_id=private'), '/oportunidades'); + assert.equal(searchTerritoryHref('/investimentos/id','/carteira?province_id=inh'), '/investimentos/id'); + assert.equal(searchTerritoryHref('https://other.test/carteira','/carteira?province_id=inh'), 'https://other.test/carteira'); +});