Skip to content

Commit

Permalink
3827: Sdg indicators->add table notice message + sdg metadata downloa…
Browse files Browse the repository at this point in the history
…d links (#3854)

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
minotogna and mergify[bot] committed Jul 6, 2024
1 parent b251d23 commit 70d7143
Show file tree
Hide file tree
Showing 19 changed files with 229 additions and 62 deletions.
7 changes: 7 additions & 0 deletions src/client/pages/Section/Title/Hints/Hints.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
@import 'src/client/style/partials';

.title-hints {
display: flex;
align-items: center;
gap: $spacing-xs;
}
94 changes: 94 additions & 0 deletions src/client/pages/Section/Title/Hints/Hints.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import './Hints.scss'
import React from 'react'
import { useTranslation } from 'react-i18next'

import { Objects } from 'utils/objects'

import { ApiEndPoint } from 'meta/api/endpoint'
import { CountryIso } from 'meta/area'
import { SubSectionHints, SubSections } from 'meta/assessment'

import { useCycle } from 'client/store/assessment'
import { useCycleRouteParams, useSectionRouteParams } from 'client/hooks/useRouteParams'
import DefinitionLink from 'client/components/DefinitionLink'
import { Props } from 'client/pages/Section/Title/props'

type Hint = {
document: string
key: keyof SubSectionHints
labelKey: string
}

const HINTS: Array<Hint> = [
{ document: 'tad', key: 'definitions', labelKey: 'definition.definitionLabel' },
{ document: 'faq', key: 'faqs', labelKey: 'definition.faqLabel' },
{ document: 'rn', key: 'notes', labelKey: 'definition.seeReportingNotes' },
]

export const HintsSustainableDevelopment: React.FC<Props> = () => {
const { t } = useTranslation()

const routeParams = useSectionRouteParams<CountryIso>()
const searchParams = new URLSearchParams(routeParams)

return (
<div className="title-hints">
{['Metadata-15-01-01', 'Metadata-15-02-01'].map((key) => {
searchParams.set('key', key)

return (
<a
key={key}
className="definition-link no-print"
href={`${ApiEndPoint.File.sdgMetadata()}?${searchParams.toString()}`}
rel="noreferrer"
target="_blank"
>
{t(`fra.sustainableDevelopment.${key}`)}
</a>
)
})}
</div>
)
}

const Hints: React.FC<Props> = (props) => {
const { subSection } = props
const { hints: sectionHints } = subSection.props

const { i18n, t } = useTranslation()
const { assessmentName, cycleName } = useCycleRouteParams()
const cycle = useCycle()

const anchor = SubSections.getAnchor({ cycle, subSection })
const hints = sectionHints?.[cycle.uuid] ?? {}

if (Objects.isEmpty(hints)) return null

return (
<div className="title-hints">
{HINTS.map((hint) => {
const { document, key, labelKey } = hint
const show = Boolean(hints?.[key])

if (show) {
return (
<DefinitionLink
key={key}
anchor={anchor}
assessmentName={assessmentName}
cycleName={cycleName}
document={document}
lang={i18n.resolvedLanguage}
title={t(labelKey)}
/>
)
}

return null
})}
</div>
)
}

export default Hints
2 changes: 2 additions & 0 deletions src/client/pages/Section/Title/Hints/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default } from './Hints'
export { HintsSustainableDevelopment } from './Hints'
4 changes: 0 additions & 4 deletions src/client/pages/Section/Title/Title.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,3 @@
grid-row-gap: $spacing-xxxs;
margin-bottom: $spacing-xs;
}

.title-hint__link {
margin-right: $spacing-xs;
}
53 changes: 8 additions & 45 deletions src/client/pages/Section/Title/Title.tsx
Original file line number Diff line number Diff line change
@@ -1,69 +1,32 @@
import './Title.scss'
import React from 'react'
import { useTranslation } from 'react-i18next'

import { SubSectionHints, SubSections } from 'meta/assessment'
import { SectionName } from 'meta/assessment'

import { useCycle } from 'client/store/assessment'
import { useCycleRouteParams } from 'client/hooks/useRouteParams'
import DefinitionLink from 'client/components/DefinitionLink'
import { Components, TitleDefault } from 'client/pages/Section/Title/Components'
import Hints, { HintsSustainableDevelopment } from 'client/pages/Section/Title/Hints'

import { Props } from './props'

