Source: nicu-lytes.js

/**
 * NICU Equivalent Lytes Calculator
 * @since v1.4.0
 * @requires module:util
 * @requires module:formValidation
 * @requires module:logger
 */

// eslint-disable-next-line no-global-assign
$ = require( 'jquery' );
import 'bootstrap';
import '../scss/main.scss';
import { checkValue, displayValue } from './util.js';
import { default as setupValidation } from './formValidation.js';
import * as LOG from './logger.js';

/**
 * Length of timeout (in ms) for event handlers that use elements from other modules
 */
const MODULE_DELAY = 100;
let validatedFields;
const comps = [
  { ident: 'NaCl', sodium: 1 },
  { ident: 'NaAcet', sodium: 1 },
  { ident: 'KCl', potassium: 1 },
  { ident: 'KPhos', potassium: 1, phosphate: 1 },
  { ident: 'CaGluc', calcium: 1 },
  { ident: 'NaPhos', sodium: 1, phosphate: 1 },
  { ident: 'MgSulf', magnesium: 1 },
  { ident: 'KAcet', potassium: 1 },
];
//---------------------------------------------------------------
// ON PAGE LOAD

$( () => {
  if ( /debug/.test( location.search ) ) {
    LOG.enable();
    LOG.presetValues();
    $('#nicu-lytes-weight').val(0.785);
    $('#nicu-lytes-dailyRatePerKg').val(160);
    calculateNicuFluid();
  } else if ( /log/.test( location.search ) ) {
    LOG.enable();
  }

  validatedFields = setupValidation([
    { selector: '#nicu-lytes-weight', min: 0, max: 40 },
    { selector: '#nicu-lytes-dailyRatePerKg', min: 0, max: 999 },
    { selector: '#nicu-lytes-input-NaCl', min: 0, max: 20 },
    { selector: '#nicu-lytes-input-NaAcet', min: 0, max: 20 },
    { selector: '#nicu-lytes-input-KCl', min: 0, max: 20 },
    { selector: '#nicu-lytes-input-KPhos', min: 0, max: 20 },
    { selector: '#nicu-lytes-input-CaGluc', min: 0, max: 20 },
    { selector: '#nicu-lytes-input-NaPhos', min: 0, max: 20 },
    { selector: '#nicu-lytes-input-MgSulf', min: 0, max: 20 },
    { selector: '#nicu-lytes-input-KAcet', min: 0, max: 20 },
  ]);
  $('#nicu-lytes-name').get(0).focus();
});

$( '#nicu-lytes-reset' ).on( 'click', () => {
  LOG.green( 'Reset' );
  $( '.input-nicu-lytes' ).val(null);
  $( validatedFields ).removeClass( 'invalid' );
  $('#nicu-lytes-name').get(0).focus();
});

$('.input-nicu-lytes').on('keyup', () => {
  setTimeout( () => {
    LOG.yellow('NICU Lytes Input Received');
    calculateNicuFluid();
  }, MODULE_DELAY);
});

