UNPKG

@ministryofjustice/hmpps-digital-prison-reporting-frontend

Version:

The Digital Prison Reporting Frontend contains templates and code to help display data effectively in UI applications.

309 lines (274 loc) 9.36 kB
import { DashboardDataResponse } from '../../../types/Metrics' import { DashboardUIVisualisation, DashboardVisualisation, DashboardVisualisationColumn, DashboardVisualisationColumns, DashboardVisualisationType, ScorecardVisualisationColumn, } from '../dashboard/types' import { Scorecard, ScorecardGroup, ScorecardTrend } from './types' import DatasetHelper from '../../../utils/datasetHelper' const createScorecards = ( scorecardDefinition: DashboardVisualisation, rawData: DashboardDataResponse[], ): ScorecardGroup[] => { const { columns } = scorecardDefinition const { measures, keys } = columns const dataset = getDataset(scorecardDefinition, rawData) const { earliest, latest, earliestTs, latestTs } = dataset const scorecardFromListValueColumn = (<ScorecardVisualisationColumn[]>measures).find((col) => col.displayValue) const groupKey = DatasetHelper.getGroupKey(keys, latest) let scorecardGroup: ScorecardGroup[] if (!scorecardFromListValueColumn) { scorecardGroup = createScorecardGroupFromColumns(columns, earliest, earliestTs, latest, latestTs, groupKey) } else if (groupKey) { scorecardGroup = createScorecardGroupFromListWithGroups(columns, earliest, earliestTs, latest, latestTs, groupKey) } else { scorecardGroup = createScorecardGroupFromList(columns, earliest, earliestTs, latest, latestTs) } return scorecardGroup } const getDataset = (scorecardDefinition: DashboardVisualisation, rawData: DashboardDataResponse[]) => { const latestData = DatasetHelper.getLastestDataset(rawData) const latestDataSetRows = DatasetHelper.getDatasetRows(scorecardDefinition, latestData) const latestTs = latestDataSetRows[0]?.ts?.raw const latestFiltered = DatasetHelper.filterRowsByDisplayColumns(scorecardDefinition, latestDataSetRows, true) const earliestData = DatasetHelper.getEarliestDataset(rawData) const earliestDataSetRows = DatasetHelper.getDatasetRows(scorecardDefinition, earliestData) const earliestTs = earliestDataSetRows[0]?.ts?.raw const earliestfiltered = DatasetHelper.filterRowsByDisplayColumns(scorecardDefinition, earliestDataSetRows, true) return { earliest: earliestfiltered, earliestTs, latest: latestFiltered, latestTs, } } const createScorecardData = ({ title, value, rag, valueFor, valueFrom, prevVal, groupTitle, }: { title: string value: string | number rag?: number valueFor: string valueFrom: string prevVal: string | number groupTitle?: string }) => { return { title, value, ...(rag && { rag: getRag(rag) }), valueFor, trend: createTrend(valueFor, valueFrom, value, prevVal), ...(groupTitle && { group: groupTitle, }), } } const createScorecard = (scorecardDefinition: DashboardVisualisation, rawData: DashboardDataResponse[]) => { const { columns } = scorecardDefinition const { measures } = columns const displayColumn = measures[0] const { id: valueColumnId, display } = displayColumn const dataset = getDataset(scorecardDefinition, rawData) const { earliest, latest, earliestTs, latestTs } = dataset const scorecordArr: Scorecard[] = latest.map((datasetRow: DashboardDataResponse, index: number) => { const title = display const { rag, raw: value } = datasetRow[valueColumnId] const prevVal = earliest[index][valueColumnId].raw const valueFor = `${latestTs}` const valueFrom = `${earliestTs}` return createScorecardData({ title, value, rag, prevVal, valueFor, valueFrom, }) }) return scorecordArr[0] } const createScorecardGroupFromList = ( columns: DashboardVisualisationColumns, earliest: DashboardDataResponse[], earliestTs: string | number, latest: DashboardDataResponse[], latestTs: string | number, ): ScorecardGroup[] => { const { measures } = columns const valueColumn = (<ScorecardVisualisationColumn[]>measures).find((col) => col.displayValue) const displayColumn = measures.find((col) => { return col.display || col.display === '' }) return [ { title: '', scorecards: latest.map((datasetRow: DashboardDataResponse, index: number) => { const title = displayColumn ? `${displayColumn.display} ${datasetRow[displayColumn.id].raw}` : displayColumn.display const { rag, raw: value } = datasetRow[valueColumn.id] const prevVal = earliest[index][valueColumn.id].raw const valueFor = `${latestTs}` const valueFrom = `${earliestTs}` return createScorecardData({ title, value, rag, prevVal, valueFor, valueFrom, }) }), }, ] } const createScorecardGroupFromColumns = ( columns: DashboardVisualisationColumns, earliest: DashboardDataResponse[], earliestTs: string | number, latest: DashboardDataResponse[], latestTs: string | number, groupKey: DashboardVisualisationColumn, ) => { const { measures } = columns return latest.map((row, rowIndex) => { const groupTitle = `${row[groupKey?.id]?.raw}` || '' return { title: groupKey.display ? `${groupKey.display}: ${groupTitle}` : groupTitle, scorecards: Object.keys(row) .filter((colId) => colId !== groupKey?.id) .map((colId) => { const comparisonRow = earliest[rowIndex] const measure = measures.find((m) => m.id === colId) const title = measure?.display || colId const value = +row[colId].raw const rag = +row[colId].rag const prevVal = comparisonRow[colId]?.raw const valueFor = `${latestTs}` const valueFrom = `${earliestTs}` return createScorecardData({ title, value, rag, prevVal, valueFor, valueFrom, }) }), } }) } const createScorecardGroupFromListWithGroups = ( columns: DashboardVisualisationColumns, earliest: DashboardDataResponse[], earliestTs: string | number, latest: DashboardDataResponse[], latestTs: string | number, groupKey: DashboardVisualisationColumn, ) => { const { measures } = columns const latestGroupedByKey = DatasetHelper.groupRowsByKey(latest, groupKey.id) const earliestGroupedByKey = DatasetHelper.groupRowsByKey(earliest, groupKey.id) const valueColumn = (<ScorecardVisualisationColumn[]>measures).find((col) => col.displayValue) const displayColumn = measures.find((col) => { return col.display || col.display === '' }) const scorecardGroup = latestGroupedByKey.map((group, groupIndex) => { const groupTitle = `${group[0][groupKey?.id]?.raw}` || '' return { title: groupKey.display ? `${groupKey.display}: ${groupTitle}` : groupTitle, scorecards: group.map((row, rowIndex) => { const title = displayColumn ? `${displayColumn.display} ${row[displayColumn.id].raw}` : displayColumn.display const value = +row[valueColumn.id].raw const rag = +row[valueColumn.id].rag const valueFor = `${latestTs}` const valueFrom = `${earliestTs}` const comparisonRow = earliestGroupedByKey[groupIndex][rowIndex] const prevVal = comparisonRow[valueColumn.id]?.raw return createScorecardData({ title, value, rag, prevVal, valueFor, valueFrom, }) }), } }) return scorecardGroup } const getRag = (ragScore: number) => { const ragColors = ['green', 'yellow', 'red'] return { score: ragScore, color: ragColors[ragScore], } } const createTrend = ( valueFor: string, valueFrom: string, latestValue: string | number, earliestValue: string | number, ): ScorecardTrend | undefined => { let trendData if (valueFrom !== valueFor) { const value = +latestValue - +earliestValue const direction = Math.sign(value) trendData = { direction, value: Math.abs(value), from: valueFrom, } } return trendData } const mergeScorecardsIntoGroup = (visualisations: DashboardUIVisualisation[]) => { const groupedScorecardIndexes: number[][] = visualisations // get scorecard indexes .reduce((acc: number[], vis: DashboardUIVisualisation, i: number) => { if (vis.type === DashboardVisualisationType.SCORECARD) acc.push(i) return acc }, []) // group adjacent indexes .reduce((r, n) => { const lastSubArray = r[r.length - 1] if (!lastSubArray || lastSubArray[lastSubArray.length - 1] !== n - 1) r.push([]) r[r.length - 1].push(n) return r }, []) groupedScorecardIndexes.reverse().forEach((group: number[]) => { const spliceAtIndex = group[0] const scorecardGroup: Scorecard[] = group .map((scIndex: number) => { return visualisations[scIndex].data as Scorecard }) .filter((scorecard: Scorecard) => !!scorecard) while (group.length) { visualisations.splice(group.pop(), 1) } if (scorecardGroup.length) { visualisations.splice(spliceAtIndex, 0, { id: `${spliceAtIndex}`, type: DashboardVisualisationType.SCORECARD_GROUP, data: [{ scorecards: scorecardGroup }], }) } }) return visualisations } export default { createScorecard, createScorecards, mergeScorecardsIntoGroup, }