Skip to content

Commit

Permalink
Merge branch 'development' into 4033-nationaldata-datasources-cycle-2029
Browse files Browse the repository at this point in the history
  • Loading branch information
minotogna authored Oct 16, 2024
2 parents 45d2f2a + 60fc942 commit 0ebef8b
Show file tree
Hide file tree
Showing 35 changed files with 380 additions and 103 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
"@types/lodash.isequal": "^4.5.5",
"@types/lodash.isfunction": "^3.0.6",
"@types/lodash.isnil": "^4.0.6",
"@types/lodash.merge": "^4.6.9",
"@types/lodash.pick": "^4.4.7",
"@types/lodash.range": "^3.2.6",
"@types/lodash.reverse": "^4.0.6",
Expand Down Expand Up @@ -213,6 +214,7 @@
"lodash.isequal": "^4.5.0",
"lodash.isfunction": "^3.0.9",
"lodash.isnil": "^4.0.0",
"lodash.merge": "^4.6.2",
"lodash.pick": "^4.4.0",
"lodash.range": "^3.2.0",
"lodash.reverse": "^4.0.1",
Expand Down
8 changes: 4 additions & 4 deletions src/client/pages/CountryHome/Overview/Overview.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import React from 'react'

import { useSections } from 'client/store/metadata'
import { useDashboardItems, useGetDashboard, useSections } from 'client/store/metadata'
import Dashboard from 'client/components/Dashboard'
import { useDashboardItems } from 'client/pages/CountryHome/Overview/hooks'

const Overview: React.FC = () => {
const sections = useSections()
const items = useDashboardItems()
useGetDashboard()

const sections = useSections()
if (!sections) return null
if (!sections || !items) return null

return <Dashboard items={items} />
}
Expand Down
63 changes: 0 additions & 63 deletions src/client/pages/CountryHome/Overview/hooks/index.ts

This file was deleted.

21 changes: 21 additions & 0 deletions src/client/store/metadata/actions/getDashboard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { createAsyncThunk } from '@reduxjs/toolkit'
import axios from 'axios'

import { ApiEndPoint } from 'meta/api/endpoint'
import { AreaCode } from 'meta/area'
import { AssessmentName, CycleName } from 'meta/assessment'
import { DashboardItem } from 'meta/dashboard'

type Returned = Array<DashboardItem>

type Props = {
assessmentName: AssessmentName
cycleName: CycleName
countryIso: AreaCode
}

export const getDashboard = createAsyncThunk<Returned, Props>('metadata/dashboard/get', async (props) => {
const params = { ...props }
const { data } = await axios.get(ApiEndPoint.CycleData.Dashboard.one(), { params })
return data
})
16 changes: 16 additions & 0 deletions src/client/store/metadata/extraReducers/getDashboardReducer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { ActionReducerMapBuilder } from '@reduxjs/toolkit'
import { Objects } from 'utils/objects'

import { Areas } from 'meta/area'

import { getDashboard } from 'client/store/metadata/actions/getDashboard'
import { DashboardAreaType, MetadataState } from 'client/store/metadata/state'

export const getDashboardReducer = (builder: ActionReducerMapBuilder<MetadataState>): void => {
builder.addCase(getDashboard.fulfilled, (state, action) => {
const { assessmentName, cycleName, countryIso } = action.meta.arg
const key = Areas.isISOCountry(countryIso) ? DashboardAreaType.Country : DashboardAreaType.Region

Objects.setInPath({ obj: state.dashboard, path: [assessmentName, cycleName, key], value: action.payload })
})
}
14 changes: 14 additions & 0 deletions src/client/store/metadata/hooks/useDashboardItems.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Areas } from 'meta/area'
import { DashboardItem } from 'meta/dashboard'

import { MetadataSelectors } from 'client/store/metadata/selectors'
import { useAppSelector } from 'client/store/store'
import { useCountryRouteParams } from 'client/hooks/useRouteParams'

import { DashboardAreaType } from '../state'

export const useDashboardItems = (): Array<DashboardItem> => {
const { assessmentName, cycleName, countryIso } = useCountryRouteParams()
const key = Areas.isISOCountry(countryIso) ? DashboardAreaType.Country : DashboardAreaType.Region
return useAppSelector((state) => MetadataSelectors.getDashboard(state, assessmentName, cycleName, key))
}
19 changes: 19 additions & 0 deletions src/client/store/metadata/hooks/useGetDashboard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { useEffect } from 'react'

import { useAppDispatch } from 'client/store'
import { useCountryRouteParams } from 'client/hooks/useRouteParams'

import { MetadataActions } from '../slice'
import { useDashboardItems } from './useDashboardItems'

