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
parent
1d5bdfe920
commit
16701a6313
|
@ -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/details/details.js";
|
||||||
import "@shoelace-style/shoelace/dist/components/icon/icon.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/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-style/shoelace/dist/components/textarea/textarea.js";
|
||||||
|
|
||||||
import "./shoelace.js";
|
import "./shoelace.js";
|
||||||
|
@ -10,6 +13,7 @@ import "./camera.ts";
|
||||||
|
|
||||||
import CameraInput from "./camera.ts";
|
import CameraInput from "./camera.ts";
|
||||||
import SlButton from "@shoelace-style/shoelace/dist/components/button/button.js";
|
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 { notify, notifyError } from "./alert";
|
||||||
import { getResponseError } from "./ajaxUtil.js";
|
import { getResponseError } from "./ajaxUtil.js";
|
||||||
|
@ -21,7 +25,10 @@ const btnUpload = form.querySelector(
|
||||||
"sl-button[class='choose-file']",
|
"sl-button[class='choose-file']",
|
||||||
) as SlButton;
|
) as SlButton;
|
||||||
const inpImage = form.photo as HTMLInputElement;
|
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) => {
|
form.addEventListener("submit", async (evt) => {
|
||||||
evt.preventDefault();
|
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();
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
{% extends "base" %} {% block head %}
|
{% extends "base" %} {% block head %}
|
||||||
<title>Add Receipt</title>
|
<title>Add Receipt</title>
|
||||||
|
<style></style>
|
||||||
{% endblock %} {% block main %}
|
{% endblock %} {% block main %}
|
||||||
<h1>Add Receipt</h1>
|
<h1>Add Receipt</h1>
|
||||||
<nav>
|
<nav>
|
||||||
|
@ -9,11 +10,24 @@
|
||||||
</nav>
|
</nav>
|
||||||
<article>
|
<article>
|
||||||
<form>
|
<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>
|
<p>
|
||||||
<sl-input
|
<sl-input
|
||||||
name="vendor"
|
name="vendor"
|
||||||
label="Vendor"
|
label="Vendor"
|
||||||
placeholder="Vendor"
|
placeholder="Vendor"
|
||||||
|
list="vendors"
|
||||||
required
|
required
|
||||||
></sl-input>
|
></sl-input>
|
||||||
</p>
|
</p>
|
||||||
|
@ -36,7 +50,7 @@
|
||||||
</sl-details>
|
</sl-details>
|
||||||
<sl-details summary="Upload Photo" style="text-align: center">
|
<sl-details summary="Upload Photo" style="text-align: center">
|
||||||
<p>
|
<p>
|
||||||
<img id="upload-preview" style="max-height: 400px"/>
|
<img id="upload-preview" style="max-height: 400px" />
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<input name="photo" type="file" style="display: none" />
|
<input name="photo" type="file" style="display: none" />
|
||||||
|
@ -47,6 +61,7 @@
|
||||||
</p>
|
</p>
|
||||||
</sl-details>
|
</sl-details>
|
||||||
<footer class="table-actions">
|
<footer class="table-actions">
|
||||||
|
<sl-button type="reset">Reset</sl-button>
|
||||||
<sl-button type="submit" variant="primary" disabled>Submit</sl-button>
|
<sl-button type="submit" variant="primary" disabled>Submit</sl-button>
|
||||||
</footer>
|
</footer>
|
||||||
</form>
|
</form>
|
||||||
|
|
Loading…
Reference in New Issue