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.

172 lines (169 loc) 6 kB
import { DataTableBuilder } from '../../DataTableBuilder/DataTableBuilder.js'; import { SectionedDataHelper } from '../SectionedDataHelper/SectionedDataHelper.js'; import { TemplateBuilder } from '../TemplateBuilder.js'; class ParentChildDataBuilder extends TemplateBuilder { childColumns = []; childVariants = []; childData = []; joinFields = []; childFields = []; parentChildDatasets = []; dataTableBuilder; constructor(variant, defId) { super(variant, defId); this.childVariants = this.variant.childVariants || []; } getChildVariant(childId) { return this.childVariants.find(cv => cv.id === childId); } /** * Exracts the relevant data from the child variant definition * to generate the child table * * @param {string} childId * @return { fields: components['schemas']['FieldDefinition'][], joinFields: string[], columns: string[], name: string } * @memberof ParentChildDataBuilder */ getChildVariantDefinitionData(childId) { const childVariant = this.getChildVariant(childId); let fields = []; let joinFields = []; let columns = []; let name = 'Child report'; if (childVariant && childVariant.specification) { fields = childVariant.specification.fields; joinFields = childVariant && childVariant.specification ? childVariant.joinFields : []; columns = fields.filter(f => f.visible).map(f => f.name); name = childVariant.name; } return { fields, joinFields, columns, name, }; } /** * Maps the parent child rows. * Splits into sections that will become the parent table * * @return {*} {GroupedParentChildDataset[]} * @memberof ParentChildDataBuilder */ mergeParentChildAndGroup(parentData) { const groups = []; let pendingParents = []; parentData.forEach(parentRow => { // Build a dataset for this parent const dataset = { parent: parentRow, children: [], }; // Match against each child dataset this.childData.forEach(child => { const { joinFields } = this.getChildVariantDefinitionData(child.id); const matchedChildren = []; // Compare join fields child.data.forEach(childRow => { const isMatch = joinFields.every(col => { return parentRow[col] === childRow[col]; }); if (isMatch) matchedChildren.push(childRow); }); if (matchedChildren.length) { dataset.children.push({ id: child.id, data: matchedChildren, }); } }); // Always collect the parent pendingParents.push(dataset.parent); // If dataset has children → close the group if (dataset.children.length > 0) { groups.push({ parent: pendingParents, children: dataset.children, }); pendingParents = []; } }); // If leftover parents exist, make a final group (empty children) if (pendingParents.length > 0) { groups.push({ parent: pendingParents, children: [], }); } return groups; } /** * Maps the parent child data to a table data * * @param {GroupedParentChildDataset[]} parentChildGroups * @return {*} {ParentChildData[]} * @memberof ParentChildDataBuilder */ mapToTableData(parentChildGroups) { const parentTableBuilder = new DataTableBuilder(this.fields); return parentChildGroups.map((group) => { const parentTable = parentTableBuilder.withNoHeaderOptions(this.columns).buildTable(group.parent); const children = this.mapChildDataToTableData(group); return { parent: parentTable, children, }; }); } /** * Maps the grouped child data to table data * * @param {GroupedParentChildDataset} group * @return {*} * @memberof ParentChildDataBuilder */ mapChildDataToTableData(group) { return group.children.map(child => { const { fields: childFields, columns: childColumns, name } = this.getChildVariantDefinitionData(child.id); const childTableBuilder = new DataTableBuilder(childFields); const childTable = childTableBuilder.withNoHeaderOptions(childColumns).buildTable(child.data); return { title: name, ...childTable, }; }); } withChildData(childData) { this.childData = childData; return this; } withChildColumns(childColumns) { this.childColumns = childColumns; return this; } build() { const sectionData = new SectionedDataHelper() .withSections(this.sections) .withData(this.data) .withFields(this.fields) .withReportQuery(this.reportQuery) .build(); const { sections } = sectionData; const mappedSections = sections.map((section) => { const groups = this.mergeParentChildAndGroup(section.data); const table = this.mapToTableData(groups); return { ...section, summaries: [], data: table, }; }); return { rowCount: this.data.length, sections: mappedSections, }; } } export { ParentChildDataBuilder }; //# sourceMappingURL=ParentChildDataBuilder.js.map