export const useGetDashboard = () => {
const dispatch = useAppDispatch()
const { assessmentName, cycleName, countryIso } = useCountryRouteParams()
const dashboardItems = useDashboardItems()

useEffect(() => {
if (!dashboardItems) {
dispatch(MetadataActions.getDashboard({ assessmentName, cycleName, countryIso }))
}
}, [assessmentName, cycleName, countryIso, dispatch, dashboardItems])
}
3 changes: 3 additions & 0 deletions src/client/store/metadata/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
export { useDashboardItems } from './hooks/useDashboardItems'
export { useGetDashboard } from './hooks/useGetDashboard'
export { useGetTableSections } from './hooks/useGetTableSections'
export { usePreviousSection, useSection, useSections } from './hooks/useSections'
export { useTableSections, useTableSectionsCycle } from './hooks/useTableSections'
export { MetadataSelectors } from './selectors'
export { MetadataActions } from './slice'
export type { MetadataState } from './state'
export { DashboardAreaType } from './state'
13 changes: 13 additions & 0 deletions src/client/store/metadata/selectors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { createSelector } from '@reduxjs/toolkit'

import { AssessmentName, CycleName } from 'meta/assessment'

import { DashboardAreaType } from 'client/store/metadata/state'
import { RootState } from 'client/store/RootState'

const getSections = createSelector(
Expand All @@ -12,6 +13,18 @@ const getSections = createSelector(
],
(metadataState, assessmentName, cycleName) => metadataState.sections?.[assessmentName]?.[cycleName]
)

const getDashboard = createSelector(
[
(state: RootState) => state.metadata,
(_state: RootState, assessmentName: AssessmentName) => assessmentName,
(_state: RootState, _assessmentName: AssessmentName, cycleName: CycleName) => cycleName,
(_state: RootState, _assessmentName: AssessmentName, _cycleName: CycleName, key: DashboardAreaType) => key,
],
(metadataState, assessmentName, cycleName, key) => metadataState.dashboard?.[assessmentName]?.[cycleName]?.[key]
)

export const MetadataSelectors = {
getSections,
getDashboard,
}
4 changes: 4 additions & 0 deletions src/client/store/metadata/slice.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { createSlice, Reducer } from '@reduxjs/toolkit'

import { getDashboard } from 'client/store/metadata/actions/getDashboard'
import { getSections } from 'client/store/metadata/actions/getSections'
import { getTableSections } from 'client/store/metadata/actions/getTableSections'
import { getDashboardReducer } from 'client/store/metadata/extraReducers/getDashboardReducer'
import { getSectionsReducer } from 'client/store/metadata/extraReducers/getSectionsReducer'
import { setTableSectionsReducer } from 'client/store/metadata/extraReducers/setTableSectionsReducer'
import { initialState, MetadataState } from 'client/store/metadata/state'
Expand All @@ -13,13 +15,15 @@ export const metadataSlice = createSlice({
extraReducers: (builder) => {
getSectionsReducer(builder)
setTableSectionsReducer(builder)
getDashboardReducer(builder)
},
})

export const MetadataActions = {
...metadataSlice.actions,
getSections,
getTableSections,
getDashboard,
}

export default metadataSlice.reducer as Reducer<MetadataState>
16 changes: 16 additions & 0 deletions src/client/store/metadata/state.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,28 @@
import { AssessmentName, CycleName, Section, TableSection } from 'meta/assessment'
import { SectionName } from 'meta/assessment/section'
import { DashboardItem } from 'meta/dashboard'

export enum DashboardAreaType {
Region = 'region',
Country = 'country',
}

type DashboardState = Record<
AssessmentName,
Record<
CycleName,
{ [DashboardAreaType.Region]?: Array<DashboardItem>; [DashboardAreaType.Country]?: Array<DashboardItem> }
>
>

export interface MetadataState {
sections: Record<AssessmentName, Record<CycleName, Array<Section>>>
tableSections: Record<AssessmentName, Record<CycleName, Record<SectionName, Array<TableSection>>>>
dashboard: DashboardState
}

