Alfies — Status Update Notifier

Sends notifications when the order status gets updated

  1. // ==UserScript==
  2. // @name Alfies — Status Update Notifier
  3. // @name:de Alfies — Status Update Benachrichtigungen
  4. // @description Sends notifications when the order status gets updated
  5. // @description:de Sendet Benachrichtigungen, wenn der Bestellungsstatus aktualisiert wird
  6. // @version 1.4
  7. // @grant GM_notification
  8. // @match https://*.alfies.at/account/*
  9. // @icon https://external-content.duckduckgo.com/ip3/www.alfies.at.ico
  10. // @require https://cdn.jsdelivr.net/npm/@violentmonkey/dom@2
  11. // @license GPL v3
  12. // @author incognico
  13. // @namespace https://greasyfork.org/users/931787
  14. // ==/UserScript==
  15.  
  16. // various selectors
  17. const orderStatusWrapper = '[class^=AccountOrderPage_accountorderwrapper__]';
  18.  
  19. const orderStatusClass = 'OrderStatus_orderstatus';
  20. const subTreeItem = `[class^=${orderStatusClass}__statustreeitem__]`; // call .dataset.active on these to check
  21.  
  22. const headerList = '[class^=Header_profilenav__] > ul';
  23.  
  24. const orderStatusTitle = `[class^=${orderStatusClass}__] > p`;
  25.  
  26. // IDs to only create these once
  27. const alfiesNotifierId = 'alfies-notifier';
  28. const slideInAnimationId = 'alfies-notifier-slidein';
  29.  
  30. // need to remember last values to watch for changes
  31. let lastStatusTitle = undefined;
  32. let lastActiveStatus = undefined;
  33.  
  34. const disconnect = VM.observe(document.body, () => {
  35. // Is on order status page?
  36. const orderStatus = document.querySelector(orderStatusWrapper);
  37. if (orderStatus) {
  38. defineSlideInAnimation();
  39. createNotifierIfNotExists();
  40. watchTitleChanges();
  41. watchStatusTreeChanges();
  42. } else {
  43. destroyNotifier();
  44. }
  45. });
  46.  
  47. const defineSlideInAnimation = () => {
  48. const slideInAnimation = document.getElementById(slideInAnimationId);
  49. if (!slideInAnimation) {
  50. const style = document.createElement('style');
  51. style.id = slideInAnimationId;
  52. style.textContent = `
  53. @keyframes slidein {
  54. from {
  55. transform: translateY(-100%);
  56. }
  57. to {
  58. transform: translateY(0);
  59. }
  60. }
  61. `;
  62. document.head.appendChild(style);
  63. }
  64. };
  65.  
  66. const createNotifierIfNotExists = () => {
  67. const notifierExists = document.getElementById(alfiesNotifierId);
  68. if (!notifierExists) {
  69. const notifier = document.createElement('div');
  70. notifier.id = alfiesNotifierId;
  71. notifier.textContent = 'Alfies Status Update Notifier is active!';
  72.  
  73. // assign style to the notifier
  74. const style = {
  75. color: '#72ff72',
  76. marginBottom: '10px',
  77. textAlign: 'center',
  78. fontSize: '1.5em',
  79. fontWeight: 'bold',
  80. border: '2px solid #00d900',
  81. padding: '10px',
  82. borderRadius: '10px',
  83. marginTop: '10px',
  84. backgroundColor: 'rgba(0, 255, 0, 0.1)',
  85. boxShadow: '0 0 10px 0 rgba(0, 255, 0, 0.5)',
  86. // slide in animation
  87. animation: 'slidein 1s',
  88. animationFillMode: 'forwards',
  89. };
  90. Object.assign(notifier.style, style);
  91.  
  92. // append notifier to the header list
  93. const header = document.querySelector(headerList);
  94. if (header) {
  95. header.appendChild(notifier);
  96. }
  97. }
  98. };
  99.  
  100. const destroyNotifier = () => {
  101. const notifier = document.getElementById(alfiesNotifierId);
  102. if (notifier) {
  103. notifier.remove();
  104. }
  105. };
  106.  
  107. const timeout = 10000;
  108. const image = 'https://external-content.duckduckgo.com/ip3/www.alfies.at.ico';
  109.  
  110. const watchTitleChanges = () => {
  111. const statusTitle = document.querySelector(orderStatusTitle)?.textContent;
  112. if (statusTitle && statusTitle !== lastStatusTitle) {
  113. GM_notification({
  114. title: 'Alfies Status Change',
  115. text: statusTitle,
  116. timeout,
  117. image,
  118. });
  119. }
  120. lastStatusTitle = statusTitle;
  121. };
  122.  
  123. const watchStatusTreeChanges = () => {
  124. const statusTreeItems = Array.from(document.querySelectorAll(subTreeItem));
  125. const activeStatus = statusTreeItems.filter(item => item.dataset.active === 'true');
  126. if (activeStatus.length && lastActiveStatus !== undefined && activeStatus.length !== lastActiveStatus.length) {
  127. const activeStatusNames = activeStatus.map(item => item.textContent);
  128. GM_notification({
  129. title: 'Alfies Status Checklist Update',
  130. text: activeStatusNames[activeStatusNames.length - 1],
  131. timeout,
  132. image,
  133. });
  134. }
  135. lastActiveStatus = activeStatus;
  136. };