"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.CheckboxField = exports.InjectionTypeField = exports.InfusionBolusField = exports.InfusionUnitField = exports.InfusionTypeField = exports.LocalUnitField = exports.OralAdministrationField = exports.SelectField = exports.SignatureField = exports.TimeIncrementField = exports.IncrementButtonField = exports.TextareaField = exports.DecimalInputField = exports.InputField = exports.SelectButtons = exports.Label = void 0;

var _preact = require("preact");

var _classnames = _interopRequireDefault(require("classnames"));

var _incrementors = require("./incrementors");

var _signature = require("./signature");

var _signatureInput = require("./signature-input");

var _button = require("./button");

var _icon = require("./icon");

var _inputs = require("./inputs");

var _suggestionsBox = _interopRequireDefault(require("./suggestions-box"));

var _env = require("./utils/env");

var _decimals = require("./utils/decimals");

var _question = require("./utils/question");

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }

function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }

function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }

function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }

const noOp = () => {};

const Label = ({
  item,
  updateValue,
  removeSuggestion
}) => {
  const isRequired = item.required !== false;
  return (0, _preact.h)("label", {
    className: "db fw6 lh-copy f5 mb1",
    htmlFor: item.name
  }, (0, _preact.h)("div", {
    className: "flex-shrink-0"
  }, (0, _preact.h)("div", {
    className: "flex items-center"
  }, item.label, isRequired && item.isComplete && (0, _preact.h)(_icon.Icon, {
    className: "ml2 light-blue",
    icon: "check",
    size: "18"
  }), isRequired && !item.isComplete && (0, _preact.h)("span", {
    className: "fw3 red ml2"
  }, "(required)"), !isRequired && item.explicitOptional && (0, _preact.h)("span", {
    className: "fw3 gray ml2"
  }, "(optional)")), item.subLabel && (0, _preact.h)("div", {
    className: (0, _classnames.default)('fw3 f6', {
      orange: item.subLabelWarning,
      red: item.subLabelError
    })
  }, item.subLabel instanceof Function ? item.subLabel(item) : item.subLabel)), item.buttons && (0, _preact.h)("div", null, item.buttons.map(option => {
    let label;
    let val;

    if (Array.isArray(option)) {
      label = option[0];
      val = option[1];
    } else {
      label = option;
      val = option;
    }

    return (0, _preact.h)(_button.Button, {
      key: val,
      type: "button",
      "data-e2e": "".concat(item.name, "InputButton:").concat(val),
      className: "mr2 ml0 mt2",
      pressed: item.value === val,
      onClick: e => {
        e.preventDefault();
        updateValue(val);
      }
    }, label);
  })), item.suggestions && (0, _preact.h)(_suggestionsBox.default, {
    removeSuggestion: removeSuggestion,
    name: item.name,
    value: item.value,
    autoSuggestType: item.autoSuggestType,
    updateValue: updateValue,
    suggestions: item.suggestions,
    suggestionsDeleting: item.suggestionsDeleting
  }));
};

exports.Label = Label;
const separator = ', ';

const stringToArray = str => str ? str.toString().split(separator) : [];

const arrayToString = arr => arr.filter(Boolean).join(separator);

class SelectButtons extends _preact.Component {
  constructor(props) {
    super(props);
    this.state = {
      open: false
    };
    this.handleButtonPress = this.handleButtonPress.bind(this);
    this.handleOtherPress = this.handleOtherPress.bind(this);

    this.open = () => {
      if (!this.state.open) {
        this.setState({
          open: true
        });
      }

      setTimeout(() => {
        const input = this.base && this.base.querySelector('input');

        if (input) {
          input.focus();
        }
      }, 200);
    };

    this.close = () => this.setState({
      open: false
    });

    this.choiceValues = props.item.choices.reduce((res, choice) => {
      res[choice.val] = true;
      return res;
    }, {});
  }

  handleButtonPress(val, isPressed) {
    const {
      item,
      updateValue,
      allowDeselect
    } = this.props;
    const preventDeselect = item.allowDeselect === false || allowDeselect === false;
    const isMultiButton = item.type === 'multiButton';
    const {
      value
    } = item;

    if (!isMultiButton) {
      this.close();

      if (isPressed && preventDeselect) {
        return;
      }

      updateValue(isPressed ? null : val);
    } else {
      const values = stringToArray(value);
      const index = values.indexOf(val);

      if (index === -1) {
        values.push(val);
      } else {
        values.splice(index, 1);
      }

      updateValue(arrayToString(values));
    }
  }

