perbaikan foto dan penambahan basic data foto objek jaminan, print-out

This commit is contained in:
majid
2024-12-29 06:10:45 +07:00
parent 9a24751f65
commit e62524e683
19 changed files with 1175 additions and 676 deletions

View File

@@ -1,71 +1,76 @@
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function() {
const ruteLainnyaDiv = document.getElementById("ruteLainnya");
// const lantaiLainnyaDiv = document.getElementById("lantaiLainnya");
const lantaiLainnyaDiv = document.getElementById("lantaiLainnya");
// Function to add delete event listeners to existing buttons
function addDeleteListeners(container) {
container.querySelectorAll(".delete-btn").forEach(button => {
button.addEventListener("click", function() {
this.closest(
".flex.items-baseline.flex-wrap.lg\\:flex-nowrap.gap-2\\.5.mb-5"
).remove();
".flex.items-baseline.flex-wrap.lg\\:flex-nowrap.gap-2\\.5.mb-5")
.remove();
});
});
}
// Add delete listeners to existing buttons
addDeleteListeners(ruteLainnyaDiv);
// addDeleteListeners(lantaiLainnyaDiv);
// Create new div for additional items
function createNewDiv(container, inputName) {
const newDiv = document.createElement("div");
newDiv.className = "flex items-baseline flex-wrap lg:flex-nowrap gap-2.5 mb-5";
const index = container.querySelectorAll(".flex.items-baseline")
.length; // Get index for dynamic IDs
newDiv.innerHTML = `
<div class="flex items-baseline w-full flex-wrap lg:flex-nowrap gap-2.5 mb-5" id="photoContainer">
<label class="flex flex-col form-label max-w-56">
Masukkan nama ${inputName}
</label>
<div class="flex flex-wrap items-baseline w-full">
<div class="flex flex-wrap items-baseline w-full gap-4">
<img id="foto_${inputName}-preview-${index}"
src="{{ isset($formFoto['gerbang']) ? asset('storage/' . $formFoto['gerbang']) : '' }}"
alt="Foto Gerbong" class="mt-2 max-w-full h-auto"
style="{{ isset($formFoto['gerbang']) ? '' : 'display: none;' }} width: 30rem;">
<div class="flex flex-col lg:flex-row gap-2 w-full">
<div class="flex flex-wrap items-baseline px-2">
<input class="input" type="text" name="name_${inputName}[]">
</div>
<div class=" w-full flex flex-col gap-2">
<img id="foto_${inputName}-preview"
src="{{ isset($formFoto['gerbang']) ? asset('storage/' . $formFoto['gerbang']) : '' }}"
alt="Foto Gerbong" class="mt-2 max-w-full h-auto"
style="{{ isset($formFoto['gerbang']) ? '' : 'display: none;' }} width: 30rem;">
<div class="input-group w-full flex gap-2">
<input id="inputLainnya" type="file" name="foto_${inputName}[]"
class="file-input file-input-bordered w-full" accept="image/*" capture="camera"
onchange="previewImage(this, 'foto_${inputName}-preview')"
>
<button type="button" id="btnCamera" class="btn btn-light"
data-modal-toggle="#cameraModal">
<i class="ki-outline ki-abstract-33"></i> Camera
<div class="input-group w-full flex flex-col gap-2">
<div class="input-group w-full flex gap-2">
<input id="inputLainnya-${index}" type="file" name="foto_${inputName}[]"
class="file-input file-input-bordered w-full" accept="image/*"
capture="camera" onchange="previewImage(this, 'foto_${inputName}-preview-${index}')">
<button type="button" id="btnCamera-${index}" class="btn btn-light"
data-modal-toggle="#cameraModal">
<i class="ki-outline ki-abstract-33"></i> Camera
</button>
</div>
</div>
</div>
<button type="button" class="btn btn-danger btn-sm delete-btn">
<i class="ki-filled ki-trash"></i>
</button>
</div>
</div>
`;x
</div>
`;
container.appendChild(newDiv);
addDeleteListeners(container);
addDeleteListeners(container); // Re-add listeners for delete buttons in the new div
}
// Event listener for adding more items
document.getElementById("btnAddMore").addEventListener("click", function() {
createNewDiv(ruteLainnyaDiv, "rute_lainnya");
});
// document.getElementById("btnAddMoreObject").addEventListener("click", function() {
// createNewDiv(lantaiLainnyaDiv, "lantai_lainnya");
// });
document.getElementById("btnAddMoreObject").addEventListener("click", function() {
createNewDiv(lantaiLainnyaDiv, "lantai_lainnya");
});
function setupInputHandlers(containerId, buttonId, labelText, inputDataClass, buttonDeleteClass) {
const addButton = document.getElementById(buttonId);
@@ -185,13 +190,331 @@
}
setupInputHandlers('inputContainerRute', 'btnRute', 'Foto Rute Menuju Lokasi', 'file-input',
'delete-btn');
// setupInputHandlers('inputContainerRute', 'btnRute', 'Foto Rute Menuju Lokasi', 'file-input',
// 'delete-btn');
// setupInputHandlers('inputContainerLantai', 'btnLantai', 'Foto Lantai', 'file-input',
// 'delete-btn');
setupInputHandlers('inputContainerLingkungan', 'btnLingkungan', 'Lingkungan', 'file-input',
'delete-btn');
// setupInputHandlers('inputContainerLingkungan', 'btnLingkungan', 'Lingkungan', 'file-input',
// 'delete-btn');
});
class DynamicFileUploader {
constructor(options) {
const defaultOptions = {
containerId: 'lantaiContainer',
addButtonId: null,
fileInputName: 'foto_lantai_unit',
maxFiles: 4,
allowMultiple: true,
name: null,
accept: 'image/*',
existingFiles: []
};
this.options = {
...defaultOptions,
...options
};
this.container = document.getElementById(this.options.containerId);
if (this.options.addButtonId) {
this.addButton = document.getElementById(this.options.addButtonId);
this.addButton.addEventListener('click', () => {
this.addNewItem();
});
}
// Inisialisasi global handlers
this.initGlobalHandlers();
this.init();
}
initGlobalHandlers() {
// Simpan instance ke window untuk akses global
// window.dynamicFileUploader = this;
// Global handler untuk drag and drop
window.handleDrop = (event) => {
event.preventDefault();
event.stopPropagation();
const dropzone = event.currentTarget;
const fileInput = dropzone.querySelector('.file-input');
this.handleDrop(event, fileInput);
};
window.allowDrop = (event) => {
event.preventDefault();
event.stopPropagation();
};
window.handleFileInput = (fileInput) => {
this.handleFileInput(fileInput);
};
}
init() {
// Proses file yang sudah ada
if (this.options.existingFiles && this.options.existingFiles.length > 0) {
this.processExistingFiles();
}
// Inisialisasi item pertama jika belum ada file
if (this.container.children.length === 0) {
this.addNewItem();
}
// Inisialisasi event listener untuk item yang sudah ada
this.container.querySelectorAll(".dynamic-item").forEach(item => {
this.attachEventListeners(item);
});
this.updateRemoveButtonVisibility();
}
addNewItem() {
const currentItemCount = this.container.children.length + 1;
const newItem = document.createElement("div");
newItem.classList.add("dynamic-item", "w-full", "mb-4");
newItem.innerHTML = this.generateItemHTML(currentItemCount);
this.container.appendChild(newItem);
if (currentItemCount > 1) {
this.attachEventListeners(newItem);
}
this.updateRemoveButtonVisibility();
return newItem;
}
generateItemHTML(itemCount) {
return `
<div class="flex w-full items-center justify-between">
${this.options.name ? `<label class="form-label">${this.options.name} ${itemCount}</label>` : ''}
<button type="button" class="btn btn-danger btn-sm btnRemoveLantai"
style="${itemCount === 1 ? 'display: none;' : ''}">
Hapus
</button>
</div>
<div class="dropzone w-full border-2 border-dashed border-gray-400 rounded-lg p-4 mt-2"
ondrop="handleDrop(event)" ondragover="allowDrop(event)">
<div class="preview-container grid grid-cols-2 md:grid-cols-4 gap-4"></div>
<input type="file"
name="${this.options.fileInputName}[${itemCount}][]"
class="file-input hidden"
multiple
accept="${this.options.accept}"
onchange="handleFileInput(this)"
data-lantai="${itemCount}">
<button type="button" class="btn btn-light btn-sm btnUploadFiles mt-2">
<i class="ki-outline ki-upload"></i> Unggah Gambar
</button>
</div>
`;
}
attachEventListeners(item) {
const uploadButton = item.querySelector('.btnUploadFiles');
const fileInput = item.querySelector('.file-input');
const previewContainer = item.querySelector('.preview-container');
if (!uploadButton.dataset.listenerAttached) {
uploadButton.addEventListener('click', () => {
fileInput.click();
});
uploadButton.dataset.listenerAttached = true;
}
const removeItemButton = item.querySelector('.btnRemoveLantai');
if (removeItemButton && !removeItemButton.dataset.listenerAttached) {
removeItemButton.addEventListener('click', () => {
this.removeItem(item);
});
removeItemButton.dataset.listenerAttached = true;
}
}
handleDrop(event, fileInput) {
event.preventDefault();
event.stopPropagation();
const files = event.dataTransfer.files;
const previewContainer = fileInput.closest('.dropzone').querySelector('.preview-container');
this.processFiles(files, fileInput, previewContainer);
}
handleFileInput(fileInput) {
if (!fileInput || !fileInput.files) return;
const files = fileInput.files;
const dropzone = fileInput.closest('.dropzone');
const previewContainer = dropzone.querySelector('.preview-container');
// Proses file
this.processFiles(files, fileInput, previewContainer);
}
processFiles(files, fileInput, previewContainer) {
const existingPreviews = previewContainer.querySelectorAll('.preview-item img');
const existingFiles = Array.from(existingPreviews).map(img => img.src);
const maxFiles = this.options.maxFiles;
const remainingSlots = maxFiles - existingPreviews.length;
const filesToAdd = Array.from(files).filter(file => {
const reader = new FileReader();
reader.onload = (e) => {
return !existingFiles.includes(e.target.result);
};
reader.readAsDataURL(file);
return true;
}).slice(0, remainingSlots);
if (filesToAdd.length === 0) {
alert(`Maksimal ${maxFiles} foto per lantai`);
return;
}
filesToAdd.forEach(file => {
const isValidType = this.options.accept === '*' || file.type.match(this.options.accept
.replace('*', '.*'));
if (isValidType) {
this.createFilePreview(file, previewContainer, fileInput);
} else {
alert(`File ${file.name} tidak valid. Hanya file gambar yang diperbolehkan.`);
}
});
}
createFilePreview(file, previewContainer, fileInput) {
const reader = new FileReader();
reader.onload = (e) => {
const imgWrapper = document.createElement('div');
imgWrapper.classList.add('preview-item', 'relative');
const img = document.createElement('img');
img.src = e.target.result;
img.classList.add('w-full', 'h-40', 'object-cover', 'rounded-lg');
const removeBtn = document.createElement('button');
removeBtn.type = 'button';
removeBtn.classList.add(
'absolute', 'top-2', 'right-2',
'btn', 'btn-sm', 'btn-danger', 'btn-icon',
'btnRemoveFoto'
);
removeBtn.innerHTML = '<i class="ki-solid ki-cross"></i>';
removeBtn.addEventListener('click', () => {
imgWrapper.remove();
this.updatePreviewContainerVisibility(previewContainer);
this.resetFileInput(fileInput);
});
imgWrapper.appendChild(img);
imgWrapper.appendChild(removeBtn);
previewContainer.appendChild(imgWrapper);
this.updatePreviewContainerVisibility(previewContainer);
};
reader.readAsDataURL(file);
}
updatePreviewContainerVisibility(previewContainer) {
const previewItems = previewContainer.querySelectorAll('.preview-item');
previewContainer.style.display = previewItems.length > 0 ? 'grid' : 'none';
}
resetFileInput(fileInput) {
fileInput.value = '';
}
removeItem(item) {
this.container.removeChild(item);
this.updateRemoveButtonVisibility();
}
updateRemoveButtonVisibility() {
const removeButtons = this.container.querySelectorAll('.btnRemoveLantai');
removeButtons.forEach((btn, index) => {
btn.style.display = index === 0 ? 'none' : 'block';
});
}
processExistingFiles() {
this.container.innerHTML = '';
const groupedFiles = this.groupFilesByItem(this.options.existingFiles);
Object.keys(groupedFiles).forEach((itemKey, index) => {
const itemCount = index + 1;
const newItem = document.createElement("div");
newItem.classList.add("dynamic-item", "w-full", "mb-4");
newItem.innerHTML = this.generateItemHTML(itemCount);
this.container.appendChild(newItem);
const previewContainer = newItem.querySelector(".preview-container");
const fileInput = newItem.querySelector(".file-input");
groupedFiles[itemKey].forEach(file => {
this.addExistingFilePreview(previewContainer, fileInput, file, itemCount);
});
// this.attachEventListeners(newItem);
});
this.updateRemoveButtonVisibility();
}
groupFilesByItem(files) {
return files.reduce((acc, file) => {
const itemKey = file.item || '1';
if (!acc[itemKey]) {
acc[itemKey] = [];
}
acc[itemKey].push(file);
return acc;
}, {});
}
addExistingFilePreview(previewContainer, fileInput, file, itemCount) {
const imgWrapper = document.createElement("div");
imgWrapper.classList.add("relative", "preview-item");
const img = document.createElement("img");
img.src = file.url || file.path;
img.classList.add("w-full", "h-auto", "object-cover", "rounded-lg");
const removeBtn = document.createElement("button");
removeBtn.type = "button";
removeBtn.classList.add("absolute", "top-2", "right-2", "btn", "btn-danger", "btn-sm");
removeBtn.innerHTML = '<i class="ki-outline ki-cross"></i>';
removeBtn.addEventListener("click", () => {
imgWrapper.remove();
this.updatePreviewContainerVisibility(previewContainer);
});
imgWrapper.appendChild(img);
imgWrapper.appendChild(removeBtn);
previewContainer.appendChild(imgWrapper);
this.updatePreviewContainerVisibility(previewContainer);
}
getAllUploadedFiles() {
const files = [];
this.container.querySelectorAll('.file-input').forEach(input => {
if (input.files.length > 0) {
files.push(...input.files);
}
});
return files;
}
}
</script>