Keka Log Duration by Jp

try to take over the world

当前为 2024-02-28 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Keka Log Duration by Jp
  3. // @namespace http://tampermonkey.net/
  4. // @version 2023-12-27
  5. // @description try to take over the world
  6. // @author You
  7. // @match https://ezeetechnosys.keka.com/
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=keka.com
  9. // @grant none
  10. // @license MIT
  11. // ==/UserScript==
  12.  
  13. (function() {
  14. 'use strict';
  15. const channel = new BroadcastChannel('keka-duration');
  16. let fistDuration;
  17. let secondDuration;
  18. function parseTime(timeStr) {
  19. const parts = timeStr.split(':');
  20. return parseInt(parts[0]) * 3600000 + parseInt(parts[1]) * 60000 + parseInt(parts[2]) * 1000;
  21. }
  22. function calculateTotalDuration(duration1Str, duration2Str) {
  23. // Extract hours and minutes from each duration string
  24. const [hours1, minutes1] = duration1Str.match(/\d+/g);
  25. const [hours2, minutes2] = duration2Str.match(/\d+/g);
  26.  
  27. // Convert hours and minutes to numbers
  28. const hours1Num = parseInt(hours1);
  29. const minutes1Num = parseInt(minutes1);
  30. const hours2Num = parseInt(hours2);
  31. const minutes2Num = parseInt(minutes2);
  32. console.log("IIIIIIIIIIIIIIIIII",hours1Num,minutes1Num,hours2Num,minutes2Num)
  33. // Add hours and minutes separately
  34. const totalMinutes = minutes1Num + minutes2Num;
  35. const totalHours = hours1Num + hours2Num + Math.floor(totalMinutes / 60);
  36. const remainingMinutes = totalMinutes % 60;
  37.  
  38. // Format the total duration string
  39. const totalDurationStr = `${totalHours} Hr ${remainingMinutes} Min`;
  40.  
  41. return totalDurationStr;
  42. }
  43.  
  44. function calculateDuration(startTimeSpan, endTimeSpan) {
  45. const startTimeStr = startTimeSpan.textContent.trim();
  46. const endTimeStr = endTimeSpan.textContent.trim();
  47.  
  48. // If end time is empty, use current time
  49. const endTime = endTimeStr !="MISSING" ? endTimeStr : new Date().toLocaleTimeString('en-US', { hour12: true });
  50. console.log("TIMES",startTimeStr,endTime);
  51. // Parse time strings into Date objects
  52. const startTime = new Date(`2023-12-27 ${startTimeStr}`); // Assuming today's date
  53. const endTimeDate = new Date(`2023-12-27 ${endTime}`);
  54.  
  55. // Calculate duration in milliseconds
  56. const durationMillis = endTimeDate.getTime() - startTime.getTime();
  57.  
  58. // Convert milliseconds to hours and minutes
  59. const durationHours = Math.floor(durationMillis / (3600 * 1000));
  60. const durationMinutes = Math.floor((durationMillis % (3600 * 1000)) / (60 * 1000));
  61.  
  62. // Formatted duration string
  63. const durationStr = `${durationHours} Hr ${durationMinutes} Min`;
  64.  
  65. return durationStr;
  66. }
  67.  
  68. function watchForModals() {
  69. const modals = document.querySelectorAll('body > modal-container > div.modal-dialog.small-modal > div > attendance-adjustment-request > div.modal-body > form > div.mt-20 > div > div:nth-child(2) > div');
  70. console.log("Modals",modals)
  71.  
  72. modals.forEach(modal => {
  73.  
  74. const modalsArray = Array.from(modals);
  75. const dayIndex = modalsArray.indexOf(modal) + 1; // Determine the day index (1, 2, or 3)
  76.  
  77. const displaySpanXPath = `/html/body/modal-container/div[2]/div/attendance-adjustment-request/div[2]/form/div[2]/div/div[2]/div/div/div/div[1]/span[1]`;
  78. const displaySpan = document.evaluate(
  79. displaySpanXPath,
  80. modal,
  81. null,
  82. XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
  83. null
  84. ).snapshotItem(0);
  85.  
  86. const startTimeSpan = document.evaluate(
  87. '/html/body/modal-container/div[2]/div/attendance-adjustment-request/div[2]/form/div[2]/div/div[2]/div/div/div[1]/div[1]/div[2]/span[2]',
  88. modal,
  89. null,
  90. XPathResult.FIRST_ORDERED_NODE_TYPE,
  91. null
  92. ).singleNodeValue;
  93.  
  94. const endTimeSpan = document.evaluate(
  95. '/html/body/modal-container/div[2]/div/attendance-adjustment-request/div[2]/form/div[2]/div/div[2]/div/div/div[1]/div[1]/div[3]/span[2]',
  96. modal,
  97. null,
  98. XPathResult.FIRST_ORDERED_NODE_TYPE,
  99. null
  100. ).singleNodeValue;
  101.  
  102. const startTimeSpan1 = document.evaluate(
  103. '/html/body/modal-container/div[2]/div/attendance-adjustment-request/div[2]/form/div[2]/div/div[2]/div/div/div[2]/div[1]/div[2]/span[2]',
  104. modal,
  105. null,
  106. XPathResult.FIRST_ORDERED_NODE_TYPE,
  107. null
  108. ).singleNodeValue;
  109.  
  110. const endTimeSpan1 = document.evaluate(
  111. '/html/body/modal-container/div[2]/div/attendance-adjustment-request/div[2]/form/div[2]/div/div[2]/div/div/div[2]/div[1]/div[3]/span[2]',
  112. modal,
  113. null,
  114. XPathResult.FIRST_ORDERED_NODE_TYPE,
  115. null
  116. ).singleNodeValue;
  117.  
  118. if (startTimeSpan && endTimeSpan) {
  119. const durationStr = calculateDuration(startTimeSpan, endTimeSpan);
  120. fistDuration = durationStr
  121. const durationDisplaySpan = document.querySelector('.d-flex.align-items-center.ml-10');
  122. window.postMessage({ type: 'duration', value: durationStr }, '*');
  123. console.log("POSTED-DURATION")
  124. // Check for existing duration span:
  125. const existingDurationSpan = durationDisplaySpan.querySelector('.duration-span-1');
  126. if (!existingDurationSpan) {
  127. // Create span only if it doesn't exist
  128. const durationSpan = document.createElement('span');
  129. durationSpan.classList.add('duration-span-1'); // Add class for identification
  130. durationSpan.textContent = durationStr;
  131. durationSpan.style.fontWeight = 'bold';
  132. durationSpan.style.paddingLeft = '17px';
  133. durationSpan.style.color = 'darkred';
  134. durationDisplaySpan.insertAdjacentElement('afterend', durationSpan);
  135. } else {
  136. console.log("Duration span already exists, skipping creation.");
  137. }
  138. }
  139.  
  140. if (startTimeSpan1 && endTimeSpan1) {
  141. console.log("11111111--11111", startTimeSpan1, endTimeSpan1)
  142. const durationStr = calculateDuration(startTimeSpan1, endTimeSpan1);
  143. secondDuration = durationStr;
  144. const durationDisplaySpan = document.querySelector('body > modal-container > div.modal-dialog.small-modal > div > attendance-adjustment-request > div.modal-body > form > div.mt-20 > div > div:nth-child(2) > div > div > div:nth-child(2) > div.d-flex.align-items-center.ng-untouched.ng-pristine.ng-valid > div.d-flex.align-items-center.ml-10');
  145. console.log("durationDisplaySpan", durationDisplaySpan)
  146.  
  147. // Check for existing duration span:
  148. const existingDurationSpan = durationDisplaySpan.querySelector('.duration-span-2');
  149. if (!existingDurationSpan) {
  150. // Create span only if it doesn't exist
  151. const durationSpan = document.createElement('span');
  152. durationSpan.classList.add('duration-span-2'); // Add class for identification
  153. durationSpan.textContent = durationStr;
  154. durationSpan.style.fontWeight = 'bold';
  155. durationSpan.style.paddingLeft = '17px';
  156. durationSpan.style.color = 'darkred';
  157. durationDisplaySpan.insertAdjacentElement('afterend', durationSpan);
  158. } else {
  159. console.log("Duration span already exists, skipping creation.");
  160. }
  161.  
  162. const totaldurationDisplaySpan = document.querySelector('body > modal-container > div.modal-dialog.small-modal > div > attendance-adjustment-request > div.modal-body > form > div.mt-20 > div > div:nth-child(2) > div > div > div:nth-child(2) > div.d-flex.align-items-center.ng-untouched.ng-pristine.ng-valid');
  163. console.log(fistDuration, secondDuration, "#################")
  164. const total = calculateTotalDuration(fistDuration, secondDuration);
  165. console.log("total" , total)
  166.  
  167. // Check for existing total duration span:
  168. const existingTotalDurationSpan = totaldurationDisplaySpan.querySelector('.total-duration-span');
  169. if (!existingTotalDurationSpan) {
  170. // Create span only if it doesn't exist
  171. const TotaldurationSpan = document.createElement('span'); // Added closing parenthesis
  172. TotaldurationSpan.classList.add('total-duration-span'); // Add class for identification
  173. TotaldurationSpan.textContent = total;
  174. TotaldurationSpan.style.fontWeight = 'bold';
  175. // TotaldurationSpan.style.paddingLeft = '17px';
  176. TotaldurationSpan.style.color = '#0600ff';
  177. TotaldurationSpan.style.float = 'right';
  178. TotaldurationSpan.style.padding = '5px';
  179. TotaldurationSpan.style.background = 'lightblue';
  180. TotaldurationSpan.style.marginRight = '150px';
  181. TotaldurationSpan.style.borderRadius = '5px';
  182. TotaldurationSpan.style.borderTop = '3px solid #888'
  183. totaldurationDisplaySpan.insertAdjacentElement('afterend', TotaldurationSpan);
  184.  
  185. }
  186. }
  187.  
  188. })
  189. };
  190.  
  191.  
  192. const observer = new MutationObserver(mutations => {
  193. console.log("Observing.....")
  194. const modalTriggerElements = document.querySelectorAll('employee-attendance-list-view .attendance-logs-row');
  195. modalTriggerElements.forEach(element => {
  196. element.addEventListener('click', watchForModals);
  197. });
  198. });
  199.  
  200. observer.observe(document.body, { childList: true, subtree: false });
  201.  
  202. })(); // Closed parenthesis for the immediately invoked function expression