CodeTheChangeUBC/reBOOT

View on GitHub
app/templates/admin/extras/donations_change_form.html

Summary

Maintainability
Test Coverage
{% extends 'admin/change_form.html' %}
{% load i18n static %}

{% block extrastyle %}
    {{ block.super }}
    <link rel="stylesheet" type="text/css" href="{% static "admin/css/donation_change_form.css" %}">
    <link rel="stylesheet" href="//code.jquery.com/ui/1.13.1/themes/base/jquery-ui.css">
{% endblock %}

{% block extrahead %}
  {{ block.super }}
  <script src="https://code.jquery.com/jquery-1.9.1.js"></script>
  <script src="https://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
  <script>
    const AUTOCOMPLETE_MIN_LENGTH = 2;

    function debounce(func, timeout = 200){
      let timer;
      return (...args) => {
        if (!timer) {
          func.apply(this, args);
        }
        clearTimeout(timer);
        timer = setTimeout(() => { func.apply(this, args); }, timeout);
      };
    }
    const getDonorData = debounce((filter="") => {
      $.ajax({
        type: "GET",
        url: "/api/donor_info_auto_complete",
        data: { filter },
        success(res) {
          DONOR_ID_API.data = res.donorInfos;
        },
        error(res) {
          console.error(res)
        }
      });
    });

    const getItemDeviceData = debounce((filter="") => {
      $.ajax({
        type: "GET",
        url: "/api/device_info_auto_complete",
        data: { filter },
        success(res) {
          ITEM_DEVICE_ID_API.data = res.deviceInfos;
        },
        error(res) {
          console.error(res)
        }
      });
    });

    function applyAutocomplete(element, api) {
      element.autocomplete({
          source: (request, response) => matchStartingWithInput(request, response, api),
          select: function(event, ui) {
            const value = getID(ui?.item?.value || "");
            $(this).val(value);
            return false;
          },
          autoFocus: true,
          minLength: AUTOCOMPLETE_MIN_LENGTH,
        });
    }

    /**
     * Return matches that start with the input
     */
    let prevFirstTwo = "";
    async function matchStartingWithInput({ term }, response, api) {
      if (!term.toUpperCase().startsWith(prevFirstTwo)) {
        // trigger autocomplete fetch
        await api.fetch(term);
      }
      prevFirstTwo = term.toUpperCase().substr(0, AUTOCOMPLETE_MIN_LENGTH);
      const matches = api.data.filter((item) =>
          item.toUpperCase().includes(term.toUpperCase()));
      response(matches);
    }

    /**
     * Get ID assuming the input str is ending with "{info} | {id}"
     */
    function getID(str) {
      const strArr = str.split(" | ");
      return strArr[strArr.length-1] ?? "";
    }


    const DONOR_ID_SELECTOR = "#id_donor"
    const ITEM_DEVICE_ID_SELECTOR = "input[id^='id_item_set-'][id$='-device']"
    const DONOR_ID_API = {
      data: [],
      fetch: getDonorData,
    };
    const ITEM_DEVICE_ID_API = {
      data: [],
      fetch: getItemDeviceData,
    }

    $(document).ready(() => {
      // Add autocomplete when Item Device ID field is clicked as it's dynamic
      $(document).on("click", ITEM_DEVICE_ID_SELECTOR, (e) => {
        applyAutocomplete($(`#${e.target.id}`), ITEM_DEVICE_ID_API);
      });
      applyAutocomplete($(DONOR_ID_SELECTOR), DONOR_ID_API);
    });
  </script>
{% endblock %}

{% block submit_buttons_bottom %}
  {{ block.super }}
  <div class="submit-row">
    <input type="submit" value="Save and Mark items verified" name="_mark_items_verified">
    <input type="submit" value="Save and Mark items unverified" name="_mark_items_unverified">
    {% if not is_popup and change %}
      {% if perms.app.generate_tax_receipt %}
        <input type="submit" class="button-danger" value="Save and Generate tax receipt" name="_generate_receipt">
      {% else %}
        <input type="submit" class="button-danger" value="Save and Generate tax receipt" name="_generate_receipt" disabled>
      {% endif %}
    {% endif %}
  </div>
{% endblock %}