export const initialState: MetadataState = {
sections: {},
tableSections: {},
dashboard: {},
}
4 changes: 4 additions & 0 deletions src/meta/api/endpoint/ApiEndPoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ export const ApiEndPoint = {
history: (target = ':target') => apiPath('cycle-data', 'history', target),
historyCount: (target = ':target') => apiPath('cycle-data', 'history', target, 'count'),

Dashboard: {
one: () => apiPath('cycle-data', 'dashboard'),
},

Descriptions: {
many: () => apiPath('cycle-data', 'descriptions'),

Expand Down
2 changes: 1 addition & 1 deletion src/meta/dashboard/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export type { DashboardItem, DashboardTable } from './dashboard'
export type { DashboardBarChart, DashboardItem, DashboardPieChart, DashboardTable } from './dashboard'
export { DashboardItemType } from './dashboard'
1 change: 1 addition & 0 deletions src/meta/nodeExt/nodeExt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export enum NodeExtCellType {
export enum NodeExtType {
contact = 'contact',
node = 'node',
dashboard = 'dashboard',
}

export type NodeExt<Props, Value extends NodeValue | null = NodeValue> = {
Expand Down
20 changes: 20 additions & 0 deletions src/server/api/cycleData/dashboard/getDashboardItems.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Response } from 'express'

import { CycleRequest } from 'meta/api/request'

import { AssessmentController } from 'server/controller/assessment'
import { DashboardController } from 'server/controller/cycleData/dashboard'
import Requests from 'server/utils/requests'

export const getDashboardItems = async (req: CycleRequest, res: Response) => {
try {
const { assessmentName, cycleName, countryIso } = req.query

const { assessment, cycle } = await AssessmentController.getOneWithCycle({ assessmentName, cycleName })

const result = await DashboardController.getManyItems({ assessment, cycle, countryIso })
Requests.send(res, result)
} catch (e) {
Requests.sendErr(res, e)
}
}
4 changes: 4 additions & 0 deletions src/server/api/cycleData/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as queue from 'express-queue'

import { ApiEndPoint } from 'meta/api/endpoint'

import { getDashboardItems } from 'server/api/cycleData/dashboard/getDashboardItems'
import { getHistory } from 'server/api/cycleData/history/getHistory'
import { getHistoryCount } from 'server/api/cycleData/history/getHistoryCount'
import { AuthMiddleware } from 'server/middleware/auth'
Expand Down Expand Up @@ -193,5 +194,8 @@ export const CycleDataApi = {
express.get(ApiEndPoint.CycleData.Links.count(), AuthMiddleware.requireAdmin, getLinksCount)
express.post(ApiEndPoint.CycleData.Links.verify(), AuthMiddleware.requireAdmin, verifyLinks)
express.get(ApiEndPoint.CycleData.Links.verifyStatus(), AuthMiddleware.requireAdmin, isVerificationInProgress)

// dashboard
express.get(ApiEndPoint.CycleData.Dashboard.one(), getDashboardItems)
},
}
24 changes: 24 additions & 0 deletions src/server/controller/cycleData/dashboard/getManyItems.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Objects } from 'utils/objects'

import { AreaCode, Areas } from 'meta/area'
import { Assessment, Cycle } from 'meta/assessment'
import { DashboardItem, DashboardItemType } from 'meta/dashboard'

import { NodeExtRepository } from 'server/repository/assessmentCycle/nodeExt'

type Props = {
assessment: Assessment
cycle: Cycle
countryIso: AreaCode
}

export const getManyItems = async (props: Props): Promise<Array<DashboardItem<DashboardItemType>>> => {
const { assessment, cycle, countryIso } = props
const isISOCountry = Areas.isISOCountry(countryIso)
const countryDashboardItems = await NodeExtRepository.getManyDashboardItems({ assessment, cycle })
if (isISOCountry) return countryDashboardItems

const regionDashboardItems = await NodeExtRepository.getManyDashboardItems({ assessment, cycle, region: true })

return Objects.merge(countryDashboardItems, regionDashboardItems)
}
5 changes: 5 additions & 0 deletions src/server/controller/cycleData/dashboard/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { getManyItems } from './getManyItems'

export const DashboardController = {
getManyItems,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Assessment, Cycle } from 'meta/assessment'
import { DashboardItem, DashboardItemType } from 'meta/dashboard'
import { NodeExtType } from 'meta/nodeExt'

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

type Props = { assessment: Assessment; cycle: Cycle; region?: boolean }

export const getManyDashboardItems = async (
props: Props,
client: BaseProtocol = DB
): Promise<Array<DashboardItem<DashboardItemType>>> => {
const { assessment, cycle, region } = props
const schemaCycle = Schemas.getNameCycle(assessment, cycle)
return client.one<Array<DashboardItem<DashboardItemType>>>(
`
select value
from ${schemaCycle}.node_ext
where type = $1
${
region
? `and (props->>'region')::boolean = true`
: `and (props->>'region' is null or (props->>'region')::boolean = false)`
}
`,
[NodeExtType.dashboard],
(result) => result.value
)
}
2 changes: 2 additions & 0 deletions src/server/repository/assessmentCycle/nodeExt/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { getManyContacts } from './getManyContacts'
import { getManyDashboardItems } from './getManyDashboardItems'
import { removeContact } from './removeContact'
import { upsert } from './upsert'

export const NodeExtRepository = {
getManyContacts,
getManyDashboardItems,
removeContact,
upsert,
}
Loading

0 comments on commit 0ebef8b

Please sign in to comment.