tubular-common
Version:
Tubular Common Models and Data Transformer
116 lines (95 loc) • 4.13 kB
text/typescript
import { ColumnDataType, type ColumnModel, parseDateColumnValue } from './Models';
export const parsePayload = (row: Record<string, unknown>, columns: ColumnModel[]): Record<string, unknown> =>
columns.reduce((obj: Record<string, unknown>, column: ColumnModel, key: number) => {
obj[column.name] = row[key] || row[column.name];
return obj;
}, {});
export const getColumnAlign = (column: ColumnModel): 'inherit' | 'left' | 'center' | 'right' | 'justify' => {
switch (column.dataType) {
case ColumnDataType.Numeric:
return 'right';
case ColumnDataType.Boolean:
return 'center';
default:
return 'inherit';
}
};
const getRealCellValue = (column: ColumnModel, value: unknown, isHeader = false): string => {
if (isHeader) return String(value);
switch (column.dataType) {
case ColumnDataType.Date:
case ColumnDataType.DateTime:
case ColumnDataType.DateTimeUtc:
return value ? parseDateColumnValue(column, String(value)) : '';
case ColumnDataType.Boolean:
return value === true ? 'Yes' : 'No';
default:
return String(value ?? '');
}
};
const getCellValue = (column: ColumnModel, row: unknown, isHeader) =>
column.isComputed
? column.getComputedStringValue(column, row, isHeader)
: getRealCellValue(column, row[column.name], isHeader);
const processRow = (row: unknown, columns: ColumnModel[], isHeader: boolean): string => {
const finalVal = columns.reduce<string>((prev: string, currentColumn: ColumnModel) => {
const result = `"${getCellValue(currentColumn, row, isHeader).replace(/"/g, '""')}"`;
return `${prev}${result},`;
}, '');
return `${finalVal.replace(/(^,)|(,$)/g, '')}\n`;
};
const visibleColumns = (c: ColumnModel) => (c.visible && c.exportable) || (c.isComputed && !c.getComputedStringValue);
export const getCsv = (gridResult: unknown[], columns: ColumnModel[]): string => {
const exportableColumns = columns.filter(visibleColumns);
const headers = processRow(
exportableColumns
.map((x) => ({ [x.name]: x.label }))
// biome-ignore lint/performance/noAccumulatingSpread: <explanation>
.reduce((prev, current) => ({ ...prev, ...current }), {}),
exportableColumns,
true,
);
return gridResult.reduce(
(prev, row) => String(prev) + processRow(row, exportableColumns, false),
headers,
) as string;
};
export const getHtml = (gridResult: unknown[], columns: ColumnModel[]): string => {
const exportableColumns = columns.filter(visibleColumns);
const headers = exportableColumns.reduce((prev, el) => `${prev}<th>${el.label || el.name}</th>`, '');
return `<table class="table table-bordered table-striped"><thead><tr>${headers}</tr></thead><tbody>${
gridResult.reduce(
(prevRow, row) =>
`${prevRow}<tr>${exportableColumns.reduce(
(prev, currentColumn) => `${prev}<td>${getCellValue(currentColumn, row, false)}</td>`,
'',
)}</tr>`,
'',
) as string
}</tbody></table>`;
};
export const getPages = (currentPage: number, totalRows: number, rowsPerPage: number): number[] => {
const pages: number[] = [];
// Default page limits
const totalPages = Math.ceil(totalRows / rowsPerPage);
let startPage = 1;
let endPage = totalPages;
const maxSize = 6;
const isMaxSized = maxSize < totalPages;
// recompute if maxSize
if (isMaxSized) {
// Current page is displayed in the middle of the visible ones
startPage = Math.max(currentPage - Math.floor(maxSize / 2), 1);
endPage = startPage + maxSize - 1;
// Adjust if limit is exceeded
if (endPage > totalPages) {
endPage = totalPages;
startPage = endPage - maxSize + 1;
}
}
// Add page number links
for (let num = startPage; num <= endPage; num++) {
pages.push(num - 1);
}
return pages;
};