/** Class representing a component used in NICU Fluid builder */
class NicuFluidComponent {
  /**
   * Create a NicuFluidComponent
   * @param {NicuFluidComponentParams} cfg 
   */
  constructor( cfg ) {
    this.ident = cfg.ident;
    this.sodium = cfg.sodium || 0;
    this.potassium = cfg.potassium || 0;
    this.calcium = cfg.calcium || 0;
    this.phosphate = cfg.phosphate || 0;
    this.magnesium = cfg.magnesium || 0;
    this.idInput = `nicu-lytes-input-${cfg.ident}`;
    this.idBagDosePerKg = `nicu-lytes-bagDose-${cfg.ident}`;
    this.idBagAmount =  `nicu-lytes-bagAmount-${cfg.ident}`;
    this.idBagConcentration =  `nicu-lytes-bagConc-${cfg.ident}`;
    this.dailyDosePerKg = 0;
    this.bagDosePerKg = 0;
    this.bagAmount = 0;
    this.bagConcentration = 0;
    this.isIncluded = 0;
    return this;
  }
  update({ wt, hourlyRate } = {}) {
    LOG.beginFunction(`Update: ${this.ident}`, arguments);
    this.dailyDosePerKg = checkValue( $( `#${this.idInput}` ).val() );
    if ( this.dailyDosePerKg > 0 && wt > 0 && hourlyRate > 0 ) {
      this.bagDosePerKg =   this.dailyDosePerKg / ( hourlyRate * 24 ) * 250;
      this.bagAmount = this.bagDosePerKg * wt;
      this.bagConcentration = this.bagAmount / 250;
      this.isIncluded = 1;
    } else {
      this.bagDosePerKg = 0;
      this.bagAmount = 0;
      this.bagConcentration = 0;
      this.isIncluded = 0;
    }
    displayValue(`#${this.idBagDosePerKg}`, this.bagDosePerKg, 0.1, ' mEq/kg/bag');
    displayValue(`#${this.idBagAmount}`, this.bagAmount, 0.1, ' mEq/bag');
    displayValue(`#${this.idBagConcentration}`, this.bagConcentration, 0.0001, ' mEq/mL');
    LOG.endResult(this);
  }
}

const components = comps.map( c => new NicuFluidComponent( c ) );