  handleOtherPress(isPressed) {
    const {
      updateValue,
      item
    } = this.props;
    const {
      type,
      otherInitText
    } = item;
    const isMultiButton = type === 'multiButton';

    if (!isMultiButton) {
      if (isPressed) {
        this.close();
        updateValue(null);
      } else {
        this.open();
        updateValue(otherInitText || '');
      }
    } else {
      const values = stringToArray(this.props.item.value);

      if (isPressed) {
        this.close();
        const unknownRemoved = values.reduce((res, val) => {
          if (this.choiceValues[val]) {
            res.push(val);
          }

          return res;
        }, []);
        updateValue(arrayToString(unknownRemoved));
      } else {
        values.push('');
        updateValue(arrayToString(values));
        this.open();
      }
    }
  }

  getPressed(val) {
    const {
      value,
      type
    } = this.props.item;
    const isMultiButton = type === 'multiButton'; // if there are no unusual circumstances, we just want an exact match

    if (!isMultiButton) {
      return value === val;
    }

    return value != null && value.toString().includes(val);
  }

  getOtherInputVisible() {
    return (// either its explicitly open
      this.state.open || // or it contains something outside of known options
      // this is important for first load (since we may not have state yet)
      !stringToArray(this.props.item.value).every(val => this.choiceValues[val])
    );
  }

  render(_ref) {
    let {
      item,
      updateValue
    } = _ref,
        rest = _objectWithoutProperties(_ref, ["item", "updateValue"]);

    const showOtherInput = this.getOtherInputVisible();
    const {
      value
    } = item;
    return (0, _preact.h)("div", rest, item.label && (0, _preact.h)(Label, {
      item: item,
      updateValue: updateValue
    }), (0, _preact.h)("div", {
      "data-e2e": "".concat(item.name, "InputButtons")
    }, item.choices.map(choice => {
      let {
        name,
        val,
        disabled
      } = choice;
      const pressed = this.getPressed(val);
      return (0, _preact.h)(_button.Button, {
        key: val,
        pressed: pressed,
        className: "mr2 mv1 items-base",
        "data-e2e": "".concat(item.name, "InputButton:").concat(val),
        "data-state": pressed ? 'pressed' : 'unpressed',
        type: "button",
        disabled: !!disabled,
        onClick: () => this.handleButtonPress(val, pressed)
      }, name);
    }), item.showOther && (0, _preact.h)(_button.Button, {
      key: "other",
      pressed: showOtherInput,
      "data-state": showOtherInput ? 'pressed' : 'unpressed',
      className: "mr2 mv1 items-base",
      type: "button",
      onClick: () => this.handleOtherPress(showOtherInput),
      "data-e2e": "".concat(item.name, "InputButton:other")
    }, "Other"), item.showOther && showOtherInput && (0, _preact.h)(_inputs.Input, {
      className: "mv1 w-100 border-box",
      name: "".concat(item.name, "Other"),
      value: value,
      onInput: e => updateValue(e.target.value)
    })));
  }

}

exports.SelectButtons = SelectButtons;

const identity = res => res;

const autoCompleteFallback = _env.IS_CHROME ? 'new-password' : 'none';

const InputField = (_ref2) => {
  let {
    item,
    updateValue,
    autocomplete = autoCompleteFallback,
    autofocus,
    className = '',
    inputClassName = 'w-100',
    removeSuggestion
  } = _ref2,
      rest = _objectWithoutProperties(_ref2, ["item", "updateValue", "autocomplete", "autofocus", "className", "inputClassName", "removeSuggestion"]);

  const type = item.type || 'text';
  let clean = item.clean;
  const {
    value,
    cleanRe
  } = item;

  if (!clean && cleanRe) {
    clean = val => val.replace(cleanRe, '');
  }

  if (!clean) {
    clean = identity;
  }

  if (item.inputClassName) {
    inputClassName = item.inputClassName;
  }

  const update = e => updateValue(clean(e.target.value));

  const hasError = !!item.errorMessage;
  return (0, _preact.h)("div", _extends({
    className: "w-100 ".concat(className)
  }, rest), item.label && (0, _preact.h)(Label, {
    item: item,
    updateValue: updateValue,
    removeSuggestion: removeSuggestion
  }), (0, _preact.h)(_inputs.Input, {
    className: (0, _classnames.default)('mv1', {
      'bg-washed-red': hasError
    }, inputClassName),
    name: item.name,
    onChange: item.onInput ? noOp : update,
    onInput: item.onInput ? update : noOp,
    id: item.name,
    placeholder: item.placeholder,
    type,
    value,
    autocomplete,
    autofocus,
    disabled: item.disabled,
    inputmode: item.inputmode || null,
    'data-e2e': "".concat(item.name, "Input"),
    'data-has-error': hasError ? true : null,
    style: item.inputWidth ? {
      width: item.inputWidth
    } : null
  }));
};

