Pestpac - Easy Quick Scheduler Buttons

Adds buttons to select technicians by area and dates up to 7 days from the latest selected date in the calendar in Pestpac

  1. // ==UserScript==
  2. // @name Pestpac - Easy Quick Scheduler Buttons
  3. // @version 5.2.2
  4. // @description Adds buttons to select technicians by area and dates up to 7 days from the latest selected date in the calendar in Pestpac
  5. // @match https://app.pestpac.com/appointment/*
  6. // @author Jamie Cruz
  7. // @grant none
  8. // @license MIT
  9. // @namespace https://greasyfork.org/users/1433767
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. 'use strict';
  14.  
  15. /**
  16. * Creates and inserts the button container for technician selection.
  17. * This container is styled as a scrollable two-column grid.
  18. * It is placed next to the "Refresh Search" button for accessibility.
  19. * @returns {HTMLElement} The created container element.
  20. */
  21. function createButtonContainer() {
  22. var container = document.createElement("div");
  23. container.id = "techbuttons";
  24. container.classList.add("slim-scrollbar", "pr-tiny"); // Applies styling for custom scrollbar
  25. container.style.display = "grid";
  26. container.style.gridTemplateColumns = "auto auto"; // Two columns with flexible sizing
  27. container.style.gap = "5px"; // Space between buttons
  28. container.style.overflowY = "auto"; // Enables vertical scrolling
  29. container.style.maxHeight = "125px"; // Limits height for a compact view
  30. container.style.border = "1px solid #ccc"; // Adds a border for clarity
  31. container.style.padding = "10px";
  32. container.style.marginBottom = "10px";
  33. container.style.width = "fit-content"; // Prevents unnecessary horizontal scrolling
  34.  
  35. var refreshSearchButton = document.getElementById("butRefreshSearch");
  36. if (refreshSearchButton) {
  37. refreshSearchButton.parentNode.insertBefore(container, refreshSearchButton.nextSibling);
  38. } else {
  39. console.error("Element with ID 'butRefreshSearch' not found."); // Logs an error if the expected element is missing
  40. }
  41. return container;
  42. }
  43.  
  44. /**
  45. * Adds a technician selection button to the container.
  46. * Clicking the button selects specific rows based on given range IDs.
  47. * @param {string} buttonText - Label for the button.
  48. * @param {string} color - Background color for the button.
  49. * @param {Array} rowRanges - Array of start and end row IDs to select.
  50. * @param {HTMLElement} container - The container to add the button to.
  51. * @param {string} position - Positioning data for organizational purposes.
  52. */
  53. function addTechButton(buttonText, color, rowRanges, container, position) {
  54. var button = document.createElement("button");
  55. button.innerHTML = buttonText;
  56. button.style.width = "90px"; // Uniform button size
  57. button.style.height = "28px";
  58. button.style.fontSize = "12px"; // Smaller text for clarity
  59. button.style.backgroundColor = color;
  60. button.style.color = "white";
  61. button.style.border = "none";
  62. button.style.borderRadius = "5px";
  63. button.style.cursor = "pointer";
  64. button.style.textAlign = "center";
  65. button.setAttribute("data-position", position); // Stores position metadata
  66. var positionParts = position.split(":");
  67. button.style.gridRow = positionParts[0]; // Assigns the row number
  68. button.style.gridColumn = positionParts[1]; // Assigns the column number
  69.  
  70. container.appendChild(button);
  71.  
  72. button.addEventListener("click", function() {
  73. // Deselects all previously selected rows
  74. document.querySelectorAll("tr.SelectedRow").forEach(row => {
  75. row.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, view: window }));
  76. row.classList.remove("SelectedRow");
  77. });
  78.  
  79. // Selects new rows based on predefined ID ranges
  80. for (let range of rowRanges) {
  81. for (let i = range.start; i <= range.end; i++) {
  82. let row = document.querySelector("table.insetTable #MultiTechRow" + i);
  83. if (row) {
  84. row.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, view: window }));
  85. row.classList.add("SelectedRow");
  86. } else {
  87. console.error("Row with ID 'MultiTechRow" + i + "' not found.");
  88. }
  89. }
  90. }
  91. });
  92. }
  93.  
  94. /**
  95. * Adds a button to automatically select the next 7 calendar dates after the last selected date.
  96. * Useful for scheduling appointments efficiently.
  97. */
  98. function addSelectButton() {
  99. var button = document.createElement("button");
  100. button.innerHTML = "+7";
  101. button.style.width = "60px"; // Compact button
  102. button.style.height = "28px";
  103. button.style.fontSize = "12px";
  104. button.style.backgroundColor = "#1565C0";
  105. button.style.color = "white";
  106. button.style.border = "none";
  107. button.style.borderRadius = "5px";
  108. button.style.cursor = "pointer";
  109.  
  110. var updateCalendarButton = document.getElementById("butUpdateCalendarDate");
  111. if (updateCalendarButton) {
  112. updateCalendarButton.parentNode.insertBefore(button, updateCalendarButton.nextSibling);
  113. } else {
  114. console.error("Element with ID 'butUpdateCalendarDate' not found.");
  115. }
  116.  
  117. button.addEventListener("click", function() {
  118. var selectedDates = document.querySelectorAll(".selectedcalendarlink");
  119. if (selectedDates.length === 0) {
  120. alert("No date selected.");
  121. return;
  122. }
  123.  
  124. var latestSelectedDate = selectedDates[selectedDates.length - 1];
  125. var latestDateText = latestSelectedDate.textContent.trim();
  126. var latestDate = new Date(latestDateText);
  127.  
  128. var calendarDates = document.querySelectorAll("table.insetTable .calendarlink, table.insetTable .selectedcalendarlink");
  129. var count = 0;
  130. var latestFound = false;
  131. for (var i = 0; i < calendarDates.length; i++) {
  132. var dateText = calendarDates[i].textContent.trim();
  133. if (latestFound && count < 7) {
  134. calendarDates[i].dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, view: window }));
  135. count++;
  136. }
  137. if (dateText === latestDateText) {
  138. latestFound = true;
  139. }
  140. }
  141. });
  142. }
  143.  
  144. /**
  145. * Initializes the script by creating the button container and adding technician selection buttons.
  146. * Also adds the "+7" button for date selection.
  147. */
  148. window.onload = function() {
  149. var container = createButtonContainer();
  150.  
  151. addTechButton("VA techs", "#262F6A", [{ start: 3, end: 10 }], container, "1:1");
  152. addTechButton("VA ACT", "#0057E9", [{ start: 3, end: 4 }, { start: 6, end: 7 }], container, "2:1");
  153. addTechButton("VA TM", "#262F6A", [{ start: 4, end: 4 }, { start: 6, end: 6 }], container, "3:1");
  154. addTechButton("Tide", "#52C5D8", [{ start: 24, end: 26 }], container, "4:1");
  155. addTechButton("MD techs", "#EF4255", [{ start: 11, end: 23 }], container, "1:2");
  156. addTechButton("MD TM", "#EF4255", [{ start: 11, end: 14 }, { start: 17, end: 17 }], container, "3:2");
  157. addTechButton("MD ACT", "#F5A623", [{ start: 11, end: 18 }, { start: 21, end: 21 }], container, "2:2");
  158.  
  159. addSelectButton("+7", "#1565C0");
  160. };
  161. })();