Bootta11 / Attendo_ba_daily_work_time_extended

// ==UserScript==
// @name         Attendo_ba_daily_work_time_extended
// @namespace    http://tampermonkey.net/
// @version      0.38
// @license MIT
// @description  Add missing work timer for current day to attendo.ba. Extended with monthly summary and daily pause display.
// @author       Bootta
// @match        https://attendo.ba/attendo/app/entry
// @require https://code.jquery.com/jquery-3.3.1.min.js
// @updateURL https://openuserjs.org/meta/Bootta11/Attendo_ba_daily_work_time_extended.meta.js
// ==/UserScript==

(function () {
  'use strict';

  let entries_refresh_interval_in_seconds = 300;
  let enable_time_without_pause = true;

  let $ = window.jQuery;
  let worklog_entries;
  let checkedout_time_periods_sum = 0;
  let open_time_period_start;
  let mandatory_break = 30 * 60 * 1000;
  let mandatory_break_left = mandatory_break;
  let meal_break_sum = 0;
  let refresh_enteries_interval;
  let today = new Date();
  let dd = today.getDate();
  let mm = today.getMonth() + 1; //January is 0!
  let yyyy = today.getFullYear();
  let today_datetime_string = yyyy + '-' + aln(mm) + '-' + aln(dd);
  let daily_work_time_element = `
<li id="daily_work_timer_holder" >
<a href="#" onclick="return false" disabled id='daily_time_holder' style="hidden:true">
Today worked:&nbsp;&nbsp;<big><span id="daily_work_timer" style="color: black"></span></big>
</a>
<a href="#" onclick="return false" disabled id='plus_minus_holder' style='hidden:true'>
<span id="plus_or_minus"></span><big><span style="color: black" id='plus_minus_timer'></span></big>
</a>
</li>`;
  let plus_minus_worked_ms = 0;
  let cumulative_daily_time, previous_cumulative_daily_time = 0;
  let wanted_time = 0;
  let timer_is_running = false;

  refreshEnteries(function () {
    getMonthlySummary();
  });

  refresh_enteries_interval = setInterval(refreshEnteries, 1000 * entries_refresh_interval_in_seconds);
  setInterval(refreshDailyWorkTime, 1000);

  $('.navbar .navbar-right').prepend(daily_work_time_element);
  $('#daily_time_holder').mouseenter(function () {

    $('#daily_time_holder').hide();
    $('#plus_minus_holder').show();
    $('#plus_minus_holder').css('width', '350px');
    $('#plus_minus_holder').attr('align', 'center');
  })
  $('#plus_minus_holder').mouseout(function (event) {
    if ($.contains(this, event.relatedTarget) || this == event.relatedTarget) {
      return;
    }
    $('#daily_time_holder').show();
    $('#daily_time_holder').css('width', '350px')
    $('#daily_time_holder').css('text-align', 'center')
    $('#daily_time_timer').css('display', 'block')
    $('#plus_minus_holder').hide();

  })
  $('#plus_minus_holder').hide();

  function refreshDailyWorkTime() {

    if (worklog_entries) {
      cumulative_daily_time = checkedout_time_periods_sum;

      if (open_time_period_start) {
        let open_time_period_current_datetime = new Date();
        cumulative_daily_time += Math.abs(open_time_period_current_datetime - open_time_period_start);
      }

      let cumulative_daily_time_without_pause = cumulative_daily_time - (1000 * 60 * 30);
      //console.log(tsToDisplayTime(plus_minus_worked_ms), tsToDisplayTime(cumulative_daily_time), tsToDisplayTime(wanted_time), tsToDisplayTime(mandatory_break_left), timer_is_running, tsToDisplayTime(cumulative_daily_time - wanted_time - mandatory_break_left),tsToDisplayTime(plus_minus_worked_ms));
      let monthly_time = plus_minus_worked_ms + (timer_is_running ? (cumulative_daily_time - wanted_time - mandatory_break_left) : 0);
      $('#plus_minus_timer').text(tsToDisplayTime(monthly_time));
      $('#plus_or_minus').html('Monthly (' + (plus_minus_worked_ms >= 0 ? 'plus:&nbsp;&nbsp;' : 'minus:&nbsp;&nbsp;') + tsToDisplayTime(plus_minus_worked_ms) + '): ');

      var seconds = Math.floor(((cumulative_daily_time % (1000 * 60)) / 1000));
      var minutes = Math.floor(((cumulative_daily_time % (1000 * 60 * 60)) / (1000 * 60)));
      var hours = Math.floor((cumulative_daily_time / (1000 * 60 * 60)));

      let display_time = tsToDisplayTime(cumulative_daily_time);
      let mandatory_minutes = Math.floor(((mandatory_break_left % (1000 * 60 * 60)) / (1000 * 60)));
      let mandatory_seconds = Math.floor(((mandatory_break_left % (1000 * 60)) / 1000));

      display_time += (enable_time_without_pause ? '(-' + (aln(mandatory_minutes) + ' : ' + aln(mandatory_seconds)) + 'min)' : '');
      $('#daily_work_timer').text(display_time);
      previous_cumulative_daily_time = cumulative_daily_time;
    }
  }

  function refreshEnteries(callback) {
    checkedout_time_periods_sum = 0;
    $.get('https://attendo.ba/attendo/app/api/employee/overview/daily?date=' + today_datetime_string, function (data) {
      worklog_entries = data.entries;
      if (data.calculation && data.calculation.summary && data.calculation.summary.wantedTime) {
        wanted_time = parsePTInterval(data.calculation.summary.wantedTime);
      }
      if (worklog_entries && worklog_entries.length > 0) {
        for (let i = 0; i < worklog_entries.length; i++) {
          let entry = worklog_entries[i];

          if (entry.entryType == "CHECK_IN") {
            let check_in_start_datetime = new Date(entry.dateTime);
            let check_in_end_datetime = new Date();

            if (worklog_entries[i + 1]) {
              check_in_end_datetime = new Date(worklog_entries[i + 1].dateTime);
              checkedout_time_periods_sum += Math.abs(check_in_end_datetime - check_in_start_datetime);
            }
            else {
              open_time_period_start = check_in_start_datetime;
            }

          }
          else if (entry.entryType == "MEAL_BREAK") {
            let meal_break_start_datetime = new Date(entry.dateTime);
            let meal_break_end_datetime = new Date();

            if (worklog_entries[i + 1]) {
              meal_break_end_datetime = new Date(worklog_entries[i + 1].dateTime);
              meal_break_sum += Math.abs(meal_break_end_datetime - meal_break_start_datetime);
              if (meal_break_sum <= mandatory_break) {
                mandatory_break_left -= meal_break_sum;
              }
              else {
                mandatory_break_left = 0;
              }
            }
          }
        }

        if (open_time_period_start) {
          timer_is_running = true;
        }
        let cumulative_daily_time_without_pause = checkedout_time_periods_sum - (1000 * 60 * 30);
      }
      else {
        mandatory_break_left = 0;
      }
      callback();
    });

  }

  //add leading null
  function aln(n) {
    return (n < 10 ? '0' + n : n);
  }

  // timestamp to time
  function tsToDisplayTime(ts) {
    let minus = '';
    if (ts < 0) {
      minus = '-';
      ts = ts * -1;
    }
    var seconds = Math.floor(((ts % (1000 * 60)) / 1000));
    var minutes = Math.floor(((ts % (1000 * 60 * 60)) / (1000 * 60)));
    var hours = Math.floor((ts / (1000 * 60 * 60)));

    return minus + aln(hours) + ' : ' + aln(minutes) + ' : ' + aln(seconds);
  }

  function parsePTInterval(pt_interval) {
    var reptms = /^PT(?:([0-9\-]+)H)?(?:([0-9\-]+)M)?(?:([0-9\-]+)S)?$/;
    let hours = 0,
      minutes = 0,
      seconds = 0,
      totalseconds = 0;

    if (reptms.test(pt_interval)) {
      var matches = reptms.exec(pt_interval);
      if (matches[1]) hours = Number(matches[1]);
      if (matches[2]) minutes = Number(matches[2]);
      if (matches[3]) seconds = Number(matches[3]);
      totalseconds = hours * 3600 + minutes * 60 + seconds;
    }
    return totalseconds * 1000;
  }

  function getMonthlySummary() {

    var date = new Date();
    var firstDayOfMonth = formatDateForQuery(new Date(date.getFullYear(), date.getMonth(), 1));
    var lastDayOfMonth = formatDateForQuery(new Date(date.getFullYear(), date.getMonth() + 1, 0));

    $.get('https://attendo.ba/attendo/app/api/employee/overview/period?page=0&size=40&fromDate=' + firstDayOfMonth + '&toDate=' + lastDayOfMonth, function (data) {
      for (let i = 0; i < data.rows.length; i++) {
        if (timer_is_running && i == (data.rows.length - 1)) {
          continue;
        }
        plus_minus_worked_ms += parsePTInterval(data.rows[i].calculation.summary.difference);

      }
    });
  }

  function formatDateForQuery(input_date) {
    let dd = input_date.getDate();
    let mm = input_date.getMonth() + 1; //January is 0!
    let yyyy = input_date.getFullYear();
    return yyyy + '-' + aln(mm) + '-' + aln(dd);
  }
})();