exports.InputField = InputField;

const DecimalInputField = (_ref3) => {
  let {
    item,
    updateValue
  } = _ref3,
      rest = _objectWithoutProperties(_ref3, ["item", "updateValue"]);

  const args = {};

  if (item.hasOwnProperty('maxLenBefore')) {
    args.min = item.min;
  }

  if (item.hasOwnProperty('max')) {
    args.max = item.max;
  }

  const {
    maxLenBefore,
    maxLenAfter
  } = item,
        itemRest = _objectWithoutProperties(item, ["maxLenBefore", "maxLenAfter"]);

  const modifiedItem = _objectSpread(_objectSpread({
    onInput: true,
    inputmode: 'decimal',
    clean: (0, _decimals.getCleanDecimalWithLimits)({
      maxLenBefore,
      maxLenAfter
    }),
    required: false
  }, itemRest), {}, {
    type: 'text'
  });

  return (0, _preact.h)(InputField, _extends({
    updateValue: updateValue,
    item: modifiedItem
  }, rest));
};

exports.DecimalInputField = DecimalInputField;

const TextareaField = ({
  item,
  updateValue,
  removeSuggestion
}) => (0, _preact.h)("div", {
  className: "mb2"
}, (0, _preact.h)(Label, {
  item: item,
  updateValue: updateValue,
  removeSuggestion: removeSuggestion
}), (0, _preact.h)(_inputs.Textarea, {
  className: (0, _classnames.default)('w-100', item.size === 'large' ? 'h5' : 'h4'),
  name: item.name,
  onChange: item.onInput ? noOp : e => updateValue(e.target.value),
  onInput: item.onInput ? e => updateValue(e.target.value) : noOp,
  value: item.value,
  id: item.name,
  'data-e2e': "".concat(item.name, "Input")
}));

exports.TextareaField = TextareaField;

const IncrementButtonField = ({
  item,
  displayValue,
  updateValue,
  step = 1,
  max = Infinity,
  min = 0,
  width,
  unit = '',
  showStep = true,
  formatter,
  className
}) => {
  const {
    name,
    value,
    fieldSpecificProps
  } = item;

  const passOn = _objectSpread({
    formatter,
    width,
    updateValue,
    displayValue,
    step,
    showStep,
    max,
    min,
    unit,
    name,
    value: value != null ? value : fieldSpecificProps.startingValue
  }, fieldSpecificProps || {});

  return (0, _preact.h)("div", {
    className: (0, _classnames.default)(className)
  }, (0, _preact.h)(Label, {
    item: item
  }), (0, _preact.h)("div", null, (0, _preact.h)(_incrementors.IncrementorButtons, passOn)));
};

exports.IncrementButtonField = IncrementButtonField;

const TimeIncrementField = (_ref4) => {
  let {
    item,
    displayValue,
    updateValue,
    max = Infinity,
    min = 0,
    className
  } = _ref4,
      rest = _objectWithoutProperties(_ref4, ["item", "displayValue", "updateValue", "max", "min", "className"]);

  const {
    name,
    value,
    fieldSpecificProps
  } = item;

  const passOn = _objectSpread({
    updateValue,
    displayValue,
    max,
    min,
    name,
    value: value != null ? value : fieldSpecificProps.startingValue
  }, fieldSpecificProps || {});

  return (0, _preact.h)("div", _extends({
    className: (0, _classnames.default)(className)
  }, rest), item.label && (0, _preact.h)(Label, {
    item: item
  }), (0, _preact.h)("div", null, (0, _preact.h)(_incrementors.TimeIncrementorButtons, passOn)));
};

exports.TimeIncrementField = TimeIncrementField;

class SignatureField extends _preact.Component {
  constructor(props) {
    super(props);
    this.state = {
      editing: false
    };
  }