function calculateNicuFluid() {
  
  const wt = checkValue( +$('#nicu-lytes-weight').val(), 0, 40 );
  const dailyRatePerKg = checkValue( +$('#nicu-lytes-dailyRatePerKg').val(), 0, 999 );

  const hourlyRate = dailyRatePerKg * wt / 24;
  displayValue('#nicu-lytes-hourlyRate', hourlyRate, 0.1, ' mL/hr');

  const inputs = { wt, dailyRatePerKg, hourlyRate };
  LOG.cyanGroupCollapsed('Update components');
  components.forEach( c => c.update( inputs ) );
  LOG.groupEnd();

  const totalNaPerBag = components.reduce( ( tot, c ) => { return tot + c.bagAmount * c.sodium }, 0 );
  const totalKPerBag = components.reduce( ( tot, c ) => { return tot + c.bagAmount * c.potassium }, 0);
  const totalCaPerBag = components.reduce( ( tot, c ) => { return tot + c.bagAmount * c.calcium }, 0);
  const totalPhosPerBag = components.reduce( ( tot, c ) => { return tot + c.bagAmount * c.phosphate }, 0);
  const totalMgPerBag = components.reduce( ( tot, c ) => { return tot + c.bagAmount * c.magnesium }, 0);
  const numberOfAdditives = components.reduce( ( tot, c ) => { return tot + c.isIncluded }, 0);
  LOG.log(`Na: ${totalNaPerBag}, K: ${totalKPerBag}, Ca: ${totalCaPerBag}, Phos: ${totalPhosPerBag}, Mg: ${totalMgPerBag}`);

  const totalNaRate =  totalNaPerBag / 250  * hourlyRate;
  const totalKRate =  totalKPerBag / 250  * hourlyRate;
  const totalCaRate =  totalCaPerBag / 250  * hourlyRate;
  const totalPhosRate =  totalPhosPerBag / 250  * hourlyRate;
  const totalMgRate =  totalMgPerBag / 250  * hourlyRate;
  const caPhosProduct = totalCaPerBag * totalPhosPerBag;

  displayValue('#nicu-lytes-total-sodium', totalNaPerBag, 0.1, ' mEq');
  displayValue('#nicu-lytes-total-sodium-rate', totalNaRate, 0.1, ' mEq/hr');
  displayValue('#nicu-lytes-total-potassium', totalKPerBag, 0.1, ' mEq');
  displayValue('#nicu-lytes-total-potassium-rate', totalKRate, 0.1, ' mEq/hr');
  displayValue('#nicu-lytes-total-calcium', totalCaPerBag, 0.1, ' mEq');
  displayValue('#nicu-lytes-total-calcium-rate', totalCaRate, 0.1, ' mEq/hr');
  displayValue('#nicu-lytes-total-phosphate', totalPhosPerBag, 0.1, ' mEq');
  displayValue('#nicu-lytes-total-phosphate-rate', totalPhosRate, 0.1, ' mEq/hr');
  displayValue('#nicu-lytes-total-magnesium', totalMgPerBag, 0.1, ' mEq');
  displayValue('#nicu-lytes-total-magnesium-rate', totalMgRate, 0.1, ' mEq/hr');

  if ( numberOfAdditives > 3 ) {
    $('#nicu-lytes-additive-note').removeClass('hidden');
  } else {
    $('#nicu-lytes-additive-note').addClass('hidden');
  }
  if ( totalNaPerBag > 38.5 ) {
    $('#nicu-lytes-sodium-note').html('Warning: NaCl exceeds the recommended 0.9% concentration');
    $('#nicu-lytes-sodium-note').addClass('alert-danger').removeClass('alert-warning').removeClass('hidden');
  } else if ( totalNaPerBag > 19.3 ) {
    $('#nicu-lytes-sodium-note').html('Warning: NaCl exceeds the recommended 0.45% concentration');
    $('#nicu-lytes-sodium-note').addClass('alert-warning').removeClass('alert-danger').removeClass('hidden');
  } else {
    $('#nicu-lytes-sodium-note').html('');
    $('#nicu-lytes-sodium-note').removeClass('alert-danger').removeClass('alert-warning').addClass('hidden');
  }
  if ( totalKPerBag > 20 ) {
    $('#nicu-lytes-potassium-note').html('Warning: Potassium exceeds the recommended 20 mEq/250 mL concentration');
    $('#nicu-lytes-potassium-note').addClass('alert-danger').removeClass('hidden');
  } else {
    $('#nicu-lytes-potassium-note').html('');
    $('#nicu-lytes-potassium-note').removeClass('alert-danger').addClass('hidden');
  }
  if ( caPhosProduct > 50 ) {
    $('#nicu-lytes-caPhos-note').html('Ca-Phos product is too high, consider supplementing Ca gluconate via IV bolus');
    $('#nicu-lytes-caPhos-note').addClass('alert-danger').removeClass('alert-warning').removeClass('hidden');
  } else if ( totalCaPerBag > 0 && totalPhosPerBag > 0 ) {
    $('#nicu-lytes-caPhos-note').html('Fluid contains both Ca and Phos; ensure that a 0.22 micron filter is used');
    $('#nicu-lytes-caPhos-note').removeClass('alert-danger').addClass('alert-warning').removeClass('hidden');
  } else {
    $('#nicu-lytes-caPhos-note').html('');
    $('#nicu-lytes-caPhos-note').removeClass('alert-danger').removeClass('alert-warning').addClass('hidden');
  }
  const nsEquivRate = hourlyRate * 0.154;
  const hnsEquivRate = hourlyRate * 0.077;
  const qnsEquivRate = hourlyRate * 0.0385;

  displayValue('#nicu-lytes-equivalent-ns', nsEquivRate, 0.1, ' mEq/hr');
  displayValue('#nicu-lytes-equivalent-hns', hnsEquivRate, 0.1, ' mEq/hr');
  displayValue('#nicu-lytes-equivalent-qns', qnsEquivRate, 0.1, ' mEq/hr');

}


/**
 * NICU Fluid Component Parameters
 * @typedef  {Object} NicuFluidComponentParams
 * @property {String} ident        - Identifier
 * @property {Number} [sodium]     - mEq of sodium per mEq of this component
 * @property {Number} [potassium]  - mEq of potassium per mEq of this component
 * @property {Number} [calcium]    - mEq of calcium per mEq of this component
 * @property {Number} [phosphate]  - mEq of phosphate per mEq of this component
 */