From e23caa2eb6f01ca7a7bede9257a740371fcc9fc6 Mon Sep 17 00:00:00 2001 From: Katrina Wheelan Date: Tue, 23 Jul 2024 12:53:50 -0400 Subject: [PATCH] #38 implement personnel tooltips --- src/js/components/tooltip/tooltip.js | 66 ++++++++++++++++++++++++++-- src/js/utils/common_utils.js | 8 +++- src/js/views/04_personnel/helpers.js | 13 +++--- 3 files changed, 76 insertions(+), 11 deletions(-) diff --git a/src/js/components/tooltip/tooltip.js b/src/js/components/tooltip/tooltip.js index 40e1915..aeb6fc1 100644 --- a/src/js/components/tooltip/tooltip.js +++ b/src/js/components/tooltip/tooltip.js @@ -1,4 +1,6 @@ +import { FISCAL_YEAR } from '../../init'; import Cell from '../table/subcomponents/cells'; +import { formatCurrency } from '../../utils/common_utils'; import './tooltip.css' function hideTooltip() { @@ -23,12 +25,48 @@ function showAccountString(event){ Cost Center: ${cc}`) } +function showSalaryProjection(event){ + const row = event.target.parentElement; + const general_increase = Cell.getText(row, 'general-increase-rate'); + const merit_increase = Cell.getText(row, 'merit-increase-rate'); + const current_salary = Cell.getValue(row, 'current-salary'); + const proj_salary = Cell.getValue(row, 'avg-salary'); + if (current_salary){ + var message = `The average salary/wage for this position was + ${formatCurrency(current_salary)} as of September 20${FISCAL_YEAR-2}. With two general + increases of ${general_increase*100}% and a merit increase of ${merit_increase*100}%, the + Budget Office projects that the average annual + salary/wage for this position will be ${formatCurrency(proj_salary)} in FY${FISCAL_YEAR}.`; + } else { + var message = `The average salary/wage for this position was + unknown as of September 20${FISCAL_YEAR-2}, or the position + did not exist. The Budget Office projects that + the average annual salary/wage for this position + will be ${formatCurrency(proj_salary)} in FY2026.` + } + + editTooltipText(message); +} + +function showFinalPersonnelCost(event){ + const row = event.target.parentElement; + const proj_salary = Cell.getValue(row, 'avg-salary'); + const ftes = Cell.getText(row, 'baseline-ftes'); + const fringe = parseFloat(Cell.getText(row, 'fringe')); + const avg_benefits = proj_salary * fringe; + const message = `The total cost captures ${ftes} position(s) at + an annual salary/wage of ${formatCurrency(proj_salary)}, + plus fringe benefits that cost ${formatCurrency(avg_benefits)} + per position per year, on average.` + editTooltipText(message); +} + export const Tooltip = { hide : hideTooltip, show : showTooltip, - link : function(element) { + link : function(element, displayFn) { // add class to show cell with an underline, etc element.classList.add('tooltip-cell'); @@ -37,10 +75,10 @@ export const Tooltip = { const infoIcon = document.createElement('i'); infoIcon.classList.add('fas', 'fa-info-circle', 'info-icon'); element.appendChild(infoIcon); - + // add event listener to show tooltip on mouseover element.addEventListener('click', function (event) { - showAccountString(event); + displayFn(event); showTooltip(); }); // and hide when mouse moves off @@ -58,8 +96,28 @@ export const Tooltip = { linkAccountStringCol : function() { // get all relevant cells document.querySelectorAll('.account-string').forEach( (cell) => { - this.link(cell); + this.link(cell, showAccountString); }) + }, + + linkSalaryCol : function() { + // get all relevant cells + document.querySelectorAll('.avg-salary').forEach( (cell) => { + this.link(cell, showSalaryProjection); + }) + }, + + linkTotalPersonnelCostCol : function() { + // get all relevant cells + document.querySelectorAll('.total-baseline').forEach( (cell) => { + this.link(cell, showFinalPersonnelCost); + }) + }, + + linkAll : function() { + this.linkAccountStringCol(); + this.linkSalaryCol(); + this.linkTotalPersonnelCostCol(); } } diff --git a/src/js/utils/common_utils.js b/src/js/utils/common_utils.js index 3e92ad2..eb154cf 100644 --- a/src/js/utils/common_utils.js +++ b/src/js/utils/common_utils.js @@ -37,6 +37,10 @@ export function cleanString(str){ } export function removeNewLines(str){ - // TODO: ensure there is a space between words on new lines - return str.replaceAll(/[\r\n]+/g, ""); + // replace all new lines with spaces + str = str.replaceAll(/[\r\n]+/g, " "); + // remove any extra spaces or trailing/leading whitespace + str = str.replaceAll(' ', ' '); + str = str.replace(/^\s+|\s+$/g, ''); + return str; } \ No newline at end of file diff --git a/src/js/views/04_personnel/helpers.js b/src/js/views/04_personnel/helpers.js index 1c86478..7a33faf 100644 --- a/src/js/views/04_personnel/helpers.js +++ b/src/js/views/04_personnel/helpers.js @@ -41,9 +41,12 @@ function assignClasses() { { title: 'Total Cost', className: 'total-baseline', isCost: true }, { title: 'Edit', className: 'edit' }, // hidden columns needed for calculations - { title: 'Fringe Benefits Final Request', className: 'fringe', isCost: true, hide: true }, + { title: 'Fringe Benefits Rate', className: 'fringe', hide: true }, { title: 'Appropriation Name', className: 'approp-name', hide: true }, - { title: 'Cost Center Name', className: 'cc-name', hide: true } + { title: 'Cost Center Name', className: 'cc-name', hide: true }, + { title: 'General Increase Rate', className: 'general-increase-rate', hide: true}, + { title: 'Step/Merit Increase Rate', className: 'merit-increase-rate', hide: true}, + { title: `Average Salary/Wage as of 9/1/20${FISCAL_YEAR-2}`, className: 'current-salary', isCost: true, hide: true}, ]; // assign cost classes @@ -71,7 +74,7 @@ export async function initializePersonnelTable(){ Prompt.Text.update('No personnel expenditures for this fund.') } // Link up tooltips to display more info on hover - Tooltip.linkAccountStringCol(); + Tooltip.linkAll(); } function initializeRowAddition(){ @@ -86,11 +89,11 @@ function updateDisplayandTotals(){ for (let i = 1; i < rows.length; i++){ // fetch values for calculations let avg_salary = Table.Cell.getValue(rows[i], 'avg-salary'); - let fringe = Table.Cell.getValue(rows[i], 'fringe'); + let fringe = parseFloat(Table.Cell.getText(rows[i], 'fringe')); let baseline_ftes = Table.Cell.getText(rows[i], 'baseline-ftes'); // calcuate #FTEs x average salary + COLA adjustments + merit adjustments + fringe - let total_baseline_cost = (avg_salary + fringe) * baseline_ftes; + let total_baseline_cost = avg_salary * baseline_ftes * (1 + fringe); // update total column Table.Cell.updateValue(rows[i], 'total-baseline', total_baseline_cost);