type Hint = {
document: string
key: keyof SubSectionHints
labelKey: string
const HintsComponents: Record<SectionName, React.FC<Props>> = {
sustainableDevelopment: HintsSustainableDevelopment,
}

const HINTS: Array<Hint> = [
{ document: 'tad', key: 'definitions', labelKey: 'definition.definitionLabel' },
{ document: 'faq', key: 'faqs', labelKey: 'definition.faqLabel' },
{ document: 'rn', key: 'notes', labelKey: 'definition.seeReportingNotes' },
]

const Title: React.FC<Props> = (props) => {
const { subSection } = props
const { hints: sectionHints, name: sectionName } = subSection.props
const { name: sectionName } = subSection.props

const { i18n, t } = useTranslation()
const { assessmentName, cycleName } = useCycleRouteParams()
const cycle = useCycle()
const { assessmentName } = useCycleRouteParams()

const anchor = SubSections.getAnchor({ cycle, subSection })
const hints = sectionHints?.[cycle.uuid] ?? {}
const Component = Components[assessmentName]?.[sectionName] ?? TitleDefault
const HintsComponent = HintsComponents[sectionName] ?? Hints

return (
<div className="section__title">
{React.createElement(Component, { subSection })}

{Object.keys(hints).length > 0 && (
<div>
{HINTS.map((hint) => {
const { document, key, labelKey } = hint
const show = Boolean(hints?.[key])

if (show) {
return (
<DefinitionLink
key={key}
anchor={anchor}
assessmentName={assessmentName}
className="title-hint__link"
cycleName={cycleName}
document={document}
lang={i18n.resolvedLanguage}
title={t(labelKey)}
/>
)
}

return null
})}
</div>
)}
<HintsComponent subSection={subSection} />
</div>
)
}
Expand Down
3 changes: 3 additions & 0 deletions src/i18n/resources/en/fra.js
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,9 @@ module.exports = {
proportionForestAreaLongTermForestManagement2025:
'$t(sustainableDevelopment.proportionForestAreaLongTermForestManagement)',
forestAreaVerifiedForestManagement2025: '$t(sustainableDevelopment.forestAreaVerifiedForestManagement)',
dataProvidedBy: `Data for this SDG sub-indicator are provided by FSC and PEFC (forest certification organizations).`,
'Metadata-15-01-01': `SDG Indicator 15.1.1 Metadata`,
'Metadata-15-02-01': `SDG Indicator 15.2.1 Metadata`,
},

navigation: {
Expand Down
3 changes: 3 additions & 0 deletions src/i18n/resources/es/fra.js
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,9 @@ module.exports = {
annualForestAreaChangeRate: 'Tasa de cambio anual del área de bosque',
sdgIndicator1_2025: 'Indicador ODS 15.1.1: Área de bosque en proporción a la superficie terrestre total',
forestAreaProportionLandArea: 'Área de bosque en proporción a la superficie terrestre total',
dataProvidedBy: `Los datos para este subindicador ODS son proporcionados por FSC y PEFC (organizaciones de certificación forestal).`,
'Metadata-15-01-01': `Metadatos del Indicador ODS 15.1.1`,
'Metadata-15-02-01': `Metadatos del Indicador ODS 15.2.1`,
},
navigation: {
sectionHeaders: {
Expand Down
3 changes: 3 additions & 0 deletions src/i18n/resources/zh/fra.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,9 @@ module.exports = {
annualForestAreaChangeRate: '年森林面积变化率',
sdgIndicator1_2025: '可持续发展目标指标 15.1.1 森林面积占土地总面积的比例',
forestAreaProportionLandArea: '森林面积占土地总面积的比例',
dataProvidedBy: `该可持续发展目标次级指标的数据由FSC和PEFC(森林认证机构)提供。`,
'Metadata-15-01-01': `可持续发展目标指标15.1.1元数据`,
'Metadata-15-02-01': `可持续发展目标指标15.2.1元数据`,
},
navigation: {
sectionHeaders: {
Expand Down
3 changes: 2 additions & 1 deletion src/meta/api/endpoint/ApiEndPoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,10 @@ export const ApiEndPoint = {
selectedDomain = ':selectedDomain',
}) =>
apiPath('file', 'biomass-stock', assessmentName, cycleName, countryIso, sectionName, selectedDomain, language),
bulkDownload: () => apiPath('file', 'bulk-download'),
dashboard: () => apiPath('file', 'dashboard'),
dataDownload: () => apiPath('file', 'data-download'),
bulkDownload: () => apiPath('file', 'bulk-download'),
sdgMetadata: () => apiPath('file', 'sdg-metadata'),
userGuide: (language = ':language') => apiPath('file', 'user-guide', language),
},

Expand Down
1 change: 1 addition & 0 deletions src/meta/assessment/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export enum TableNames {
growingStockTotal = 'growingStockTotal',
primaryDesignatedManagementObjective = 'primaryDesignatedManagementObjective',
specificForestCategories = 'specificForestCategories',
sustainableDevelopment15_2_1_5 = 'sustainableDevelopment15_2_1_5',
totalAreaWithDesignatedManagementObjective = 'totalAreaWithDesignatedManagementObjective',
// Used to append ODP data to tableData
originalDataPointValue = 'originalDataPointValue',
Expand Down
18 changes: 18 additions & 0 deletions src/server/api/file/getSdgMetadata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Response } from 'express'

import { CycleDataRequest } from 'meta/api/request'
import { Lang } from 'meta/lang'

import { FileRepository, fileTypes } from 'server/service/file'
import { Requests } from 'server/utils'

type Request = CycleDataRequest<{ key: 'Metadata-15-01-01' | 'Metadata-15-02-01' }>

export const getSdgMetadata = async (req: Request, res: Response) => {
try {
const { key } = req.query
FileRepository.download(res, fileTypes.sdgMetadata(key), Lang.en)
} catch (err) {
Requests.sendErr(res, err)
}
}
5 changes: 4 additions & 1 deletion src/server/api/file/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { getBiomassStockFile } from './getBiomassStockFile'
import { getBulkDownload } from './getBulkDownload'
import { getDataDownloadFile } from './getDataDownloadFile'
import { getHiddenFile } from './getHiddenFile'
import { getSdgMetadata } from './getSdgMetadata'
import { getUserGuideFile } from './getUserGuide'
import multer = require('multer')

Expand All @@ -30,13 +31,15 @@ export const FileApi = {

// BiomassStock
express.get(ApiEndPoint.File.biomassStock({}), AuthMiddleware.requireEditTableData, getBiomassStockFile)

// Files
express.post(
ApiEndPoint.File.many(),
multer({ fileFilter }).array('file'),
AuthMiddleware.requireEditRepositoryItem,
createManyFiles
)

// SDG Metadata
express.get(ApiEndPoint.File.sdgMetadata(), AuthMiddleware.requireView, getSdgMetadata)
},
}
28 changes: 28 additions & 0 deletions src/server/repository/assessment/row/create.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Assessment, Cycle, Row, RowProps, Table } from 'meta/assessment'

import { BaseProtocol, DB, Schemas } from 'server/db'
import { RowAdapter } from 'server/repository/adapter'

type Props = {
assessment: Assessment
cycles: Array<Cycle>
table: Table
rowProps: RowProps
}

export const create = async (props: Props, client: BaseProtocol = DB): Promise<Row> => {
const { assessment, cycles, table } = props

const rolProps = { ...props.rowProps, cycles: cycles.map(({ uuid }) => uuid) }

const schemaName = Schemas.getName(assessment)

return client.one<Row>(
`
insert into ${schemaName}.row (props, table_id)
values ($1::jsonb, $2)
returning *`,
[JSON.stringify(rolProps), +table.id],
RowAdapter
)
}
10 changes: 6 additions & 4 deletions src/server/repository/assessment/row/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { getManyCache } from './getManyCache'
import { getOne } from './getOne'
import { getVariablesCache } from './getVariablesCache'
import { create } from 'server/repository/assessment/row/create'
import { getManyCache } from 'server/repository/assessment/row/getManyCache'
import { getOne } from 'server/repository/assessment/row/getOne'
import { getVariablesCache } from 'server/repository/assessment/row/getVariablesCache'

export const RowRepository = {
getOne,
create,
getManyCache,
getOne,
getVariablesCache,
}
17 changes: 10 additions & 7 deletions src/server/repository/assessment/table/getOne.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { Objects } from 'utils/objects'

import { Assessment, Cycle, Table, TableName } from 'meta/assessment'

import { BaseProtocol, DB, Schemas } from 'server/db'
import { TableAdapter } from 'server/repository/adapter'

type Props = {
assessment: Assessment
cycle: Cycle
cycle?: Cycle
tableName: TableName
}

Expand All @@ -16,12 +18,13 @@ export const getOne = async (props: Props, client: BaseProtocol = DB): Promise<T

return client.one<Table>(
`
select t.*
from ${schemaName}.table t
where props ->> 'name' = $2
and props -> 'cycles' ? $1;
`,
[cycle.uuid, props.tableName],
select t.*
from ${schemaName}.table t
where props ->> 'name' = $1
${Objects.isEmpty(cycle) ? '' : `and props -> 'cycles' ? $2`}
;
`,
[props.tableName, cycle?.uuid],
TableAdapter
)
}
6 changes: 6 additions & 0 deletions src/server/service/file/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ export const fileTypes = {
downloadName: `BiomassCalculator_${domain}`,
fileType: 'xlsx',
}),
sdgMetadata: (key: string) => ({
key,
folder: `sdgMetadata`,
downloadName: key,
fileType: 'pdf',
}),
}

const _getRepositoryPath = (): string => path.resolve(__dirname, '..', '..', 'static', 'fileRepository')
Expand Down
Binary file not shown.
Binary file not shown.
Loading

0 comments on commit 70d7143

Please sign in to comment.