mmtf / Reaction Customizer

// ==UserScript==
// @name         Reaction Customizer
// @namespace    http://tampermonkey.net/
// @version      0.2
// @description  requires React Devtools to be installed!
// @author       mmtf
// @match        https://web.whatsapp.com/
// @icon         https://www.google.com/s2/favicons?sz=64&domain=whatsapp.com
// @grant        none
// @license      MIT
// ==/UserScript==

(function () {
  'use strict';
  let reactionsArray = null;
  let pickedReaction = null;

  const updateReaction = () => {
    if (reactionsArray && pickedReaction) {
      reactionsArray[5] = pickedReaction;
    }
  }

  const getRenderer = () => {
    const globalHook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__
    if (!globalHook) {
      console.debug("Reaction Customizer", "Waiting for react devtools...");
      return null;
    }

    const renderer = globalHook.renderers.get(1);
    if (!renderer) {
      return null;
    }

    return renderer;
  }

  const reactionsHook = setInterval(function () {
    const renderer = getRenderer();
    if (!renderer) {
      console.warn("Reaction Customizer", "Could not find renderer.");
    }

    const reactionPicker = document.querySelector('[role=dialog]');
    if (!reactionPicker) {
      console.debug("Reaction Customizer", "Waiting for reaction picker to open...");
      return;
    }

    try {
      const reactions = renderer.findFiberByHostInstance(reactionPicker.parentNode).return.return.memoizedProps.reactions;
      if (!reactions) {
        console.warn("Reaction Customizer", "Could not find reactions array in the open popup. Will continue to retry...");
        return;
      }
      reactionsArray = reactions;
      updateReaction();
    }
    catch (e) {
      console.warn("Reactions Customizer: Failed to reach reactions array");
      console.error(e);
    }
    clearInterval(reactionsHook);
  }, 300);

  const el = document.createElement('div');
  el.innerHTML = '<input type="text" id="reaction-picker" style="z-index:9999; position: relative"/>';

  document.body.onauxclick = (event) => {
    if (event.target) {
      if (event.target.classList.contains('emojik')) {
        const renderer = getRenderer();
        if (!renderer) {
          console.warn("Reaction Customizer", "Could not find renderer.");
          return;
        }

        let reaction;
        if (event.target.nodeName === "IMG") {
          reaction = event.target.alt;
        }
        else {
          reaction = renderer.findFiberByHostInstance(event.target).return.key;
        }

        if (!reaction) {
          return;
        }

        el.children[0].value = reaction;
        pickedReaction = reaction;
        updateReaction();
      }
    }
  }
  document.body.appendChild(el);
  document.querySelector('#reaction-picker').onchange = (e) => {
    if (e.target.value?.length > 0) {
      pickedReaction = e.target.value;
    }
    updateReaction();
  }
})();