From a892f8828e00d39e9347b33b06e709b40281da2e Mon Sep 17 00:00:00 2001 From: Vyacheslav Trushkov <36051968+VVlovsky@users.noreply.github.com> Date: Wed, 17 Mar 2021 21:09:15 +0100 Subject: [PATCH] TASK-314 Another iteration over excel layout of exported schedule (#278) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * bugfixes * implements function to decide font color * added links * small fixes Co-authored-by: Tomasz Pęcak --- .../schedule-export.logic.ts | 103 +++++++++++------- 1 file changed, 65 insertions(+), 38 deletions(-) diff --git a/src/logic/schedule-exporter/schedule-export.logic.ts b/src/logic/schedule-exporter/schedule-export.logic.ts index 8f8332fa3..88c7752a4 100644 --- a/src/logic/schedule-exporter/schedule-export.logic.ts +++ b/src/logic/schedule-exporter/schedule-export.logic.ts @@ -118,27 +118,29 @@ export class ScheduleExportLogic { this.addStyles(workSheet, schedule, headerLen, nurseLastIndex, babysitterLastIndex); workSheet.mergeCells("B1:AF1"); - workSheet.mergeCells( - this.requiredHoursAddress.slice(0, this.requiredHoursAddress.length - 1) + - "2:" + - this.requiredHoursAddress - ); - workSheet.mergeCells( - this.doneHoursAddress.slice(0, this.doneHoursAddress.length - 1) + - "2:" + - this.doneHoursAddress - ); - workSheet.mergeCells( - this.diffHoursAddress.slice(0, this.diffHoursAddress.length - 1) + - "2:" + - this.diffHoursAddress - ); - workSheet.getCell(this.requiredHoursAddress).value = "Wymagane"; - workSheet.getCell(this.doneHoursAddress).value = "Wypracowane"; - workSheet.getCell(this.diffHoursAddress).value = "Nadgodziny"; - workSheet.getCell(this.requiredHoursAddress).alignment = { textRotation: -90 }; - workSheet.getCell(this.doneHoursAddress).alignment = { textRotation: -90 }; - workSheet.getCell(this.diffHoursAddress).alignment = { textRotation: -90 }; + if (this.overtimeExport) { + workSheet.mergeCells( + this.requiredHoursAddress.slice(0, this.requiredHoursAddress.length - 1) + + "2:" + + this.requiredHoursAddress + ); + workSheet.mergeCells( + this.doneHoursAddress.slice(0, this.doneHoursAddress.length - 1) + + "2:" + + this.doneHoursAddress + ); + workSheet.mergeCells( + this.diffHoursAddress.slice(0, this.diffHoursAddress.length - 1) + + "2:" + + this.diffHoursAddress + ); + workSheet.getCell(this.requiredHoursAddress).value = "Wymagane"; + workSheet.getCell(this.doneHoursAddress).value = "Wypracowane"; + workSheet.getCell(this.diffHoursAddress).value = "Nadgodziny"; + workSheet.getCell(this.requiredHoursAddress).alignment = { textRotation: -90 }; + workSheet.getCell(this.doneHoursAddress).alignment = { textRotation: -90 }; + workSheet.getCell(this.diffHoursAddress).alignment = { textRotation: -90 }; + } } private setWorkersWorkSheet(workSheet: xlsx.Worksheet): void { @@ -245,12 +247,28 @@ export class ScheduleExportLogic { this.getRightCornerIndexes(cell, cellValue); if ((cellValue && ShiftCode[cellValue]) || isShiftRow) { isShiftRow = true; - workSheet.getColumn(colNumber).width = 4; + workSheet.getColumn(colNumber).width = 5; } }); }); } + // the values are based on w3c recommendations. + // We need to determine the color with the highest contrast. + // https://www.w3.org/TR/WCAG20/#relativeluminancedef + // https://www.w3.org/TR/WCAG20/#contrast-ratiodef + public decideBlackOrWhite(color: Color): string { + const black = "000000"; + const white = "FFFFFF"; + const rgb = [color.r, color.b, color.g]; + const linearRgb = rgb.map((c) => { + c = c / 255.0; + return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4; + }); + const luminance = 0.2126 * linearRgb[0] + 0.7152 * linearRgb[1] + 0.0722 * linearRgb[2]; + return luminance > 0.179 ? black : white; + } + private getShiftStyle(code: ShiftCode, verboseDate?: VerboseDate): Partial { const shiftFillColor = ShiftHelper.getShiftColor(code, verboseDate).backgroundColor; const borderColor: Partial = { @@ -273,6 +291,13 @@ export class ScheduleExportLogic { left: borderColor, right: borderColor, }, + font: { + color: { + argb: this.decideBlackOrWhite( + ShiftHelper.getShiftColor(code, verboseDate).backgroundColor + ), + }, + }, }; } @@ -287,21 +312,23 @@ export class ScheduleExportLogic { [WorkerType.NURSE]: [] as string[][], [WorkerType.OTHER]: [] as string[][], }; - Object.keys(scheduleModel.shifts || {}).forEach((workerName: string) => { - const category = scheduleModel.employee_info.type[workerName] ?? ""; - const shiftsRow: string[] = [ - workerName, - ...scheduleModel.shifts[workerName]?.map((s) => (s === ShiftCode.W ? "" : s)), - ]; - if (this.overtimeExport) { - shiftsRow.push( - ...WorkerHourInfo.fromSchedules(workerName, scheduleModel, this.primaryScheduleModel) - .asArray() - .map((e) => e.toString()) - ); - } - grouped[category].push(shiftsRow); - }); + Object.keys(scheduleModel.shifts || {}) + .sort() + .forEach((workerName: string) => { + const category = scheduleModel.employee_info.type[workerName] ?? ""; + const shiftsRow: string[] = [ + workerName, + ...scheduleModel.shifts[workerName]?.map((s) => (s === ShiftCode.W ? "" : s)), + ]; + if (this.overtimeExport) { + shiftsRow.push( + ...WorkerHourInfo.fromSchedules(workerName, scheduleModel, this.primaryScheduleModel) + .asArray() + .map((e) => e.toString()) + ); + } + grouped[category].push(shiftsRow); + }); return [grouped[WorkerType.NURSE], grouped[WorkerType.OTHER]]; } @@ -329,7 +356,7 @@ export class ScheduleExportLogic { private static createChildrenInfoSection( scheduleModel: MonthDataModel ): (number | ChildrenSectionKey)[][] { - // in case if it will be more complecated section + // in case if it will be more complicated section return [ [ ChildrenSectionKey.RegisteredChildrenCount,