perbaikan foto

This commit is contained in:
majid
2025-02-06 11:38:35 +07:00
parent 97ad08bc56
commit 8f2555c0a0
2 changed files with 129 additions and 53 deletions

View File

@@ -348,20 +348,23 @@ class SurveyorController extends Controller
? json_decode($inspeksi->foto_form, true) ? json_decode($inspeksi->foto_form, true)
: []; : [];
$formatFotojson = $existingData;
if (!$this->isValidFormat($existingData)) {
$existingData = [];
}
// Upload berbagai jenis foto // Upload berbagai jenis foto
$this->handleFileUploadBaru($request, 'rute_menuju_lokasi', $formatFotojson); $newFoto = $this->handleFileUpload($request, 'upload_foto', $existingData);
// Update record if (!empty($newFoto)) {
if (!empty($formatFotojson)) { $inspeksi->foto_form = json_encode($existingData);
$inspeksi->foto_form = json_encode($formatFotojson);
$inspeksi->save(); $inspeksi->save();
return response()->json([ return response()->json([
'success' => true, 'success' => true,
'message' => 'Data berhasil disimpan', 'message' => 'Data berhasil disimpan',
'data' => $formatFotojson 'file' => $newFoto
], 200); ], 200);
} }
@@ -374,6 +377,21 @@ class SurveyorController extends Controller
} }
} }
/**
* Validasi apakah format JSON sesuai dengan yang diinginkan.
*
* @param array $data
* @return bool
*/
private function isValidFormat($data)
{
if (!isset($data['upload_foto']) || !is_array($data['upload_foto'])) {
return false;
}
return true;
}
public function updateFoto(Request $request) public function updateFoto(Request $request)
{ {
@@ -399,14 +417,14 @@ class SurveyorController extends Controller
$fotoForm = json_decode($inspeksi->foto_form, true) ?? []; $fotoForm = json_decode($inspeksi->foto_form, true) ?? [];
if (!isset($fotoForm['rute_menuju_lokasi'])) { if (!isset($fotoForm['upload_foto'])) {
$fotoForm['rute_menuju_lokasi'] = []; $fotoForm['upload_foto'] = [];
} }
$existingIndex = null; $existingIndex = null;
if (!empty($validated['path'])) { if (!empty($validated['path'])) {
foreach ($fotoForm['rute_menuju_lokasi'] as $index => $foto) { foreach ($fotoForm['upload_foto'] as $index => $foto) {
if ($foto['path'] === $cleanRequestPath) { if ($foto['path'] === $cleanRequestPath) {
$existingIndex = $index; $existingIndex = $index;
break; break;
@@ -428,8 +446,8 @@ class SurveyorController extends Controller
]; ];
if ($existingIndex !== null) { if ($existingIndex !== null) {
$existingFoto = $fotoForm['rute_menuju_lokasi'][$existingIndex]; $existingFoto = $fotoForm['upload_foto'][$existingIndex];
$fotoForm['rute_menuju_lokasi'][$existingIndex] = [ $fotoForm['upload_foto'][$existingIndex] = [
'name' => $validated['name'], 'name' => $validated['name'],
'description' => $validated['description'], 'description' => $validated['description'],
'category' => $validated['category'], 'category' => $validated['category'],
@@ -441,7 +459,7 @@ class SurveyorController extends Controller
'updated_at' => now()->toDateTimeString(), 'updated_at' => now()->toDateTimeString(),
]; ];
} else { } else {
$fotoForm['rute_menuju_lokasi'][] = $newFotoData; $fotoForm['upload_foto'][] = $newFotoData;
} }
// Simpan kembali data ke database // Simpan kembali data ke database
@@ -462,7 +480,7 @@ class SurveyorController extends Controller
} }
private function handleFileUploadBaru(Request $request, $paramName, &$formatFotojson) private function handleFileUpload(Request $request, $paramName, &$formatFotojson)
{ {
if ($request->hasFile($paramName)) { if ($request->hasFile($paramName)) {
$files = $request->file($paramName); $files = $request->file($paramName);

View File

@@ -6,7 +6,7 @@
@section('content') @section('content')
<link rel="stylesheet" href="https://unpkg.com/dropzone@5/dist/min/dropzone.min.css" type="text/css" /> <link rel="stylesheet" href="https://unpkg.com/dropzone@5/dist/min/dropzone.min.css" type="text/css" />
<link rel="stylesheet" href="https://uicdn.toast.com/tui-image-editor/latest/tui-image-editor.css" /> {{-- <link rel="stylesheet" href="https://uicdn.toast.com/tui-image-editor/latest/tui-image-editor.css" /> --}}
<style> <style>
.dropzone { .dropzone {
border: 2px dashed #3498db; border: 2px dashed #3498db;
@@ -80,14 +80,11 @@
bottom: 10px; bottom: 10px;
/* Jarak dari bawah */ /* Jarak dari bawah */
left: 50%; left: 50%;
/* Pusatkan secara horizontal */
transform: translateX(-50%); transform: translateX(-50%);
display: flex; display: flex;
justify-content: center; justify-content: center;
gap: 10px; gap: 10px;
/* Jarak antar tombol */
z-index: 10; z-index: 10;
/* Pastikan tombol di atas elemen lain */
} }
.dropzone-buttons button { .dropzone-buttons button {
@@ -97,12 +94,11 @@
.dropzone-buttons button:hover { .dropzone-buttons button:hover {
opacity: 1; opacity: 1;
/* Tingkatkan opacity saat di-hover */
} }
.dz-preview { .dz-preview {
position: relative; position: relative;
/* Supaya tombol melayang relatif ke preview */
} }
</style> </style>
@@ -186,8 +182,8 @@
<h1 class="text-md font-medium text-gray-900">Upload Foto</h1> <h1 class="text-md font-medium text-gray-900">Upload Foto</h1>
</div> </div>
<div class="dropzone" id="rute-dropzone"> <div class="dropzone" id="upload-dropzone">
<div class="dz-message needsclick" data-foto-type="rute_menuju_lokasi"> <div class="dz-message needsclick" data-foto-type="upload_foto">
<i class="ki-duotone ki-file-up text-primary text-3xl"><span class="path1"></span><span <i class="ki-duotone ki-file-up text-primary text-3xl"><span class="path1"></span><span
class="path2"></span></i> class="path2"></span></i>
<div class="ms-4"> <div class="ms-4">
@@ -200,11 +196,6 @@
</div> </div>
</form> </form>
</div> </div>
{{-- <button type="button" class="btn btn-light" data-drawer-toggle="#drawer_2_2">
<i class="ki-outline ki-black-left">
</i>
End
</button> --}}
<div class="drawer drawer-end flex flex-col max-w-[90%] w-[300px]" data-drawer="true" id="drawer_2_2"> <div class="drawer drawer-end flex flex-col max-w-[90%] w-[300px]" data-drawer="true" id="drawer_2_2">
<div class="flex items-center justify-between p-5 border-b"> <div class="flex items-center justify-between p-5 border-b">
@@ -228,6 +219,7 @@
<label for="editDataDescription" class="block text-sm font-medium text-gray-700">Deskripsi</label> <label for="editDataDescription" class="block text-sm font-medium text-gray-700">Deskripsi</label>
<textarea id="editDataDescription" name="description" rows="3" <textarea id="editDataDescription" name="description" rows="3"
class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"></textarea> class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"></textarea>
<span class="text-xs text-danger"> * Kosongkan jika tidak ada</span>
</div> </div>
<div class="mb-4"> <div class="mb-4">
<label for="editDataCategory" class="block text-sm font-medium text-gray-700">Kategori</label> <label for="editDataCategory" class="block text-sm font-medium text-gray-700">Kategori</label>
@@ -235,15 +227,15 @@
</div> </div>
<div class="mb-4"> <div class="mb-4">
<label for="editDataCategory" class="block text-sm font-medium text-gray-700">Sub Kategori</label> <label for="editDataCategory" class="block text-sm font-medium text-gray-700">Sub Kategori</label>
<span class="text-xs text-danger">Jika tidak ada kosongkan</span>
<input id="editDataSub" name="sub" type="text" class="input" <input id="editDataSub" name="sub" type="text" class="input"
placeholder="Masukkan sub kategori" /> placeholder="Masukkan sub kategori" />
<span class="text-xs text-danger"> * Kosongkan jika tidak ada</span>
</div> </div>
<div class="flex gap-2.5"> <div class="flex gap-2.5">
<button id="saveEditDataButton" type="button" class="btn btn-primary" <button id="saveEditDataButton" type="button" class="btn btn-primary"
onclick="saveEditedFoto()">Simpan</button> onclick="saveEditedFoto()">Simpan</button>
<button type="button" class="btn btn-light" data-modal-toggle="#modal_10" {{-- <button type="button" class="btn btn-light" data-modal-toggle="#modal_10"
data-drawer-dismiss="true" onclick="openEditPhotoModal(file)">Edit Foto</button> data-drawer-dismiss="true" onclick="openEditPhotoModal(file)">Edit Foto</button> --}}
<button type="button" class="btn btn-danger" data-drawer-dismiss="true">Batal</button> <button type="button" class="btn btn-danger" data-drawer-dismiss="true">Batal</button>
</div> </div>
</form> </form>
@@ -274,13 +266,14 @@
@include('lpj::surveyor.js.fotojs') @include('lpj::surveyor.js.fotojs')
@include('lpj::surveyor.js.utils') @include('lpj::surveyor.js.utils')
@push('scripts') @push('scripts')
<script src="https://uicdn.toast.com/tui-image-editor/latest/tui-image-editor.js"></script> {{-- <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://unpkg.com/dropzone@5/dist/min/dropzone.min.js"></script>
<script> <script>
// console.log('@json($formFoto)');
let jsonDataContoh = @json($formFoto); let jsonDataContoh = @json($formFoto);
Dropzone.autoDiscover = false; Dropzone.autoDiscover = false;
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
let myDropzone = null;
function initDropzone(selector, paramName) { function initDropzone(selector, paramName) {
try { try {
// Pastikan elemen ada sebelum membuat Dropzone // Pastikan elemen ada sebelum membuat Dropzone
@@ -290,7 +283,7 @@
return null; return null;
} }
return new Dropzone(selector, { myDropzone = new Dropzone(selector, {
url: "{{ route('surveyor.storeFoto') }}", url: "{{ route('surveyor.storeFoto') }}",
paramName: paramName, paramName: paramName,
maxFilesize: 10, maxFilesize: 10,
@@ -298,9 +291,7 @@
uploadMultiple: false, uploadMultiple: false,
parallelUploads: 1, parallelUploads: 1,
maxFiles: 10, maxFiles: 10,
// addRemoveLinks: true,
autoProcessQueue: true, autoProcessQueue: true,
// dictRemoveFile: 'Hapus',
dictDefaultMessage: 'Seret foto atau klik untuk unggah', dictDefaultMessage: 'Seret foto atau klik untuk unggah',
headers: { headers: {
@@ -313,9 +304,7 @@
param_name: paramName, param_name: paramName,
nomor_registrasi: '{{ $permohonan->nomor_registrasi ?? '' }}', nomor_registrasi: '{{ $permohonan->nomor_registrasi ?? '' }}',
}, },
error: function(file, response) { error: function(file, response) {
console.error('Upload error:', response);
Swal.fire({ Swal.fire({
icon: 'error', icon: 'error',
title: 'Upload Gagal', title: 'Upload Gagal',
@@ -333,20 +322,30 @@
showConfirmButton: false, showConfirmButton: false,
timer: 1500 timer: 1500
}); });
addEditAndDeleteButtons(file, response); var mockFile = {
name: file.name,
size: file.size || 12345,
originalPath: file.path
};
myDropzone.emit("addedfile", mockFile);
myDropzone.emit("thumbnail", mockFile, response.file.path);
myDropzone.emit("complete", mockFile);
addEditAndDeleteButtons(mockFile, {
path: response.file.path,
name: response.file.name,
description: response.file.description || '',
category: response.file.category || 'lainnya',
sub: response.file.sub || '',
param_name: paramName
});
} }
}, },
init: function() { init: function() {
// var myDropzone = this;
// this.on("success", function(file, response) {
// addEditAndDeleteButtons(file, response);
// });
var myDropzone = this;
var loadingIndicator = $(` var loadingIndicator = $(`
<div class="loading-overlay" style=" <div class="loading-overlay" style="
position: absolute; position: absolute;
@@ -380,7 +379,6 @@
'X-CSRF-TOKEN': '{{ csrf_token() }}' 'X-CSRF-TOKEN': '{{ csrf_token() }}'
}, },
beforeSend: function() { beforeSend: function() {
// Pastikan loading indicator terlihat
loadingIndicator.show(); loadingIndicator.show();
}, },
success: function(response) { success: function(response) {
@@ -403,31 +401,89 @@
.description || '', .description || '',
category: foto.category || category: foto.category ||
'lainnya', 'lainnya',
sub: foto.sub || '',
param_name: paramName param_name: paramName
}); });
}); });
} else {
// Tambahkan pesan jika tidak ada foto
console.log('Tidak ada foto yang ditemukan');
} }
}, },
error: function(xhr, status, error) { error: function(xhr, status, error) {
console.error('Gagal memuat foto:', error); console.error('Gagal memuat foto:', error);
}, },
complete: function() { complete: function() {
// Sembunyikan loading indicator
loadingIndicator.hide(); loadingIndicator.hide();
} }
}); });
} }
}); });
return myDropzone;
} catch (error) { } catch (error) {
console.error('Dropzone initialization error:', error); console.error('Dropzone initialization error:', error);
return null; return null;
} }
} }
function updatePhotoGallery() {
const gallery = document.querySelector('#upload-dropzone');
gallery.innerHTML = '';
if (!myDropzone) {
console.error('Dropzone is not initialized');
return;
}
$.ajax({
url: "{{ route('surveyor.getFoto') }}",
method: 'GET',
data: {
permohonan_id: {{ $permohonan->id ?? 0 }},
dokument_id: '{{ request('dokument') ?? '' }}',
param_name: 'upload_foto'
},
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}'
},
success: function(response) {
if (response.fotos && response.fotos.length) {
response.fotos.forEach(function(foto) {
// Cek jika foto sudah ada di Dropzone
if (!isFileInDropzone(foto.name)) {
var mockFile = {
name: foto.name,
size: foto.size || 12345,
originalPath: foto.path
};
myDropzone.emit("addedfile", mockFile);
myDropzone.emit("thumbnail", mockFile, foto.path);
myDropzone.emit("complete", mockFile);
addEditAndDeleteButtons(mockFile, {
path: foto.path,
name: foto.name,
description: foto.description || '',
category: foto.category || 'lainnya',
sub: foto.sub || '',
param_name: 'upload_foto'
});
}
});
} else {
console.log('Tidak ada foto yang ditemukan');
}
},
error: function(xhr, status, error) {
console.error('Gagal memuat foto:', error);
}
});
}
function isFileInDropzone(fileName) {
let files = myDropzone.files;
return files.some(file => file.name === fileName);
}
// Inisialisasi Dropzone untuk elemen awal dengan pengecekan // Inisialisasi Dropzone untuk elemen awal dengan pengecekan
function safeInitDropzone(selector, paramName) { function safeInitDropzone(selector, paramName) {
setTimeout(() => { setTimeout(() => {
@@ -439,7 +495,7 @@
} }
// Inisialisasi dropzone untuk elemen awal // Inisialisasi dropzone untuk elemen awal
safeInitDropzone('#rute-dropzone', 'rute_menuju_lokasi'); safeInitDropzone('#upload-dropzone', 'upload_foto');
// Event listener untuk menambah lantai // Event listener untuk menambah lantai
@@ -454,6 +510,7 @@
document.getElementById('editDataFilePath').value = response.path || ''; document.getElementById('editDataFilePath').value = response.path || '';
document.getElementById('editDataName').value = response.name || ''; document.getElementById('editDataName').value = response.name || '';
document.getElementById('editDataDescription').value = response.description || ''; document.getElementById('editDataDescription').value = response.description || '';
document.getElementById('editDataSub').value = response.sub || '';
// Ambil elemen select kategori // Ambil elemen select kategori
const selectElement = document.getElementById('editDataCategory'); const selectElement = document.getElementById('editDataCategory');
@@ -545,7 +602,7 @@
// Tombol Hapus // Tombol Hapus
const deleteButton = document.createElement('button'); const deleteButton = document.createElement('button');
deleteButton.innerHTML = '<i class="ki-filled ki-trash"></i> Hapus'; deleteButton.innerHTML = '<i class="ki-filled ki-trash"></i> Delete';
deleteButton.className = 'btn btn-sm btn-danger'; deleteButton.className = 'btn btn-sm btn-danger';
deleteButton.style.cursor = 'pointer'; deleteButton.style.cursor = 'pointer';
deleteButton.type = "button"; deleteButton.type = "button";
@@ -596,6 +653,7 @@
} }
async function saveEditedFoto() { async function saveEditedFoto() {
$.ajax({ $.ajax({
url: `{{ route('surveyor.updateFoto') }}`, url: `{{ route('surveyor.updateFoto') }}`,