app/templates/admin/extras/donations_change_form.html
{% 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 %}