feat(C163): unifica a visualização da demografia em uma tabela

This commit is contained in:
Francisco Solla 2026-09-15 09:32:06 -03:00
parent 7a17798cda
commit 0f0f9a6eab
3 changed files with 47 additions and 28 deletions

View file

@ -0,0 +1 @@
**C163 — demografia em uma única tabela (2026-09-15):** a seção 7 tinha dois visuais para o mesmo tipo de dado (grade de stats do artefato + tabela da pesquisa); agora é **uma única tabela Indicador × Dado × Fonte**, com "base Teqo" na coluna Fonte para o artefato IBGE e a data para os itens pesquisados (URLs preservadas na nota de fontes do bloco e na seção "Fontes e limites"). O item de pesquisa "População total" saiu por duplicar a linha "População" da base. Unit 3118/3118, `tsc`/eslint verdes; PDF de Itamaraju regerado (9 páginas).

View file

@ -795,34 +795,47 @@ const buildDemographicsSection = ({ snapshot, research }) => {
},
]
}
const blocks = [
const baseRows = [
{ indicator: 'População', value: formatInteger(demographics.population) },
{ indicator: '0–17 anos', value: formatInteger(demographics.ageBands['0-17']) },
{ indicator: '18–29 anos', value: formatInteger(demographics.ageBands['18-29']) },
{ indicator: '30–59 anos', value: formatInteger(demographics.ageBands['30-59']) },
{ indicator: '60+ anos', value: formatInteger(demographics.ageBands['60+']) },
{ indicator: 'Mulheres', value: formatPercent(demographics.sexShareFemale) },
{
kind: 'stats',
indicator: 'Idade mediana',
value:
demographics.medianAge === null ? '—' : `${formatInteger(demographics.medianAge)} anos`,
},
].map((row) => ({ ...row, source: 'base Teqo' }))
const researchRows = (research.demography ?? []).map((item) => ({
indicator: item.topic,
value: item.detail,
source: formatDateBr(item.sourceDate),
}))
return [
{
kind: 'table',
title: 'Demografia (IBGE Censo 2022)',
rows: [
{ label: 'População', value: formatInteger(demographics.population) },
{ label: '0–17 anos', value: formatInteger(demographics.ageBands['0-17']) },
{ label: '18–29 anos', value: formatInteger(demographics.ageBands['18-29']) },
{ label: '30–59 anos', value: formatInteger(demographics.ageBands['30-59']) },
{ label: '60+ anos', value: formatInteger(demographics.ageBands['60+']) },
{ label: 'Mulheres', value: formatPercent(demographics.sexShareFemale) },
{
label: 'Idade mediana',
value:
demographics.medianAge === null ? '—' : `${formatInteger(demographics.medianAge)} anos`,
},
columns: [
{ key: 'indicator', label: 'Indicador', width: 22 },
{ key: 'value', label: 'Dado', width: 61 },
{ key: 'source', label: 'Fonte', width: 17 },
],
rows: [...baseRows, ...researchRows],
note: '“base Teqo” = artefato IBGE Censo 2022 commitado; datas = pesquisa web datada, com URL na seção de fontes.',
sources: [
sourceTeqo('IBGE Censo 2022 (artefato commitado)', null),
...(research.demography ?? []).map((item) => ({
kind: 'web',
label: item.topic,
url: item.sourceUrl,
date: item.sourceDate,
})),
],
sources: [sourceTeqo('IBGE Censo 2022 (artefato commitado)', null)],
},
]
blocks.push(
...buildSourcedListBlocks({
title: 'Demografia complementar (pesquisa)',
note: 'Cor/raça e poder aquisitivo (IBGE Censo 2022) — leitura para agenda e linguagem na cidade; cada item com URL.',
items: research.demography ?? [],
}),
)
return blocks
}
const buildEconomySection = ({ research }) =>

View file

@ -358,11 +358,16 @@ describe('buildCityReport', () => {
})
it('adds the researched demography, economy and transport data', () => {
const demografia = report.sections.find((section) => section.id === 'demografia')!
const complementary = demografia.blocks.find(
(block) => block.title === 'Demografia complementar (pesquisa)',
)!
expect((complementary.rows as unknown as TableRow[])[0].topic).toBe('Cor/raça')
const demografia = report.sections.find((section) => section.id === 'demografia')!.blocks[0]
const rows = demografia.rows as unknown as TableRow[]
expect(rows[0].indicator).toBe('População')
expect(rows[0].source).toBe('base Teqo')
expect(rows.some((row) => row.indicator === 'Cor/raça' && row.source === '10/09/2026')).toBe(
true,
)
expect(
demografia.sources!.some((source) => source.url === 'https://exemplo.test/cor-raca'),
).toBe(true)
const economia = report.sections.find((section) => section.id === 'economia')!.blocks[0]
expect((economia.rows as unknown as TableRow[])[0].detail).toContain('Serviços')
const transporte = report.sections.find((section) => section.id === 'transporte')!.blocks[0]