@ministryofjustice/hmpps-digital-prison-reporting-frontend
Version:
The Digital Prison Reporting Frontend contains templates and code to help display data effectively in UI applications.
256 lines (255 loc) • 9.86 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const urlHelper_1 = __importDefault(require("../urlHelper"));
const DateMapper_1 = __importDefault(require("../DateMapper/DateMapper"));
class DataTableBuilder {
constructor(fields, sortData = false) {
this.columns = [];
this.reportSummaries = {};
// Sortable headers only
this.reportQuery = null;
this.currentQueryParams = null;
this.dateMapper = new DateMapper_1.default();
this.fields = fields;
this.sortData = sortData;
}
mapDate(isoDate) {
if (!isoDate)
return '';
return this.dateMapper.toDateString(isoDate, 'local-datetime-short-year');
}
mapBoolean(value) {
if (!value)
return '';
return value.substring(0, 1).toUpperCase() + value.substring(1).toLowerCase();
}
mapRow(rowData, extraClasses = '', overrideFields = []) {
return this.fields
.filter((f) => this.columns.includes(f.name))
.map((f) => {
const overrideField = overrideFields.find((o) => o.name === f.name);
const field = overrideField !== null && overrideField !== void 0 ? overrideField : f;
return this.mapCell(field, rowData, extraClasses);
});
}
mapCell(field, rowData, extraClasses = '') {
const text = this.mapCellValue(field, rowData[field.name]);
let fieldFormat = 'string';
let classes = extraClasses;
if (field.wordWrap) {
classes += ` data-table-cell-wrap-${field.wordWrap.toLowerCase()}`;
}
if (field.header) {
classes += ' govuk-table__header';
}
if (field.type === 'double' || field.type === 'long') {
fieldFormat = 'numeric';
}
const isHtml = field.type === 'HTML';
const cell = {
fieldName: field.name,
...(isHtml ? { html: text } : { text }),
format: fieldFormat,
classes: classes.trim(),
};
return cell;
}
mapCellValue(field, cellData) {
if (field.calculated) {
return cellData;
}
switch (field.type) {
case 'boolean':
return this.mapBoolean(cellData);
case 'date':
case 'time':
return this.mapDate(cellData);
default:
return cellData;
}
}
mapHeader(disableSort = false, extraClasses = null) {
return this.fields
.filter((field) => this.columns.includes(field.name))
.map((f) => {
if (this.reportQuery && !disableSort) {
if (f.sortable) {
let sortDirection = 'none';
let url = (0, urlHelper_1.default)(this.currentQueryParams, {
sortColumn: f.name,
sortedAsc: 'true',
});
if (f.name === this.reportQuery.sortColumn) {
sortDirection = this.reportQuery.sortedAsc ? 'ascending' : 'descending';
if (this.reportQuery.sortedAsc) {
url = (0, urlHelper_1.default)(this.currentQueryParams, {
sortColumn: f.name,
sortedAsc: 'false',
});
}
}
return {
html: `<a ` +
`data-column="${f.name}" ` +
`class="data-table-header-button data-table-header-button-sort-${sortDirection}" ` +
`href="${url}"` +
`>${f.display}</a>`,
classes: extraClasses,
};
}
}
return {
text: f.display,
classes: extraClasses,
};
});
}
mapData(data) {
const mappedHeaderSummary = this.mapSummary('table-header');
const mappedTableData = this.mergeCells(data.map((rowData) => this.mapRow(rowData)));
const mappedFooterSummary = this.mapSummary('table-footer');
return mappedHeaderSummary.concat(mappedTableData).concat(mappedFooterSummary);
}
mergeCells(rows) {
const mergeFieldNames = this.fields.filter((f) => f.mergeRows).map((f) => f.name);
if (mergeFieldNames.length === 0) {
return rows;
}
const occurrences = {};
mergeFieldNames.forEach((f) => {
occurrences[f] = rows.reduce((accumulator, currentRow) => {
var _a, _b;
const currentCell = this.getCellByFieldName(currentRow, f);
const cellValue = (_a = currentCell.text) !== null && _a !== void 0 ? _a : currentCell.html;
return {
...accumulator,
[cellValue]: ((_b = accumulator[cellValue]) !== null && _b !== void 0 ? _b : 0) + 1,
};
}, {});
});
return rows.map((row) => {
let mergedRow = [...row];
mergeFieldNames.forEach((mergeFieldName) => {
var _a;
const currentRowCell = this.getCellByFieldName(row, mergeFieldName);
const cellValue = (_a = currentRowCell.text) !== null && _a !== void 0 ? _a : currentRowCell.html;
const occurrencesOfValue = occurrences[mergeFieldName][cellValue];
switch (occurrencesOfValue) {
case -1:
mergedRow = mergedRow.filter((c) => c.fieldName !== mergeFieldName);
break;
case 1:
break;
default:
currentRowCell.rowspan = occurrencesOfValue;
occurrences[mergeFieldName][cellValue] = -1;
}
});
return mergedRow;
});
}
getCellByFieldName(row, fieldName) {
return row.find((c) => c.fieldName === fieldName);
}
mapSummary(template) {
if (this.reportSummaries[template]) {
return this.reportSummaries[template].flatMap((reportSummary) => reportSummary.data.map((rowData) => this.mapRow(rowData, `dpr-report-summary-cell dpr-report-summary-cell-${template}`, reportSummary.fields)));
}
return [];
}
sort(data) {
return this.appendSortKeyToData(data)
.sort(this.sortKeyComparison())
.map((d) => ({
...d,
}));
}
sortKeyComparison() {
return (a, b) => {
const aValue = a.sortKey;
const bValue = b.sortKey;
if (aValue === bValue) {
return 0;
}
if (aValue < bValue) {
return -1;
}
return 1;
};
}
appendSortKeyToData(data, fields = null) {
const sortFields = fields || this.fields;
return data.map((rowData) => {
const sortKey = this.getSortKey(rowData, sortFields);
return {
...rowData,
sortKey,
};
});
}
mapNamesToFields(names) {
return names.map((s) => this.fields.find((f) => f.name === s));
}
getSortKey(rowData, sortFields) {
return sortFields
.map((f) => {
const value = rowData[f.name];
if (value === null) {
return 'zzzzzzzz';
}
if (this.dateMapper.isDate(value)) {
return this.dateMapper.toDateString(value, 'iso');
}
return this.mapCellValue(f, value);
})
.join('-')
.toLowerCase();
}
convertDataTableToHtml(dataTable) {
const headers = dataTable.head.map((h) => { var _a; return `<th scope='col' class='govuk-table__header'>${(_a = h.html) !== null && _a !== void 0 ? _a : h.text}</th>`; });
const rows = dataTable.rows.map((r) => `<tr class='govuk-table__row'>${r
.map((c) => { var _a; return `<td class='govuk-table__cell govuk-table__cell--${c.format} ${c.classes}'>${(_a = c.html) !== null && _a !== void 0 ? _a : c.text}</td>`; })
.join('')}</tr>`);
return ("<table class='govuk-table'>" +
`<thead class='govuk-table__head'>${headers.join('')}</thead>` +
`<tbody class='govuk-table__body'>${rows.join('')}</tbody>` +
'</table>');
}
withHeaderOptions({ reportQuery, columns, interactive, }) {
if (interactive) {
return this.withHeaderSortOptions(reportQuery);
}
return this.withNoHeaderOptions(columns);
}
withHeaderSortOptions(reportQuery) {
this.reportQuery = reportQuery;
this.columns = reportQuery.columns;
this.currentQueryParams = this.reportQuery.toRecordWithFilterPrefix();
return this;
}
withNoHeaderOptions(columns) {
this.columns = columns;
return this;
}
buildTable(data) {
const mappedData = this.mapData(this.sortData ? this.sort(data) : data);
return {
head: this.mapHeader(),
rows: mappedData,
rowCount: data.length,
colCount: this.columns.length,
};
}
withSummaries(reportSummaries) {
this.reportSummaries = reportSummaries;
return this;
}
withSortedData(sortData = true) {
this.sortData = sortData;
return this;
}
}
exports.default = DataTableBuilder;