diff --git a/css/styles.css b/css/styles.css index 46992a24d..18934476c 100644 --- a/css/styles.css +++ b/css/styles.css @@ -477,6 +477,14 @@ input:disabled + .slider { border-bottom: 4px solid var(--table-total-border); } +.common-window .window-tab { + padding-top: 10px; +} + +.common-window .tab-content { + padding-top: 10px; +} + .common-window p.header-help { font-variant-caps: all-petite-caps; font-size: 15px; diff --git a/package-lock.json b/package-lock.json index 4bb4147d2..9f08ba42c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3559,7 +3559,6 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, "requires": { "sprintf-js": "~1.0.2" }, @@ -3567,8 +3566,7 @@ "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" } } }, @@ -3671,6 +3669,11 @@ "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", "dev": true }, + "astronomia": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/astronomia/-/astronomia-2.1.3.tgz", + "integrity": "sha512-slRv2h0HlowjWwMbojL4hKcXqiItfx/TNruYmiETw6ATfeSZxBSGv1bo16ruMVKzGGxucL1esh7MYjwXuToS6w==" + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -4227,6 +4230,14 @@ } } }, + "caldate": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/caldate/-/caldate-1.1.0.tgz", + "integrity": "sha512-Z8AF+9Ha/40UBmZXJbb0qQNx6Djv1BySw0o7kcBKuzKmmqK/nUCjW+ez/6fFqWZglPgUXiy0n/zGMncYpKXtmQ==", + "requires": { + "moment-timezone": "^0.5.27" + } + }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -4761,6 +4772,64 @@ "whatwg-url": "^7.0.0" } }, + "date-bengali-revised": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/date-bengali-revised/-/date-bengali-revised-1.0.2.tgz", + "integrity": "sha512-HehC0Kcjz+wgTSXAA/ei/Y4QPEg1nCYeZdrBl/o/o1B+iPycvipeTIhff9nXtQUY17nrXLunvOWTzqbR490m2w==" + }, + "date-chinese": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/date-chinese/-/date-chinese-1.0.7.tgz", + "integrity": "sha512-Dx1VG/mSST1yYqZvJvBWxvdDKTlmerZWXopiaPmVKeVFNhTZ20RvMrexg4FPFrCygPrgqTDtB2bEcwFcRoO2ww==", + "requires": { + "astronomia": "^2.1.1" + } + }, + "date-easter": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/date-easter/-/date-easter-0.2.5.tgz", + "integrity": "sha512-pMvZSqQgPBqnUQEHhRMy7f8Dk3KYY/NPFMFHGK4mU+xM1+SX+zc9IoQMcNtS3HuJjCn3mp0GQwBzsZXz3Thjww==" + }, + "date-holidays": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/date-holidays/-/date-holidays-1.6.1.tgz", + "integrity": "sha512-pVGp4pEOu8aO/CEQXHhDnZ/eYJydDMUxC8d4jstrwU+tvmpoBcegRv1u8OVxDR4MEravN5PhITdiJAoz4tN9rQ==", + "requires": { + "date-holidays-parser": "^1.5.0", + "js-yaml": "^3.14.0", + "lodash.omit": "^4.5.0", + "lodash.pick": "^4.4.0", + "prepin": "^1.0.3" + }, + "dependencies": { + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + } + } + }, + "date-holidays-parser": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/date-holidays-parser/-/date-holidays-parser-1.5.0.tgz", + "integrity": "sha512-pRD0ITufg/j/x5bcJNyEL3QaoTbCchSDcmCOK7BpqP6yENouIHEqZsbktKCrNPX16LgDU7xhVV8meAVKWx41cA==", + "requires": { + "astronomia": "^2.1.3", + "caldate": "^1.1.0", + "date-bengali-revised": "^1.0.2", + "date-chinese": "^1.0.7", + "date-easter": "^0.2.5", + "lodash.get": "^4.4.2", + "lodash.merge": "^4.6.2", + "lodash.omit": "^4.5.0", + "lodash.set": "^4.3.2", + "moment-timezone": "^0.5.31" + } + }, "date-time": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/date-time/-/date-time-3.1.0.tgz", @@ -6022,8 +6091,7 @@ "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" }, "esquery": { "version": "1.3.1", @@ -11775,8 +11843,27 @@ "lodash.get": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", - "dev": true + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + }, + "lodash.omit": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz", + "integrity": "sha1-brGa5aHuHdnfC5aeZs4Lf6MLXmA=" + }, + "lodash.pick": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", + "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=" + }, + "lodash.set": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", + "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=" }, "lodash.sortby": { "version": "4.7.0", @@ -12140,6 +12227,19 @@ "minimist": "^1.2.5" } }, + "moment": { + "version": "2.27.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.27.0.tgz", + "integrity": "sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ==" + }, + "moment-timezone": { + "version": "0.5.31", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.31.tgz", + "integrity": "sha512-+GgHNg8xRhMXfEbv81iDtrVeTcWt0kWmTEY1XQK14dICTXnWJnT0dxdlPspwqF3keKMVPXwayEsk1DI0AA/jdA==", + "requires": { + "moment": ">= 2.9.0" + } + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -12977,6 +13077,11 @@ "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=" }, + "prepin": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/prepin/-/prepin-1.0.3.tgz", + "integrity": "sha512-0XL2hreherEEvUy0fiaGEfN/ioXFV+JpImqIzQjxk6iBg4jQ2ARKqvC4+BmRD8w/pnpD+lbxvh0Ub+z7yBEjvA==" + }, "prettier": { "version": "1.19.1", "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", diff --git a/package.json b/package.json index 219aa02a7..20a43c521 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ }, "dependencies": { "bootstrap": "^4.5.0", + "date-holidays": "^1.6.1", "electron-store": "^5.2.0", "is-online": "^8.4.0", "jquery": "^3.5.1", diff --git a/src/workday-waiver.html b/src/workday-waiver.html index 441c2a1f2..7c6da2899 100644 --- a/src/workday-waiver.html +++ b/src/workday-waiver.html @@ -18,42 +18,92 @@ Workday Waiver Manager

Changes take effect when closing this window

+ -
-
Add Waiver
-
- - - - - - - - - - - - - - - - - - - - - - - -
Start dateEnd date
Fromto
Hours - -
Reason
-
- -
-
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + +
Start dateEnd date
Fromto
Hours + +
Reason
+
+ +
+
+
+
+ + + + + + + + + + + + + + + + + + + +
Year
Country:
State:
City:
+
+ + + + + + + + + + + +
DateHolidayOn working dayConflicts?Import?
+
+ +
+
+
Waived workday list
diff --git a/src/workday-waiver.js b/src/workday-waiver.js index a9cf08c53..2d0db2cb7 100644 --- a/src/workday-waiver.js +++ b/src/workday-waiver.js @@ -1,5 +1,6 @@ const { remote } = require('electron'); const Store = require('electron-store'); +var Holidays = require('date-holidays'); const { getUserPreferences, showDay } = require('../js/user-preferences.js'); const { validateTime, diffDays } = require('../js/time-math.js'); @@ -8,6 +9,7 @@ const { getDateStr } = require('../js/date-aux.js'); const { bindDevToolsShortcut, showAlert, showDialog } = require('../js/window-aux.js'); const waiverStore = new Store({name: 'waived-workdays'}); +var hd = new Holidays(); function setDates(day) { $('#start-date').val(day); @@ -19,12 +21,11 @@ function setHours() { $('#hours').val(usersStyles['hours-per-day']); } -function toggleAddButton() { - let value = $('#reason').val(); - if (value.length > 0) { - $('#waive-button').removeAttr('disabled'); +function toggleAddButton(buttonName, state) { + if (state) { + $(`#${buttonName}`).removeAttr('disabled'); } else { - $('#waive-button').attr('disabled', 'disabled'); + $(`#${buttonName}`).attr('disabled', 'disabled'); } } @@ -112,7 +113,7 @@ function addWaiver() { //Cleanup $('#reason').val(''); - toggleAddButton(); + toggleAddButton('waive-button', $('#reason').val()); } function deleteEntryOnClick(event) { @@ -137,23 +138,209 @@ function deleteEntryOnClick(event) { }); } +function populateCountry() { + $('#country').empty(); + $('#country').append($('').val('--').html('--')); + $.each(hd.getCountries(), function(i, p) { + $('#country').append($('').val(i).html(p)); + }); +} + +function populateState(country) { + let states = hd.getStates(country); + if (states) { + $('#state').empty(); + $('#state').append($('').val('--').html('--')); + $.each(states, function(i, p) { + $('#state').append($('').val(i).html(p)); + }); + $('#state').show(); + $('#holiday-state').show(); + } else { + $('#state').hide(); + $('#holiday-state').hide(); + } +} +function populateCity(country, state) { + let regions = hd.getRegions(country, state); + if (regions) { + $('#city').empty(); + $('#city').append($('').val('--').html('--')); + $.each(regions, function(i, p) { + $('#city').append($('').val(i).html(p)); + }); + $('#city').show(); + $('#holiday-city').show(); + } else { + $('#city').hide(); + $('#holiday-city').hide(); + } +} + +function populateYear() { + var year = new Date().getFullYear(); + var obj = {}; + for (var i = year; i < year + 10; i++) { + obj[i] = i; + } + $('#year').empty(); + $.each(obj, function(i, p) { + $('#year').append($('').val(p).html(p)); + }); +} + +function getHolidays() { + var year = $('#year').find(':selected').val(), + country = $('#country').find(':selected') ? $('#country').find(':selected').val() : undefined, + state = $('#state').find(':selected') ? $('#state').find(':selected').val() : undefined, + city = $('#city').find(':selected') ? $('#city').find(':selected').val() : undefined; + if (country === undefined) { + return []; + } + if (state !== undefined && city !== undefined) { + hd.init(country, state, city); + } else if (state !== undefined && state !== '--' ) { + hd.init(country, state); + } else { + hd.init(country); + } + + return hd.getHolidays(year); +} + +function iterateOnHolidays(funct) { + let holidays = getHolidays(); + + for (let holiday of holidays) { + let startDate = new Date(holiday['start']), + endDate = new Date(holiday['end']), + reason = holiday['name']; + let diff = diffDays(startDate, endDate) - 1; + + var tempDate = new Date(startDate); + for (let i = 0; i <= diff; i++) { + let tempDateStr = getDateStr(tempDate); + funct(tempDateStr, reason); + tempDate.setDate(tempDate.getDate() + 1); + } + } +} + +function addHolidayToList(day, reason, workingDay, conflicts) { + let table = $('#holiday-list-table tbody')[0], + row = table.insertRow(table.rows.length), + dayCell = row.insertCell(0), + reasonCell = row.insertCell(1), + workingDayCell = row.insertCell(2), + conflictsCell = row.insertCell(3), + importCell = row.insertCell(4); + + dayCell.innerHTML = day; + reasonCell.innerHTML = reason; + workingDayCell.innerHTML = workingDay; + if (workingDay === 'Yes') + $(row.cells[2]).addClass('text-danger'); + if (conflicts) + $(row.cells[3]).addClass('text-danger'); + conflictsCell.innerHTML = conflicts; + importCell.innerHTML = ``; +} + +function clearHolidayTable() { + let table = $('#holiday-list-table tbody')[0]; + // Clear all rows before adding new ones + while (table.rows.length >= 1) { + table.rows[0].remove(); + } +} + +function loadHolidaysTable() { + let holidays = getHolidays(); + if (holidays.length === 0) { + return; + } + + // Clear all rows before adding new ones + clearHolidayTable(); + + function addHoliday(holidayDate, holidayReason) { + let [tempYear, tempMonth, tempDay] = getDateFromISOStr(holidayDate); + // Holiday returns month with 1-12 index, but showDay expects 0-11 + let workingDay = showDay(tempYear, tempMonth - 1, tempDay) ? 'Yes' : 'No'; + let conflicts = waiverStore.get(holidayDate); + addHolidayToList(holidayDate, holidayReason, workingDay, conflicts ? conflicts['reason'] : ''); + } + + iterateOnHolidays(addHoliday); + // Show table and enable button + $('#holiday-list-table').show(); + toggleAddButton('holiday-button', true); +} + +function addHolidaysAsWaiver() { + function addHoliday(holidayDate, holidayReason) { + let importHoliday = $(`#import-${holidayDate}`)[0].checked; + if (importHoliday) { + waiverStore.set(holidayDate, { 'reason' : holidayReason, 'hours' : '08:00' }); + addRowToListTable(holidayDate, holidayReason, '08:00'); + } + } + iterateOnHolidays(addHoliday); + + //clear data from table and return the configurations to default + initializeHolidayInfo(); + showAlert('Loaded waivers for holidays.'); +} + +function initializeHolidayInfo() { + toggleAddButton('holiday-button', false); + populateYear(); + populateCountry(); + $('#holiday-list-table').hide(); + $('#state').hide(); + $('#holiday-state').hide(); + $('#city').hide(); + $('#holiday-city').hide(); + + $('#holiday-list-table').hide(); + // Clear all rows before adding new ones + clearHolidayTable(); +} + $(() => { let preferences = getUserPreferences(); applyTheme(preferences.theme); setDates(remote.getGlobal('waiverDay')); setHours(); - toggleAddButton(); + toggleAddButton('waive-button', $('#reason').val()); populateList(); $('#reason').on('keyup', () => { - toggleAddButton(); + toggleAddButton('waive-button', $('#reason').val()); }); $('#waive-button').on('click', () => { addWaiver(); }); + $('#holiday-button').on('click', () => { + addHolidaysAsWaiver(); + }); + + initializeHolidayInfo(); + $('#country').on('change', function() { + populateState($(this).find(':selected').val()); + loadHolidaysTable(); + }); + $('#state').on('change', function() { + populateCity($('#country').find(':selected').val(), $(this).find(':selected').val()); + loadHolidaysTable(); + }); + $('#city').on('change', function() { + loadHolidaysTable(); + }); + bindDevToolsShortcut(window); }); \ No newline at end of file