crop dla userów i przeniesienie listy na inny miesiac

This commit is contained in:
Mateusz Gruszczyński
2025-07-28 13:20:23 +02:00
parent 9e3068a722
commit 643757e45e
9 changed files with 334 additions and 111 deletions

View File

@@ -4,22 +4,22 @@ let currentReceiptId;
document.addEventListener("DOMContentLoaded", function () {
const cropModal = document.getElementById("cropModal");
const cropImage = document.getElementById("cropImage");
const spinner = document.getElementById("cropLoading");
cropModal.addEventListener("shown.bs.modal", function (event) {
const button = event.relatedTarget;
const imgSrc = button.getAttribute("data-img-src");
currentReceiptId = button.getAttribute("data-receipt-id");
cropImage.src = imgSrc;
const image = document.getElementById("cropImage");
image.src = imgSrc;
if (cropper) {
cropper.destroy();
cropper = null;
}
cropImage.onload = () => {
cropper = new Cropper(cropImage, {
image.onload = () => {
cropper = new Cropper(image, {
viewMode: 1,
autoCropArea: 1,
responsive: true,
@@ -36,51 +36,7 @@ document.addEventListener("DOMContentLoaded", function () {
document.getElementById("saveCrop").addEventListener("click", function () {
if (!cropper) return;
spinner.classList.remove("d-none");
const cropData = cropper.getData();
const imageData = cropper.getImageData();
const scaleX = imageData.naturalWidth / imageData.width;
const scaleY = imageData.naturalHeight / imageData.height;
const width = cropData.width * scaleX;
const height = cropData.height * scaleY;
if (width < 1 || height < 1) {
spinner.classList.add("d-none");
showToast("Obszar przycięcia jest zbyt mały lub pusty", "danger");
return;
}
// Ogranicz do 2000x2000 w proporcji
const maxDim = 2000;
const scale = Math.min(1, maxDim / Math.max(width, height));
const finalWidth = Math.round(width * scale);
const finalHeight = Math.round(height * scale);
const croppedCanvas = cropper.getCroppedCanvas({
width: finalWidth,
height: finalHeight,
imageSmoothingEnabled: true,
imageSmoothingQuality: 'high',
});
if (!croppedCanvas) {
spinner.classList.add("d-none");
showToast("Nie można uzyskać obrazu przycięcia", "danger");
return;
}
croppedCanvas.toBlob(function (blob) {
if (!blob) {
spinner.classList.add("d-none");
showToast("Nie udało się zapisać obrazu", "danger");
return;
}
cropper.getCroppedCanvas().toBlob(function (blob) {
const formData = new FormData();
formData.append("receipt_id", currentReceiptId);
formData.append("cropped_image", blob);
@@ -91,7 +47,6 @@ document.addEventListener("DOMContentLoaded", function () {
})
.then((res) => res.json())
.then((data) => {
spinner.classList.add("d-none");
if (data.success) {
showToast("Zapisano przycięty paragon", "success");
setTimeout(() => location.reload(), 1500);
@@ -100,10 +55,9 @@ document.addEventListener("DOMContentLoaded", function () {
}
})
.catch((err) => {
spinner.classList.add("d-none");
showToast("Błąd sieci", "danger");
console.error(err);
});
}, "image/webp", 1.0);
}, "image/webp");
});
});
});

View File

@@ -0,0 +1,39 @@
(function () {
document.addEventListener("DOMContentLoaded", function () {
const cropModal = document.getElementById("adminCropModal");
const cropImage = document.getElementById("adminCropImage");
const spinner = document.getElementById("adminCropLoading");
const saveButton = document.getElementById("adminSaveCrop");
if (!cropModal || !cropImage || !spinner || !saveButton) return;
let cropper;
let currentReceiptId;
const currentEndpoint = "/admin/crop_receipt";
cropModal.addEventListener("shown.bs.modal", function (event) {
const button = event.relatedTarget;
const imgSrc = button.getAttribute("data-img-src");
currentReceiptId = button.getAttribute("data-receipt-id");
cropImage.src = imgSrc;
document.querySelectorAll('.cropper-container').forEach(e => e.remove());
if (cropper) cropper.destroy();
cropImage.onload = () => {
cropper = cropUtils.initCropper(cropImage);
};
});
cropModal.addEventListener("hidden.bs.modal", function () {
cropUtils.cleanUpCropper(cropImage, cropper);
cropper = null;
});
saveButton.addEventListener("click", function () {
if (!cropper) return;
spinner.classList.remove("d-none");
cropUtils.handleCrop(currentEndpoint, currentReceiptId, cropper, spinner);
});
});
})();

View File

@@ -0,0 +1,74 @@
// receipt_crop_logic.js
(function () {
function initCropper(imgEl) {
return new Cropper(imgEl, {
viewMode: 1,
autoCropArea: 1,
responsive: true,
background: false,
zoomable: true,
movable: true,
dragMode: 'move',
minContainerHeight: 400,
minContainerWidth: 400,
});
}
function cleanUpCropper(imgEl, cropperInstance) {
if (cropperInstance) {
cropperInstance.destroy();
}
if (imgEl) imgEl.src = "";
}
function handleCrop(endpoint, receiptId, cropper, spinner) {
const croppedCanvas = cropper.getCroppedCanvas({
imageSmoothingEnabled: false,
imageSmoothingQuality: "high",
});
if (!croppedCanvas) {
spinner.classList.add("d-none");
showToast("Nie można uzyskać obrazu przycięcia", "danger");
return;
}
croppedCanvas.toBlob(function (blob) {
if (!blob) {
spinner.classList.add("d-none");
showToast("Nie udało się zapisać obrazu", "danger");
return;
}
const formData = new FormData();
formData.append("receipt_id", receiptId);
formData.append("cropped_image", blob);
fetch(endpoint, {
method: "POST",
body: formData,
})
.then((res) => res.json())
.then((data) => {
spinner.classList.add("d-none");
if (data.success) {
showToast("Zapisano przycięty paragon", "success");
setTimeout(() => location.reload(), 1500);
} else {
showToast("Błąd: " + (data.error || "Nieznany"), "danger");
}
})
.catch((err) => {
spinner.classList.add("d-none");
showToast("Błąd sieci", "danger");
console.error(err);
});
}, "image/webp", 1.0);
}
window.cropUtils = {
initCropper,
cleanUpCropper,
handleCrop,
};
})();

View File

@@ -0,0 +1,39 @@
(function () {
document.addEventListener("DOMContentLoaded", function () {
const cropModal = document.getElementById("userCropModal");
const cropImage = document.getElementById("userCropImage");
const spinner = document.getElementById("userCropLoading");
const saveButton = document.getElementById("userSaveCrop");
if (!cropModal || !cropImage || !spinner || !saveButton) return;
let cropper;
let currentReceiptId;
const currentEndpoint = "/user_crop_receipt";
cropModal.addEventListener("shown.bs.modal", function (event) {
const button = event.relatedTarget;
const imgSrc = button.getAttribute("data-img-src");
currentReceiptId = button.getAttribute("data-receipt-id");
cropImage.src = imgSrc;
document.querySelectorAll('.cropper-container').forEach(e => e.remove());
if (cropper) cropper.destroy();
cropImage.onload = () => {
cropper = cropUtils.initCropper(cropImage);
};
});
cropModal.addEventListener("hidden.bs.modal", function () {
cropUtils.cleanUpCropper(cropImage, cropper);
cropper = null;
});
saveButton.addEventListener("click", function () {
if (!cropper) return;
spinner.classList.remove("d-none");
cropUtils.handleCrop(currentEndpoint, currentReceiptId, cropper, spinner);
});
});
})();