Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(EMS-3539): improve xlsx styled column functions #3251

Merged
merged 10 commits into from
Dec 6, 2024
82 changes: 55 additions & 27 deletions src/api/.keystone/config.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import APPLICATION_INFORMATION_INDEXES from '.';

describe('api/constants/XLSX-CONFIG/INDEXES/APPLICATION_INFORMATION', () => {
it('should return an object with indexes', () => {
const expected = {
EXPORTER_CONTACT_DETAILS: 8,
KEY_INFORMATION: 13,
};

expect(APPLICATION_INFORMATION_INDEXES).toEqual(expected);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* APPLICATION_INFORMATION
* Default indexes for the "Application information" XLSX worksheet.
*/
const APPLICATION_INFORMATION_INDEXES = {
EXPORTER_CONTACT_DETAILS: 8,
KEY_INFORMATION: 13,
};

export default APPLICATION_INFORMATION_INDEXES;
7 changes: 7 additions & 0 deletions src/api/constants/XLSX-CONFIG/INDEXES/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ const { EXPORTER_BUSINESS, POLICY, BUYER, EXPORT_CONTRACT } = SECTION_NAMES;
/**
* XLSX_ROW_INDEXES
* Generate row indexes for each worksheet in the XLSX.
* If a row requires some additional row height - for example, for a multi-line address field,
* The row's index should be listed in the relevant section below.
* No other indexes need to be listed.
* NOTE: The APPLICATION_INFORMATION section indexes are intentionally excluded from here,
* because it does NOT require additional heights.
* - The APPLICATION_INFORMATION indexes are consumed in another area for other, non-height styling purposes.
* - The APPLICATION_INFORMATION has some unique requirements unlike all other sections.
* @returns {Object}
*/
const XLSX_ROW_INDEXES = {
Expand Down
70 changes: 30 additions & 40 deletions src/api/generate-xlsx/styled-columns/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,56 +1,46 @@
import ExcelJS from 'exceljs';
import styledColumns, { worksheetRowHeights } from '.';
import { XLSX_CONFIG } from '../../constants';
import styledColumns, { getAdditionalRowHeightIndexes } from '.';
import XLSX_ROW_INDEXES from '../../constants/XLSX-CONFIG/INDEXES';
import modifyRowStyles from './modify-row-styles';
import modifyRowHeights from './modify-row-heights';
import { mockApplicationMinimalBrokerBuyerAndCompany as mockApplication } from '../../test-mocks';

const { LARGE_ADDITIONAL_COLUMN_HEIGHT, ADDITIONAL_TITLE_COLUMN_HEIGHT, FONT_SIZE } = XLSX_CONFIG;
import createMockWorksheet from '../../test-mocks/create-mock-worksheet';

describe('api/generate-xlsx/styled-columns/index', () => {
const mockSheetName = 'mock sheet name';
const { mockWorksheet, mockSheetName } = createMockWorksheet();

const workbook = new ExcelJS.Workbook();
describe('getAdditionalRowHeightIndexes', () => {
describe('when a provided sheetName is in XLSX_ROW_INDEXES', () => {
it('should return index values', () => {
const result = getAdditionalRowHeightIndexes(mockApplication, mockSheetName);

const worksheet = workbook.addWorksheet(mockSheetName);
const sheetIndexes = XLSX_ROW_INDEXES[mockSheetName](mockApplication);

describe('worksheetRowHeights', () => {
it('should add column heights to particular columns', async () => {
const mockIndexes = [5, 6];
const expected = Object.values(sheetIndexes);

const result = worksheetRowHeights(mockIndexes, worksheet);
expect(result).toEqual(expected);
});
});

result.eachRow((row, rowNumber) => {
if (rowNumber === 1) {
expect(row.height).toEqual(ADDITIONAL_TITLE_COLUMN_HEIGHT);
} else if (mockIndexes.includes(rowNumber)) {
expect(row.height).toEqual(LARGE_ADDITIONAL_COLUMN_HEIGHT);
}
describe('when a provided sheetName is NOT in XLSX_ROW_INDEXES', () => {
it('should return an empty array', () => {
const result = getAdditionalRowHeightIndexes(mockApplication, 'invalid sheet name');

expect(result).toEqual([]);
});
});
});

describe('styledColumns', () => {
it('should add custom `alignment` and font size properties to each column', async () => {
const result = styledColumns(mockApplication, worksheet, mockSheetName);

result.eachRow((row, rowNumber) => {
const isHeaderRow = rowNumber === 1;

if (isHeaderRow) {
row.eachCell((cell, colNumber) => {
const cellData = row.getCell(colNumber);

expect(cellData.font.bold).toEqual(true);
expect(cellData.font.size).toEqual(FONT_SIZE.TITLE);
});
} else {
row.eachCell((cell, colNumber) => {
const cellData = row.getCell(colNumber);

expect(cellData.font.bold).toEqual(false);
expect(cellData.font.size).toEqual(FONT_SIZE.DEFAULT);
});
}
});
it('should return a modified worksheet', async () => {
const result = styledColumns(mockApplication, mockWorksheet, mockSheetName);

const modifiedRowStyles = modifyRowStyles(mockWorksheet, mockSheetName);

const indexes = getAdditionalRowHeightIndexes(mockApplication, mockSheetName);

const expected = modifyRowHeights(indexes, modifiedRowStyles, mockSheetName);

expect(result).toEqual(expected);
});
});
});
79 changes: 20 additions & 59 deletions src/api/generate-xlsx/styled-columns/index.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,29 @@
import { Row, Worksheet } from 'exceljs';
import { XLSX_CONFIG } from '../../constants';
import { Worksheet } from 'exceljs';
import XLSX_ROW_INDEXES from '../../constants/XLSX-CONFIG/INDEXES';
import SECTION_NAMES from '../../constants/XLSX-CONFIG/SECTION_NAMES';
import modifyRowStyles from './modify-row-styles';
import modifyRowHeights from './modify-row-heights';
import { Application } from '../../types';

const { LARGE_ADDITIONAL_COLUMN_HEIGHT, ADDITIONAL_TITLE_COLUMN_HEIGHT, FONT_SIZE } = XLSX_CONFIG;

const { APPLICATION_INFORMATION } = SECTION_NAMES;
// TODO: unit test for getAdditionalRowHeightIndexes

/**
* worksheetRowHeights
* Add custom heights to certain worksheet cells
* @param {Array<number>} rowIndexes: Row indexes
* @param {ExcelJS.Worksheet} worksheet: ExcelJS worksheet
* @param {String} ExcelJS sheetName: worksheet name
* @returns {ExcelJS.Worksheet} ExcelJS worksheet
* getAdditionalRowHeightIndexes
* Get some specific row indexes for the XLSX.
* These indexes are then used for styling purposes.
* @param {Application} application
* @param {String} sheetName: ExcelJS worksheet name
* @returns {Array<number>} Row indexes
*/
export const worksheetRowHeights = (rowIndexes: Array<number>, worksheet: Worksheet, sheetName: string) => {
const modifiedWorksheet = worksheet;

modifiedWorksheet.getRow(1).height = ADDITIONAL_TITLE_COLUMN_HEIGHT;
export const getAdditionalRowHeightIndexes = (application: Application, sheetName: string) => {
let INDEXES = [] as Array<number>;

const isInformationSheet = sheetName === APPLICATION_INFORMATION;
if (XLSX_ROW_INDEXES[sheetName]) {
const sheetIndexes = XLSX_ROW_INDEXES[sheetName](application);

if (isInformationSheet) {
modifiedWorksheet.getRow(8).height = ADDITIONAL_TITLE_COLUMN_HEIGHT;
modifiedWorksheet.getRow(13).height = ADDITIONAL_TITLE_COLUMN_HEIGHT;
INDEXES = Object.values(sheetIndexes);
}

rowIndexes.forEach((rowIndex) => {
modifiedWorksheet.getRow(rowIndex).height = LARGE_ADDITIONAL_COLUMN_HEIGHT;
});

return modifiedWorksheet;
return INDEXES;
};

/**
Expand All @@ -44,43 +35,13 @@ export const worksheetRowHeights = (rowIndexes: Array<number>, worksheet: Worksh
* @returns {ExcelJS.Worksheet} ExcelJS worksheet
*/
const styledColumns = (application: Application, worksheet: Worksheet, sheetName: string) => {
let modifiedWorksheet = worksheet;

modifiedWorksheet.eachRow((row: Row, rowNumber: number) => {
row.eachCell((cell, colNumber) => {
const modifiedRow = row;
const withRowStyles = modifyRowStyles(worksheet, sheetName);

modifiedRow.getCell(colNumber).alignment = {
vertical: 'top',
wrapText: true,
};

const isInformationSheet = sheetName === APPLICATION_INFORMATION;
const isInformationTitleOne = isInformationSheet && rowNumber === 8;
const isInformationTitleTwo = isInformationSheet && rowNumber === 13;

const isInformationTitle = isInformationTitleOne || isInformationTitleTwo;

const isTitleRow = rowNumber === 1 || isInformationTitle;

modifiedRow.getCell(colNumber).font = {
bold: Boolean(isTitleRow),
size: isTitleRow ? FONT_SIZE.TITLE : FONT_SIZE.DEFAULT,
};
});
});

let INDEXES = [] as Array<number>;

if (XLSX_ROW_INDEXES[sheetName]) {
const sheetIndexes = XLSX_ROW_INDEXES[sheetName](application);

INDEXES = Object.values(sheetIndexes);
}
const indexes = getAdditionalRowHeightIndexes(application, sheetName);

modifiedWorksheet = worksheetRowHeights(INDEXES, modifiedWorksheet, sheetName);
const withRowHeights = modifyRowHeights(indexes, withRowStyles, sheetName);

return modifiedWorksheet;
return withRowHeights;
};

export default styledColumns;
56 changes: 56 additions & 0 deletions src/api/generate-xlsx/styled-columns/is-title-row/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import isTitleRow from '.';
import SECTION_NAMES from '../../../constants/XLSX-CONFIG/SECTION_NAMES';
import APPLICATION_INFORMATION_INDEXES from '../../../constants/XLSX-CONFIG/INDEXES/APPLICATION_INFORMATION';

const { APPLICATION_INFORMATION } = SECTION_NAMES;
const { EXPORTER_CONTACT_DETAILS, KEY_INFORMATION } = APPLICATION_INFORMATION_INDEXES;

describe('api/generate-xlsx/styled-columns/is-title-row', () => {
describe(`when the sheetName is ${APPLICATION_INFORMATION}`, () => {
const mockSheetName = APPLICATION_INFORMATION;

describe(`when rowNumber=${EXPORTER_CONTACT_DETAILS}`, () => {
it('should return true', () => {
const result = isTitleRow(mockSheetName, EXPORTER_CONTACT_DETAILS);

expect(result).toEqual(true);
});
});

describe(`when rowNumber=${KEY_INFORMATION}`, () => {
it('should return true', () => {
const result = isTitleRow(mockSheetName, KEY_INFORMATION);

expect(result).toEqual(true);
});
});

describe('when rowNumber is NOT 8 or 13', () => {
it('should return false', () => {
const result = isTitleRow(mockSheetName, 5);

expect(result).toEqual(false);
});
});
});

describe(`when the sheetName is NOT ${APPLICATION_INFORMATION}`, () => {
const mockSheetName = 'Mock sheet name';

describe('when rowNumber=1', () => {
it('should return true', () => {
const result = isTitleRow(mockSheetName, 1);

expect(result).toEqual(true);
});
});

describe('when rowNumber is NOT 1', () => {
it('should return false', () => {
const result = isTitleRow(mockSheetName, 5);

expect(result).toEqual(false);
});
});
});
});
Loading
Loading