fix(so/penilai) : perbaikkan paparan dan resume

This commit is contained in:
majid
2025-02-27 10:18:31 +07:00
parent 6102205900
commit 2a475a9ea7
18 changed files with 960 additions and 888 deletions

View File

@@ -234,8 +234,8 @@
<div class="flex gap-2.5">
<button id="saveEditDataButton" type="button" class="btn btn-primary"
onclick="saveEditedFoto()">Simpan</button>
{{-- <button type="button" class="btn btn-light" data-modal-toggle="#modal_10"
data-drawer-dismiss="true" onclick="openEditPhotoModal(file)">Edit Foto</button> --}}
<button type="button" class="btn btn-light" data-modal-toggle="#modal_10"
data-drawer-dismiss="true">Edit Foto</button>
<button type="button" class="btn btn-danger" data-drawer-dismiss="true">Batal</button>
</div>
</form>
@@ -244,7 +244,7 @@
<div class="modal" data-modal="true" id="modal_10">
<div class="modal-content modal-overlay">
<div class="modal-header">
{{-- <div class="modal-header">
<h3 class="modal-title">
Edit Foto
</h3>
@@ -252,9 +252,9 @@
<i class="ki-outline ki-cross">
</i>
</button>
</div>
</div> --}}
<div class="modal-body scrollable-y-auto">
<div id="tui-image-editor"></div>
<div id="editor_container" class="w-full h-full"></div>
</div>
</div>
</div>
@@ -266,224 +266,225 @@
@include('lpj::surveyor.js.fotojs')
@include('lpj::surveyor.js.utils')
@push('scripts')
{{-- <script src="https://uicdn.toast.com/tui-image-editor/latest/tui-image-editor.js"></script> --}}
<script src="https://unpkg.com/dropzone@5/dist/min/dropzone.min.js"></script>
<script src="https://scaleflex.cloudimg.io/v7/plugins/filerobot-image-editor/latest/filerobot-image-editor.min.js">
</script>
<script>
let jsonDataContoh = @json($formFoto);
Dropzone.autoDiscover = false;
document.addEventListener('DOMContentLoaded', function() {
let myDropzone = null;
let uploadQueue = 0;
let uploadBatch = [];
document.addEventListener('DOMContentLoaded', function() {
let myDropzone = null;
let uploadQueue = 0;
let uploadBatch = [];
function initDropzone(selector, paramName) {
try {
const dropzoneElement = document.querySelector(selector);
if (!dropzoneElement) {
console.error(`Dropzone element not found: ${selector}`);
return null;
}
const processedFiles = new Set();
// Track files that are already on the server
const existingFiles = new Set();
myDropzone = new Dropzone(selector, {
url: "{{ route('surveyor.storeFoto') }}",
paramName: paramName,
acceptedFiles: 'image/*',
uploadMultiple: false,
parallelUploads: 1,
autoProcessQueue: true,
dictDefaultMessage: 'Seret foto atau klik untuk unggah',
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}'
},
params: {
permohonan_id: {{ $permohonan->id ?? 0 }},
dokument_id: '{{ request('dokument') ?? '' }}',
param_name: paramName,
nomor_registrasi: '{{ $permohonan->nomor_registrasi ?? '' }}',
},
accept: function(file, done) {
// Generate a unique identifier for the file - use hash or content-based ID if possible
const fileId = file.name + '_' + file.size;
// If file is already being processed, reject it
if (processedFiles.has(fileId)) {
done('File sudah dalam antrian upload.');
return;
function initDropzone(selector, paramName) {
try {
const dropzoneElement = document.querySelector(selector);
if (!dropzoneElement) {
console.error(`Dropzone element not found: ${selector}`);
return null;
}
const processedFiles = new Set();
// Check if file already exists on server
if (existingFiles.has(file.name)) {
done('File dengan nama ini sudah ada.');
return;
}
// Track files that are already on the server
const existingFiles = new Set();
// Add file to processed set
processedFiles.add(fileId);
done();
},
myDropzone = new Dropzone(selector, {
url: "{{ route('surveyor.storeFoto') }}",
paramName: paramName,
acceptedFiles: 'image/*',
uploadMultiple: false,
parallelUploads: 1,
autoProcessQueue: true,
dictDefaultMessage: 'Seret foto atau klik untuk unggah',
addedfiles: function(files) {
const validFiles = Array.from(files).filter(file => {
// Only count files that haven't been rejected
return !file.rejected;
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}'
},
params: {
permohonan_id: {{ $permohonan->id ?? 0 }},
dokument_id: '{{ request('dokument') ?? '' }}',
param_name: paramName,
nomor_registrasi: '{{ $permohonan->nomor_registrasi ?? '' }}',
},
accept: function(file, done) {
// Generate a unique identifier for the file - use hash or content-based ID if possible
const fileId = file.name + '_' + file.size;
// If file is already being processed, reject it
if (processedFiles.has(fileId)) {
done('File sudah dalam antrian upload.');
return;
}
// Check if file already exists on server
if (existingFiles.has(file.name)) {
done('File dengan nama ini sudah ada.');
return;
}
// Add file to processed set
processedFiles.add(fileId);
done();
},
addedfiles: function(files) {
const validFiles = Array.from(files).filter(file => {
// Only count files that haven't been rejected
return !file.rejected;
});
uploadQueue += validFiles.length;
uploadBatch = validFiles;
if (validFiles.length > 0) showLoadingOverlay();
},
error: function(file, response) {
// Remove file from processed list on error
const fileId = file.name + '_' + file.size;
processedFiles.delete(fileId);
// Format error message
let errorMsg = typeof response === 'string' ? response :
(response.message || 'Gagal mengupload file');
handleUploadComplete(file, false, errorMsg);
},
success: function(file, response) {
if (response.success) {
const fileData = {
path: response.path || file.path,
name: file.name,
description: '',
category: 'lainnya',
sub: '',
param_name: paramName
};
// Add file to existing files set to prevent duplicates
existingFiles.add(file.name);
addEditAndDeleteButtons(file, fileData);
handleUploadComplete(file, true);
} else {
handleUploadComplete(file, false, response.message);
}
},
init: function() {
const dz = this;
// Clear processed files when all uploads complete
this.on("queuecomplete", function() {
processedFiles.clear();
});
// Load existing photos
loadExistingPhotos(this, paramName, existingFiles);
}
});
uploadQueue += validFiles.length;
uploadBatch = validFiles;
return myDropzone;
} catch (error) {
console.error('Dropzone initialization error:', error);
return null;
}
}
if (validFiles.length > 0) showLoadingOverlay();
},
function loadExistingPhotos(dropzone, paramName, existingFilesSet) {
showLoadingOverlay();
error: function(file, response) {
// Remove file from processed list on error
const fileId = file.name + '_' + file.size;
processedFiles.delete(fileId);
$.ajax({
url: "{{ route('surveyor.getFoto') }}",
method: 'GET',
data: {
permohonan_id: {{ $permohonan->id ?? 0 }},
dokument_id: '{{ request('dokument') ?? '' }}',
param_name: paramName
},
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}'
},
success: function(response) {
if (response.fotos && response.fotos.length) {
response.fotos.forEach(function(foto) {
var mockFile = {
name: foto.name,
size: foto.size || 12345,
originalPath: foto.path
};
// Format error message
let errorMsg = typeof response === 'string' ? response :
(response.message || 'Gagal mengupload file');
// Add to existing files set to prevent duplicates
existingFilesSet.add(foto.name);
handleUploadComplete(file, false, errorMsg);
},
dropzone.emit("addedfile", mockFile);
dropzone.emit("thumbnail", mockFile, foto.path);
dropzone.emit("complete", mockFile);
addEditAndDeleteButtons(mockFile, {
path: foto.path,
name: foto.name,
description: foto.description || '',
category: foto.category || 'lainnya',
sub: foto.sub || '',
param_name: paramName
});
});
}
},
error: function(xhr, status, error) {
console.error('Gagal memuat foto:', error);
showErrorMessage('Gagal memuat foto yang ada');
},
complete: function() {
hideLoadingOverlay();
}
});
}
success: function(file, response) {
if (response.success) {
const fileData = {
path: response.path || file.path,
name: file.name,
description: '',
category: 'lainnya',
sub: '',
param_name: paramName
};
function handleUploadComplete(file, isSuccess, errorMessage = null) {
uploadQueue--;
const index = uploadBatch.indexOf(file);
if (index > -1) {
uploadBatch.splice(index, 1);
}
// Add file to existing files set to prevent duplicates
existingFiles.add(file.name);
// Show individual error if any
if (!isSuccess && errorMessage) {
showErrorMessage(errorMessage);
}
addEditAndDeleteButtons(file, fileData);
handleUploadComplete(file, true);
// If all uploads are complete
if (uploadQueue === 0) {
hideLoadingOverlay();
// Show final status message
const totalFiles = uploadBatch.length + 1; // +1 for current file
if (totalFiles === 1) {
// Single file upload
if (isSuccess) {
showSuccessMessage('Foto berhasil diupload');
}
} else {
handleUploadComplete(file, false, response.message);
// Multiple files upload
showSuccessMessage(`${totalFiles} foto berhasil diupload`);
}
},
init: function() {
const dz = this;
// Clear processed files when all uploads complete
this.on("queuecomplete", function() {
processedFiles.clear();
});
// Load existing photos
loadExistingPhotos(this, paramName, existingFiles);
// Reset batch
uploadBatch = [];
}
});
return myDropzone;
} catch (error) {
console.error('Dropzone initialization error:', error);
return null;
}
}
function loadExistingPhotos(dropzone, paramName, existingFilesSet) {
showLoadingOverlay();
$.ajax({
url: "{{ route('surveyor.getFoto') }}",
method: 'GET',
data: {
permohonan_id: {{ $permohonan->id ?? 0 }},
dokument_id: '{{ request('dokument') ?? '' }}',
param_name: paramName
},
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}'
},
success: function(response) {
if (response.fotos && response.fotos.length) {
response.fotos.forEach(function(foto) {
var mockFile = {
name: foto.name,
size: foto.size || 12345,
originalPath: foto.path
};
// Add to existing files set to prevent duplicates
existingFilesSet.add(foto.name);
dropzone.emit("addedfile", mockFile);
dropzone.emit("thumbnail", mockFile, foto.path);
dropzone.emit("complete", mockFile);
addEditAndDeleteButtons(mockFile, {
path: foto.path,
name: foto.name,
description: foto.description || '',
category: foto.category || 'lainnya',
sub: foto.sub || '',
param_name: paramName
});
});
}
},
error: function(xhr, status, error) {
console.error('Gagal memuat foto:', error);
showErrorMessage('Gagal memuat foto yang ada');
},
complete: function() {
hideLoadingOverlay();
}
});
}
function handleUploadComplete(file, isSuccess, errorMessage = null) {
uploadQueue--;
const index = uploadBatch.indexOf(file);
if (index > -1) {
uploadBatch.splice(index, 1);
}
// Show individual error if any
if (!isSuccess && errorMessage) {
showErrorMessage(errorMessage);
}
// If all uploads are complete
if (uploadQueue === 0) {
hideLoadingOverlay();
// Show final status message
const totalFiles = uploadBatch.length + 1; // +1 for current file
if (totalFiles === 1) {
// Single file upload
if (isSuccess) {
showSuccessMessage('Foto berhasil diupload');
}
} else {
// Multiple files upload
showSuccessMessage(`${totalFiles} foto berhasil diupload`);
}
// Reset batch
uploadBatch = [];
}
}
function showLoadingOverlay() {
const overlay = document.querySelector('.loading-overlay');
if (!overlay) {
// Buat elemen overlay
const loadingOverlay = document.createElement('div');
loadingOverlay.className = 'loading-overlay';
loadingOverlay.style.cssText = `
function showLoadingOverlay() {
const overlay = document.querySelector('.loading-overlay');
if (!overlay) {
// Buat elemen overlay
const loadingOverlay = document.createElement('div');
loadingOverlay.className = 'loading-overlay';
loadingOverlay.style.cssText = `
position: fixed;
top: 0;
left: 0;
@@ -496,54 +497,54 @@ document.addEventListener('DOMContentLoaded', function() {
z-index: 9999;
`;
// Tambahkan loader di dalam overlay
loadingOverlay.innerHTML = '<div class="loader"></div>';
// Tambahkan loader di dalam overlay
loadingOverlay.innerHTML = '<div class="loader"></div>';
// Tambahkan overlay ke dalam <body>
document.body.appendChild(loadingOverlay);
} else {
// Tampilkan overlay jika sudah ada
overlay.style.display = 'flex';
}
}
function hideLoadingOverlay() {
const overlay = document.querySelector('.loading-overlay');
if (overlay) overlay.style.display = 'none';
}
function showSuccessMessage(message) {
Swal.fire({
icon: 'success',
title: message,
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 1500
});
}
function showErrorMessage(message) {
Swal.fire({
icon: 'error',
title: 'Upload Gagal',
text: message || 'Error tidak diketahui'
});
}
// Inisialisasi Dropzone untuk elemen awal dengan pengecekan
function safeInitDropzone(selector, paramName) {
setTimeout(() => {
const dropzone = initDropzone(selector, paramName);
if (!dropzone) {
console.error(`Failed to initialize Dropzone for ${selector}`);
// Tambahkan overlay ke dalam <body>
document.body.appendChild(loadingOverlay);
} else {
// Tampilkan overlay jika sudah ada
overlay.style.display = 'flex';
}
}
}, 100);
}
// Inisialisasi dropzone untuk elemen awal
safeInitDropzone('#upload-dropzone', 'upload_foto');
});
function hideLoadingOverlay() {
const overlay = document.querySelector('.loading-overlay');
if (overlay) overlay.style.display = 'none';
}
function showSuccessMessage(message) {
Swal.fire({
icon: 'success',
title: message,
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 1500
});
}
function showErrorMessage(message) {
Swal.fire({
icon: 'error',
title: 'Upload Gagal',
text: message || 'Error tidak diketahui'
});
}
// Inisialisasi Dropzone untuk elemen awal dengan pengecekan
function safeInitDropzone(selector, paramName) {
setTimeout(() => {
const dropzone = initDropzone(selector, paramName);
if (!dropzone) {
console.error(`Failed to initialize Dropzone for ${selector}`);
}
}, 100);
}
// Inisialisasi dropzone untuk elemen awal
safeInitDropzone('#upload-dropzone', 'upload_foto');
});
let fotoObjekJaminan = @json($fotoObjekJaminan);
@@ -589,35 +590,109 @@ document.addEventListener('DOMContentLoaded', function() {
}
}
document.addEventListener('DOMContentLoaded', function() {
// Create container for Filerobot editor
const editorContainer = document.createElement('div');
editorContainer.id = 'editor_container';
editorContainer.style.width = '100%';
editorContainer.style.height = '100%';
function openEditPhotoModal() {
const imageEditorContainer = document.getElementById('tui-image-editor');
// Add container to modal body
const modalBody = document.querySelector('#modal_10 .modal-body');
modalBody.innerHTML = '';
modalBody.appendChild(editorContainer);
// Inisialisasi TUI Image Editor
const imageEditor = new tui.ImageEditor(imageEditorContainer, {
includeUI: {
loadImage: {
path: file.dataURL,
name: 'Uploaded Photo'
},
theme: {
'common.bi.image': '',
'common.bisize.width': '25px',
'common.bisize.height': '25px',
'common.backgroundImage': 'none',
'common.backgroundColor': '#fff',
'common.border': '1px solid #ccc'
},
menu: ['crop', 'flip', 'rotate', 'draw', 'shape', 'icon', 'text', 'filter'],
initMenu: 'filter'
// Update the Edit Foto button event handler
const editFotoButton = document.querySelector('[data-modal-toggle="#modal_10"]');
if (editFotoButton) {
editFotoButton.addEventListener('click', function(e) {
e.preventDefault();
// Get the file path from hidden input
const filePath = document.getElementById('editDataFilePath').value;
if (filePath) {
openFilerobotEditor(filePath);
} else {
alert('Tidak ada foto untuk diedit');
}
});
}
});
function openFilerobotEditor(imagePath) {
// Get the editor container
const editorContainer = document.getElementById('editor_container');
if (!editorContainer) {
console.error('Editor container not found');
return;
}
// Configuration for the editor
const config = {
source: imagePath || '',
onSave: (editedImageObject, designState) => {
console.log('Image saved', editedImageObject);
// Save the edited image
saveEditedImage(editedImageObject, document.getElementById('editDataFilePath').value);
// Close the editor
FilerobotImageEditor.terminate();
// Hide the modal
document.getElementById('modal_10').setAttribute('data-modal-dismiss', 'true');
// Update the preview if needed
updateImagePreview(editedImageObject.imageBase64 || editedImageObject.imageCanvas.toDataURL());
},
cssMaxWidth: 700,
cssMaxHeight: 500
annotationsCommon: {
fill: '#ff0000'
},
Text: {
text: 'Tambahkan teks...'
},
Rotate: {
angle: 90,
componentType: 'slider'
},
tabsIds: [
window.FilerobotImageEditor.TABS.ADJUST,
window.FilerobotImageEditor.TABS.FILTERS,
window.FilerobotImageEditor.TABS.FINETUNE,
window.FilerobotImageEditor.TABS.ANNOTATE,
window.FilerobotImageEditor.TABS.WATERMARK,
window.FilerobotImageEditor.TABS.RESIZE,
],
defaultTabId: window.FilerobotImageEditor.TABS.ADJUST,
Language: {
Save: 'Simpan',
Cancel: 'Batal',
Reset: 'Reset',
Edit: 'Edit',
Delete: 'Hapus'
}
};
// Initialize the Filerobot Image Editor
const filerobotImageEditor = new FilerobotImageEditor(
editorContainer,
config
);
// Render the editor
filerobotImageEditor.render({
onClose: (closingReason) => {
console.log('Editor closed:', closingReason);
filerobotImageEditor.terminate();
// Hide the modal
document.querySelector('#modal_10').setAttribute('data-modal-dismiss', 'true');
}
});
// openModal('editPhotoModal');
}
window.addEditAndDeleteButtons = function(file, response) {
const filePreviewElement = file.previewElement;
@@ -694,8 +769,6 @@ document.addEventListener('DOMContentLoaded', function() {
filePreviewElement.appendChild(buttonContainer);
}
async function saveEditedFoto() {
$.ajax({
url: `{{ route('surveyor.updateFoto') }}`,
@@ -736,6 +809,56 @@ document.addEventListener('DOMContentLoaded', function() {
}
});
}
function saveEditedImage(editedImageObject, originalFilePath) {
// Get the image data (base64 or canvas)
const imageData = editedImageObject.imageBase64 ||
(editedImageObject.imageCanvas ? editedImageObject.imageCanvas.toDataURL() : null);
if (!imageData) {
Swal.fire({
icon: 'error',
title: 'Gagal Menyimpan',
text: 'Tidak ada data gambar untuk disimpan',
});
return;
}
const formData = new FormData();
formData.append('edited_image', imageData);
formData.append('original_path', originalFilePath);
formData.forEach((value, key) => {
console.log(`${key}:`, value);
});
fetch('/api/save-edited-image', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
Swal.fire({
icon: 'success',
title: 'Perubahan Disimpan',
text: response.message,
confirmButtonText: 'OK'
}).then((response) => {
if (response.isConfirmed) {
window.location.reload();
}
});;
})
.catch(error => {
const errorMessage = xhr.responseJSON?.message || 'Terjadi kesalahan';
Swal.fire({
icon: 'error',
title: 'Gagal Menyimpan',
text: errorMessage,
});
});
}
</script>
@include('lpj::surveyor.js.camera-editor')
@endpush