receipt-form: Add auto-fill feature

The Add Receipt form now has a dropdown box that will automatically
populate the data fields from the properties of an existing transaction.
This will be helpful for the cases where the transaction was created
automatically, but still needs a receipt attached to it (e.g. Wal-Mart,
Target, etc. purchases and restaurants).
bugfix/ci-buildah
Dustin 2025-03-11 07:51:49 -05:00
parent 1d5bdfe920
commit 16701a6313
2 changed files with 75 additions and 2 deletions

View File

@ -2,6 +2,9 @@ import "@shoelace-style/shoelace/dist/components/button/button.js";
import "@shoelace-style/shoelace/dist/components/details/details.js";
import "@shoelace-style/shoelace/dist/components/icon/icon.js";
import "@shoelace-style/shoelace/dist/components/input/input.js";
import "@shoelace-style/shoelace/dist/components/option/option.js";
import "@shoelace-style/shoelace/dist/components/spinner/spinner.js";
import "@shoelace-style/shoelace/dist/components/select/select.js";
import "@shoelace-style/shoelace/dist/components/textarea/textarea.js";
import "./shoelace.js";
@ -10,6 +13,7 @@ import "./camera.ts";
import CameraInput from "./camera.ts";
import SlButton from "@shoelace-style/shoelace/dist/components/button/button.js";
import SlSelect from "@shoelace-style/shoelace/dist/components/select/select.js";
import { notify, notifyError } from "./alert";
import { getResponseError } from "./ajaxUtil.js";
@ -21,7 +25,10 @@ const btnUpload = form.querySelector(
"sl-button[class='choose-file']",
) as SlButton;
const inpImage = form.photo as HTMLInputElement;
const imgPreview = document.getElementById("upload-preview") as HTMLImageElement;
const imgPreview = document.getElementById(
"upload-preview",
) as HTMLImageElement;
const xactselect = document.getElementById("transactions") as SlSelect;
form.addEventListener("submit", async (evt) => {
evt.preventDefault();
@ -89,3 +96,54 @@ inpImage.addEventListener("change", () => {
}
}
});
async function fetchTransactions() {
let r: Response;
try {
r = await fetch("/transactions");
} catch (e) {
notifyError(e.toString());
return;
} finally {
xactselect.placeholder = "";
xactselect.querySelectorAll("sl-spinner").forEach((e) => e.remove());
}
if (!r.ok) {
notifyError(await getResponseError(r), 10000);
return;
}
xactselect.placeholder = "Select existing transaction";
xactselect.disabled = false;
for (const xact of await r.json()) {
const option = document.createElement("sl-option");
option.value = xact.id;
option.textContent = `${xact.description}${xact.date}$${xact.amount}`;
option.dataset.amount = xact.amount;
option.dataset.date = xact.date.split("T")[0];
option.dataset.vendor = xact.description;
xactselect.appendChild(option);
}
}
xactselect.addEventListener("sl-change", () => {
const value = xactselect.value;
if (!value) {
return;
}
const option: HTMLOptionElement | null = xactselect.querySelector(
`[value="${value}"]`,
);
if (!option) {
return;
}
form.querySelectorAll("sl-input").forEach((elm) => {
if (elm.name && elm.value !== undefined) {
const value = option.dataset[elm.name];
if (value) {
elm.value = value;
}
}
});
});
fetchTransactions();

View File

@ -1,5 +1,6 @@
{% extends "base" %} {% block head %}
<title>Add Receipt</title>
<style></style>
{% endblock %} {% block main %}
<h1>Add Receipt</h1>
<nav>
@ -9,11 +10,24 @@
</nav>
<article>
<form>
<p>
<sl-select
id="transactions"
name="transaction"
placeholder="Loading transactions …"
help-text="Select an existing transaction to auto fill fields"
disabled
clearable
>
<sl-spinner slot="suffix"></sl-spinner>
</sl-select>
</p>
<p>
<sl-input
name="vendor"
label="Vendor"
placeholder="Vendor"
list="vendors"
required
></sl-input>
</p>
@ -36,7 +50,7 @@
</sl-details>
<sl-details summary="Upload Photo" style="text-align: center">
<p>
<img id="upload-preview" style="max-height: 400px"/>
<img id="upload-preview" style="max-height: 400px" />
</p>
<p>
<input name="photo" type="file" style="display: none" />
@ -47,6 +61,7 @@
</p>
</sl-details>
<footer class="table-actions">
<sl-button type="reset">Reset</sl-button>
<sl-button type="submit" variant="primary" disabled>Submit</sl-button>
</footer>
</form>