From 0f4a4a5113febab3f12b8723fd9a89f65741e182 Mon Sep 17 00:00:00 2001 From: Fabio Gaspar Date: Wed, 30 Mar 2022 10:54:32 +0100 Subject: [PATCH] refactor(extractor/bills): Use 'EventExtractor' (#116). Replace inline dropdowns with modal for events. --- src/js/extractors/bills.js | 175 +++++++++++++++++++++++-------------- 1 file changed, 110 insertions(+), 65 deletions(-) diff --git a/src/js/extractors/bills.js b/src/js/extractors/bills.js index 8dabdd7..2e133b5 100644 --- a/src/js/extractors/bills.js +++ b/src/js/extractors/bills.js @@ -1,4 +1,4 @@ -class BillsExtractor extends Extractor { +class Bills extends EventExtractor { constructor() { super(); this.tableSelector = "#tab0 > table > tbody > tr"; @@ -6,89 +6,134 @@ class BillsExtractor extends Extractor { } structure() { - return { - extractor: "bills", - name: "Pending Bills", - description: "Extracts all pending bills from sigarra", - icon: "bill.png", - parameters: [ - { - name: "description", - description: - "eg: Propinas - Mestrado Integrado em Engenharia Informática e Computação - Prestação 1", - }, - { - name: "date", - description: "The payment deadline eg: 2019-03-31", - }, - { - name: "amount", - description: "The amount to pay e.g. 99,90€", - }, - ], - storage: { - text: [ + return super.structure( + { + extractor: "bills", + name: "Pending Bills", + description: "Extracts all pending bills from sigarra", + icon: "bill.png", + parameters: [ { - name: "title", - default: "${description}", + name: "description", + description: + "eg: Propinas - Mestrado Integrado em Engenharia Informática e Computação - Prestação 1", }, - ], - textarea: [ { - name: "description", - default: "Amount: ${amount}", + name: "deadline", + description: "The payment deadline eg: 2019-03-31", + }, + { + name: "amount", + description: "The amount to pay e.g. 99,90€", }, ], }, - }; + "${description}", + "Amount: ${amount}", + "", + false, + CalendarEventStatus.FREE + ); } - attachIfPossible() { - $("Sigtools").appendTo(this._getBillsHeader()[0]); - this._getBills().forEach((element, index) => { - let event = this._parsePendingBill(element); - let drop = getDropdown(event, this, undefined, { - target: "dropdown_" + index, - divClass: "dropdown removeFrame", - divStyle: "display:contents;", - dropdownStyle: "position: absolute;", - }); - $("").appendTo(element).append(drop[0]); - }, this); + /** + * + * @returns {HTMLElement | null} + */ + $pendingBillsTable() { + const $tables = document.querySelectorAll("#tab0 > table"); + return $tables.length > 0 ? $tables[0] : null; + } - setDropdownListeners(this, undefined); + /** + * + * @returns + */ + $pendingBillsTableRows() { + const $table = this.$pendingBillsTable(); + return $table ? $table.querySelectorAll("tbody > tr") : null; } - _getBills() { - let _billsDOM = $(this.tableSelector); // array-like object - return Array.prototype.slice.call(_billsDOM, 1); // array object, removing header row + attachIfPossible() { + // parse all pending bills + const events = this.getPendingBillsEvents(); + if (events.length === 0) return; + + // create button for opening the modal + const $calendarBtn = createElementFromString( + ` + + ` + ); + $calendarBtn.addEventListener("click", (e) => createEventsModal(events)); + + // insert the button before the table + this.$pendingBillsTable().insertAdjacentElement("beforebegin", $calendarBtn); } - _getBillsHeader() { - return $(this.tableSelector); + getPendingBillsEvents() { + // list of calendar events for all pending bills with available deadline + const eventsLst = []; + + const $bills = this.$pendingBillsTableRows(); + if (!$bills) return eventsLst; + + // iterate over the table rows, each row => a bill + // skip first row, it is a table header, inside tbody :) + for (let i = 1; i < $bills.length; i++) { + const $bill = $bills[i]; + + // extract the necessary parameters for this bill + const params = this.parseBill($bill); + + // if the bill has a deadline, create an event for it, otherwise skip + if (params.deadline) { + const ev = new CalendarEvent( + this.getTitle(params), + this.getDescription(params), + this.isHTML, + params.deadline, + null, + this.getLocation(params) + ); + ev.status = this.status; + eventsLst.push(ev); + } + } + + return eventsLst; } - _parsePendingBill(billEl) { - let getDateFromBill = function (index) { - let dateFromBill = BillsExtractor._getDateOrUndefined($(billEl).children(`:nth(${index})`).text()); - if (dateFromBill === undefined) dateFromBill = new Date(); - return dateFromBill; + /** + * + * @param {HTMLElement} $bill A element that contains the data + * regarding a pending bill + * + * @returns {{ + * description: string, + * amount: string, + * deadline: Date | null, + * }} + */ + parseBill($bill) { + /** + * @param {number} index The column index, starting at 1 + * @returns {string | null} + */ + const getColumnText = (index) => { + const $td = $bill.querySelector(`td:nth-child(${index})`); + return $td ? $td.innerText : null; }; + return { - description: $(billEl).children(":nth(2)").text(), - amount: $(billEl).children(":nth(7)").text(), - from: getDateFromBill(3), - to: getDateFromBill(4), - date: getDateFromBill(4), - location: "", - download: false, + description: getColumnText(3), + amount: getColumnText(8), + deadline: getColumnText(5) && new Date(getColumnText(5)), }; } - - static _getDateOrUndefined(dateString) { - return dateString ? new Date(dateString) : undefined; - } } // add an instance to the EXTRACTORS variable, and also trigger attachIfPossible due to constructor -EXTRACTORS.push(new BillsExtractor()); +EXTRACTORS.push(new Bills());