  render({
    item,
    updateValue
  }, {
    editing
  }) {
    const {
      value
    } = item;
    return (0, _preact.h)("div", null, item.label && (0, _preact.h)(Label, {
      item: item
    }), (0, _preact.h)("div", null, !editing && value && (0, _preact.h)(_signature.Signature, {
      width: "200",
      path: value,
      className: _inputs.inputOutlineClasses
    }), !editing && (0, _preact.h)(_button.Button, {
      type: "button",
      className: "db mv2",
      onClick: () => this.setState({
        editing: true
      })
    }, value ? 'Change' : 'Add Signature'), editing && (0, _preact.h)(_signatureInput.SignatureInput, {
      name: item.signatureLineName,
      confirmButtonText: item.confirmButtonText,
      close: () => this.setState({
        editing: false
      }),
      updateValue: val => {
        updateValue(val);
        this.setState({
          editing: false
        });
      }
    })));
  }

}

exports.SignatureField = SignatureField;

const Options = ({
  options,
  selectedOptions
}) => (0, _preact.h)(_preact.Fragment, null, options.map(option => {
  const val = option.hasOwnProperty('value') ? option.value : option;
  return (0, _preact.h)("option", {
    key: val,
    value: val,
    selected: selectedOptions[val],
    onClick: option.onClick
  }, option.label || option);
}));

const SelectField = (_ref5) => {
  let {
    item,
    updateValue,
    autofocus,
    className = '',
    inputClassName = 'w-100'
  } = _ref5,
      rest = _objectWithoutProperties(_ref5, ["item", "updateValue", "autofocus", "className", "inputClassName"]);

  let clean = item.clean;
  const {
    value,
    cleanRe,
    multiple
  } = item;

  if (!clean && cleanRe) {
    clean = val => val.replace(cleanRe, '');
  }

  if (!clean) {
    clean = identity;
  }

  if (item.inputClassName) {
    inputClassName = item.inputClassName;
  }

  const {
    optGroups,
    options
  } = item;

  const update = value => updateValue(clean(value));

  const hasError = !!item.errorMessage; // this is for multiselect
  // which behaves kind of oddly

  const selectedOptions = {};

  if (value) {
    if (multiple) {
      const values = value.split(',');

      for (const value of values) {
        selectedOptions[value] = true;
      }
    } else {
      selectedOptions[value] = true;
    }
  }

  return (0, _preact.h)("div", _extends({
    className: "w-100 ".concat(className)
  }, rest), item.label && (0, _preact.h)(Label, {
    item: item,
    updateValue: updateValue
  }), (0, _preact.h)(_inputs.Select, {
    className: (0, _classnames.default)('mv1', {
      'bg-washed-red': hasError
    }, inputClassName),
    multiple,
    name: item.name,
    onChange: e => {
      const valString = [].slice.apply(e.target.querySelectorAll('option:checked')).map(opt => opt.value).join(',');
      update(valString);
    },
    id: item.name,
    placeholder: item.placeholder,
    value: multiple ? null : value || '',
    autofocus,
    'data-e2e': "".concat(item.name, "Select"),
    'data-has-error': hasError ? true : null,
    style: item.inputWidth ? {
      width: item.inputWidth
    } : null
  }, options && (0, _preact.h)(Options, {
    selectedOptions: selectedOptions,
    options: options
  }), optGroups && optGroups.map(({
    label,
    options
  }) => (0, _preact.h)("optgroup", {
    key: "label",
    label: label
  }, label, (0, _preact.h)(Options, {
    selectedOptions: selectedOptions,
    options: options
  })))));
};

exports.SelectField = SelectField;

const OralAdministrationField = (_ref6) => {
  let {
    updateValue,
    label,
    item
  } = _ref6,
      rest = _objectWithoutProperties(_ref6, ["updateValue", "label", "item"]);

  return (0, _preact.h)(SelectButtons, _extends({
    updateValue: updateValue,
    item: _objectSpread({
      name: 'route',
      required: false,
      choices: [(0, _question.choice)('PO'), (0, _question.choice)('SL')],
      label
    }, item)
  }, rest));
};

exports.OralAdministrationField = OralAdministrationField;

const LocalUnitField = (_ref7) => {
  let {
    updateValue,
    item
  } = _ref7,
      rest = _objectWithoutProperties(_ref7, ["updateValue", "item"]);

  return (0, _preact.h)(SelectButtons, _extends({
    item: _objectSpread({
      name: 'unit',
      required: false,
      choices: [(0, _question.choice)('cart.', 'cartridges'), (0, _question.choice)('ml'), (0, _question.choice)('mg')],
      label: 'Unit'
    }, item),
    allowDeselect: false,
    updateValue: updateValue
  }, rest));
};

