receipts/js/receipt-form.ts

101 lines
3.0 KiB
TypeScript

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/textarea/textarea.js";
import "./shoelace.js";
import "./camera.ts";
import CameraInput from "./camera.ts";
import SlButton from "@shoelace-style/shoelace/dist/components/button/button.js";
import { notify, notifyError } from "./alert";
const form = document.forms[0];
const cameraInput = form.querySelector("camera-input") as CameraInput;
const btnSubmit = form.querySelector("sl-button[type='submit']") as SlButton;
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;
form.addEventListener("submit", async (evt) => {
evt.preventDefault();
btnSubmit.loading = true;
const data = new FormData(form);
const blob = await cameraInput.getBlob();
if (blob) {
data.append("photo", blob, "photo.jpg");
}
let r: Response;
try {
r = await fetch("", {
method: "POST",
body: data,
});
} catch (e) {
notifyError(`Failed to submit form: ${e}`);
return;
} finally {
btnSubmit.loading = false;
}
if (r.ok) {
notify("Successfully uploaded receipt", undefined, undefined, null);
window.location.href = "/receipts";
} else {
let ct = r.headers.get("Content-Type");
if (ct && ct.indexOf("json") > -1) {
const json = await r.json();
if (json.error) {
notifyError(json.error);
return;
}
}
const html = await r.text();
if (html) {
const doc = new DOMParser().parseFromString(html, "text/html");
notifyError(doc.body.textContent ?? "");
} else {
notifyError(r.statusText);
}
}
});
cameraInput.addEventListener("ready", ((evt: CustomEvent) => {
btnSubmit.disabled = !evt.detail.hasPhoto;
btnUpload.disabled = !!evt.detail.hasPhoto;
if (!!evt.detail.hasPhoto) {
inpImage.value = "";
imgPreview.src = "";
}
}) as EventListener);
const cameraDetails = document.querySelector(
"sl-details[summary='Take Photo']",
)!;
let cameraInitialized = false;
cameraDetails.addEventListener("sl-show", () => {
if (!cameraInitialized) {
cameraInitialized = true;
cameraInput.startCamera();
}
});
btnUpload.addEventListener("click", (evt) => {
evt.preventDefault();
form.photo.showPicker();
});
inpImage.addEventListener("change", () => {
if (inpImage.files) {
const file = inpImage.files[0];
if (file) {
btnSubmit.disabled = false;
imgPreview.src = URL.createObjectURL(file);
}
}
});