@ministryofjustice/hmpps-digital-prison-reporting-frontend
Version:
The Digital Prison Reporting Frontend contains templates and code to help display data effectively in UI applications.
161 lines (135 loc) • 5.09 kB
text/typescript
import type { ParsedQs } from 'qs'
import { FilteredListRequest } from './index'
import Dict = NodeJS.Dict
import { components } from './api'
import { clearFilterValue } from '../utils/urlHelper'
import ColumnUtils from '../components/_reports/report-columns-form/utils'
import { Template } from './Templates'
export const DEFAULT_FILTERS_PREFIX = 'filters.'
export default class ReportQuery implements FilteredListRequest {
selectedPage: number
pageSize: number
sortColumn?: string
columns: Array<string>
sortedAsc: boolean
filters: Dict<string>
filtersPrefix: string
dataProductDefinitionsPath?: string
constructor({
fields,
template,
queryParams,
definitionsPath,
filtersPrefix = DEFAULT_FILTERS_PREFIX,
}: {
fields: components['schemas']['FieldDefinition'][]
template?: Template
queryParams: ParsedQs
definitionsPath?: string
filtersPrefix?: string
}) {
this.selectedPage = queryParams.selectedPage ? Number(queryParams.selectedPage) : 1
this.pageSize =
queryParams.pageSize && template ? Number(queryParams.pageSize) : this.getDefaultPageSize(template as Template)
this.sortColumn = queryParams.sortColumn ? queryParams.sortColumn.toString() : this.getDefaultSortColumn(fields)
this.sortedAsc = queryParams.sortedAsc !== 'false'
this.dataProductDefinitionsPath =
definitionsPath ??
(queryParams.dataProductDefinitionsPath ? queryParams.dataProductDefinitionsPath.toString() : null)
this.filtersPrefix = filtersPrefix
if (queryParams.columns) {
const columns =
typeof queryParams.columns === 'string' ? queryParams.columns.split(',') : (queryParams.columns as string[])
this.columns = ColumnUtils.ensureMandatoryColumns(fields, columns)
} else {
this.columns = fields.filter((f) => f.visible).map((f) => f.name)
}
let min: string
let max: string
const dateField: components['schemas']['FieldDefinition'] = fields.find((f) => {
return (
(f.type === 'date' && f.filter && f.filter.type === 'daterange') ||
(f.type === 'date' && f.filter && f.filter.type === 'date')
)
})
if (dateField) ({ min, max } = dateField.filter)
this.filters = {}
Object.keys(queryParams)
.filter((key) => key.startsWith(this.filtersPrefix))
.filter((key) => queryParams[key])
.forEach((key) => {
const filter = key.replace(this.filtersPrefix, '')
let value = queryParams[key].toString()
if (filter.includes('.start') && min) {
if (new Date(value) < new Date(min)) value = min
}
if (filter.includes('.end') && max) {
if (new Date(value) > new Date(max)) value = max
}
if (value !== 'no-filter') {
this.filters[filter] = value
}
})
if (dateField && dateField.filter.type === 'daterange') {
if (
min &&
Object.keys(queryParams).some((key) => key.includes(this.filtersPrefix)) &&
Object.keys(queryParams).every((key) => !key.includes('.start'))
) {
this.filters[`${dateField.name}.start`] = min
}
if (
max &&
Object.keys(queryParams).some((key) => key.includes(this.filtersPrefix)) &&
Object.keys(queryParams).every((key) => !key.includes('.end'))
) {
this.filters[`${dateField.name}.end`] = max
}
}
if (dateField && dateField.filter.type === 'date') {
if (
min &&
Object.keys(queryParams).some((key) => key.includes(this.filtersPrefix)) &&
Object.keys(queryParams).every((key) => !key.includes(dateField.name))
) {
this.filters[`${dateField.name}.start`] = min
}
}
}
private getDefaultSortColumn(fields: components['schemas']['FieldDefinition'][]) {
const defaultSortColumn = fields.find((f) => f.defaultsort)
return defaultSortColumn ? defaultSortColumn.name : fields.find((f) => f.sortable)?.name
}
toRecordWithFilterPrefix(removeClearedFilters = false): Record<string, string | Array<string>> {
const record: Record<string, string | Array<string>> = {
selectedPage: this.selectedPage.toString(),
pageSize: this.pageSize.toString(),
sortColumn: this.sortColumn,
sortedAsc: this.sortedAsc.toString(),
columns: this.columns,
}
if (this.dataProductDefinitionsPath) {
record.dataProductDefinitionsPath = this.dataProductDefinitionsPath
}
Object.keys(this.filters).forEach((filterName) => {
const value = this.filters[filterName]
if (!removeClearedFilters || value !== clearFilterValue) {
record[`${this.filtersPrefix}${filterName}`] = value
}
})
return record
}
private getDefaultPageSize(template: Template) {
const maxResultsSize = 50000
const standardPage = 20
switch (template) {
case 'list-section':
case 'summary-section':
case 'row-section-child':
case 'parent-child':
return maxResultsSize
default:
return standardPage
}
}
}