exports.LocalUnitField = LocalUnitField;

const InfusionTypeField = (_ref8) => {
  let {
    updateValue,
    label,
    item
  } = _ref8,
      rest = _objectWithoutProperties(_ref8, ["updateValue", "label", "item"]);

  return (0, _preact.h)(SelectButtons, _extends({
    updateValue: updateValue,
    item: _objectSpread({
      name: 'infusionType',
      required: false,
      allowDeselect: false,
      choices: [(0, _question.choice)('Flow rate', 'infusion'), (0, _question.choice)('Pump bolus', 'infusionBolus')],
      label
    }, item)
  }, rest));
};

exports.InfusionTypeField = InfusionTypeField;
const infusionChoices = [(0, _question.choice)('mcg/kg/min'), (0, _question.choice)('mcg/kg/hr'), (0, _question.choice)('mcg/min'), (0, _question.choice)('mg/hr')];

const InfusionUnitField = (_ref9) => {
  let {
    updateValue,
    label,
    item
  } = _ref9,
      rest = _objectWithoutProperties(_ref9, ["updateValue", "label", "item"]);

  return (0, _preact.h)(SelectButtons, _extends({
    updateValue: updateValue,
    item: _objectSpread({
      name: 'infusionUnit',
      required: false,
      choices: infusionChoices,
      label
    }, item)
  }, rest));
};

exports.InfusionUnitField = InfusionUnitField;
const infusionBolusChoices = [(0, _question.choice)('mcg/kg'), (0, _question.choice)('mcg'), (0, _question.choice)('mg')];

const InfusionBolusField = (_ref10) => {
  let {
    updateValue,
    label,
    item
  } = _ref10,
      rest = _objectWithoutProperties(_ref10, ["updateValue", "label", "item"]);

  return (0, _preact.h)(SelectButtons, _extends({
    updateValue: updateValue,
    item: _objectSpread({
      name: 'bolusUnit',
      required: false,
      choices: infusionBolusChoices,
      label
    }, item)
  }, rest));
};

exports.InfusionBolusField = InfusionBolusField;

const InjectionTypeField = (_ref11) => {
  let {
    updateValue,
    label,
    item,
    usingIV = true
  } = _ref11,
      rest = _objectWithoutProperties(_ref11, ["updateValue", "label", "item", "usingIV"]);

  const choices = [(0, _question.choice)('IM'), (0, _question.choice)('IN')];

  if (usingIV) {
    choices.unshift((0, _question.choice)('IV'));
  }

  return (0, _preact.h)(SelectButtons, _extends({
    updateValue: updateValue,
    item: _objectSpread({
      name: 'injectionType',
      required: false,
      allowDeselect: false,
      choices,
      label
    }, item)
  }, rest));
};

exports.InjectionTypeField = InjectionTypeField;

const CheckboxField = ({
  updateValue,
  item
}) => {
  const {
    value,
    name,
    fieldSpecificProps,
    label
  } = item;
  const isComplete = !!value;
  const {
    checkboxLabel,
    valueIfTrue
  } = fieldSpecificProps || {};
  const labelToUse = checkboxLabel || label;
  return (0, _preact.h)("div", null, (0, _preact.h)(Label, {
    item: item
  }), (0, _preact.h)("label", {
    htmlFor: name,
    className: (0, _classnames.default)('flex items-center mb2'),
    "data-e2e": "checkMark",
    "data-state": isComplete ? 'checked' : 'unchecked'
  }, (0, _preact.h)("input", {
    onClick: () => updateValue(isComplete ? null : valueIfTrue != null ? valueIfTrue : true),
    className: "checkbox o-0 absolute",
    id: name,
    checked: isComplete,
    type: "checkbox",
    "data-e2e": "".concat(name, "Input")
  }), (0, _preact.h)("div", {
    className: "flex items-center"
  }, (0, _preact.h)("div", {
    className: "relative",
    style: {
      height: '24px',
      width: '24px'
    }
  }, (0, _preact.h)("div", {
    style: {
      top: '4px',
      left: '4px',
      position: 'relative',
      background: 'white',
      width: '16px',
      height: '16px'
    }
  }), (0, _preact.h)(_icon.Icon, {
    size: 24,
    icon: isComplete ? 'check_box' : 'check_box_outline_blank',
    className: (0, _classnames.default)('absolute top-0', isComplete && 'light-blue')
  }))), (0, _preact.h)("span", {
    className: "ml1"
  }, labelToUse)));
};

exports.CheckboxField = CheckboxField;