Skip to content

Instantly share code, notes, and snippets.

@rastamhadi
Last active February 2, 2023 10:14
Show Gist options
  • Select an option

  • Save rastamhadi/ca4aa2a3ad0b00fd41f7b5d36e0402b0 to your computer and use it in GitHub Desktop.

Select an option

Save rastamhadi/ca4aa2a3ad0b00fd41f7b5d36e0402b0 to your computer and use it in GitHub Desktop.
How much longer do I have to work this month?
// ==UserScript==
// @name How much longer do I have to work this month?
// @namespace http://tampermonkey.net/
// @version 0.1
// @description Calculates the number of hours you need to work for the rest of the month
// @author Rastam Hadi
// @match https://p.secure.freee.co.jp/
// @icon https://www.google.com/s2/favicons?sz=64&domain=freee.co.jp
// @grant none
// ==/UserScript==
(function() {
'use strict';
if (window.location.pathname != '/' || !window.location.hash.startsWith('#work_records')) return;
const Summary = class {
constructor() {
this.container = document.querySelector('.employee-work-record-summary .main-items');
};
isNotLoaded() {
return this.container == null;
};
buildRemainderItem() {
const workedTimeItem = this.getWorkedTimeItem();
const remainderItemContainer = workedTimeItem.clone();
const remainderItem = new SummaryItem(remainderItemContainer);
const excessHours = workedTimeItem.getHours() - 8 * this.getWorkedDaysItem().getDays();
this.container.appendChild(remainderItemContainer);
remainderItem.setLabel('過不足時間');
remainderItem.setHours(excessHours);
};
getWorkedDaysItem() {
return new SummaryItem(this.container.firstChild);
};
getWorkedTimeItem() {
return new SummaryItem(this.container.childNodes[1]);
};
};
const SummaryItem = class {
constructor(container) {
this.container = container;
this.body = container.querySelector('.body');
this.hoursContainer = this.body.querySelector('.hour-min__hour .hour-min__value');
};
clone() {
return this.container.cloneNode(true);
};
setLabel(text) {
this.getLabel().textContent = text;
};
setHours(hours) {
this.hoursContainer.firstChild.nodeValue = hours;
if (hours < 0) {
this.body.style.color = 'red';
} else {
this.body.style.color = 'green';
};
};
getLabel() {
return this.container.querySelector('.label');
};
getDays() {
return parseInt(this.body.firstChild.nodeValue);
};
getHours() {
return parseInt(this.hoursContainer.innerText);
};
};
function observeBody() {
const observer = new MutationObserver(mutations => {
const summary = new Summary();
if (summary.isNotLoaded()) return;
summary.buildRemainderItem();
observer.disconnect();
document.getElementsByTagName('button').forEach(button => {
button.addEventListener('click', event => {
observeBody();
});
});
});
observer.observe(document.body, {childList: true, subtree: true})
};
observeBody();
})();
// ==UserScript==
// @name How much longer do I have to work this month?
// @namespace http://tampermonkey.net/
// @version 0.1
// @description Calculates the number of hours you need to work for the rest of the month
// @author Rastam Hadi
// @match https://ssl.jobcan.jp/employee/attendance*
// @grant none
// ==/UserScript==
(function() {
'use strict';
const ONE_HOUR = 60;
const EIGHT_HOURS = 8 * ONE_HOUR;
const Duration = class {
constructor(minutes) {
this.minutes = minutes;
};
static parse(string) {
let hours, minutes;
[hours, minutes] = string.split(':').map(i => parseInt(i));
return new Duration(minutes + hours * ONE_HOUR);
}
add(duration) {
return new Duration(this.minutes + duration.minutes);
};
overtime() {
return new Duration(this.minutes - EIGHT_HOURS);
};
toString() {
const sign = this.minutes < 0 ? '-' : '';
const formattedHours = `0${this.getHoursSegment()}`.slice(-2);
const formattedMinutes = `0${this.getMinutesSegment()}`.slice(-2);
return `${sign}${formattedHours}:${formattedMinutes}`;
};
getHoursSegment() {
return Math.abs(Math.trunc(this.minutes / ONE_HOUR));
};
getMinutesSegment() {
return Math.abs(this.minutes % ONE_HOUR);
};
};
const headerRow = document.querySelector('.jbc-table-header');
const header = headerRow.lastChild.cloneNode(false);
header.appendChild(document.createTextNode('労働時間'));
header.appendChild(document.createElement('BR'));
header.appendChild(document.createTextNode('過不足'));
headerRow.appendChild(header);
let overtimeTotal = new Duration(0);
const rows = document.querySelector('.table-responsive tbody').children;
for(let i = 0; i < rows.length; i++) {
const row = rows.item(i);
const hoursWorkedCell = row.children.item(4);
const cell = row.lastChild.cloneNode(false);
row.appendChild(cell);
if(hoursWorkedCell.innerText != "") {
const overtime = Duration.parse(hoursWorkedCell.innerText).overtime();
const cellText = document.createTextNode(overtime.toString());
cell.appendChild(cellText);
overtimeTotal = overtimeTotal.add(overtime);
}
};
const footerRow = document.querySelector('.jbc-table-footer');
const footer = footerRow.lastChild.cloneNode(false);
footer.appendChild(document.createTextNode(overtimeTotal.toString()));
footer.setAttribute('style', `background-color: ${overtimeTotal.minutes < 0 ? '#FEEFED' : '#52CD9A'}`);
footerRow.appendChild(footer);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment