Files
lpj/resources/views/surveyor/components/foto.blade.php

1087 lines
53 KiB
PHP

@extends('layouts.main')
@section('breadcrumbs')
{{ Breadcrumbs::render(request()->route()->getName()) }}
@endsection
@section('content')
<link rel="stylesheet" href="https://unpkg.com/dropzone@5/dist/min/dropzone.min.css" type="text/css" />
<style>
.dropzone {
border: 2px dashed #3498db;
border-radius: 10px;
background: #f9f9f9;
min-height: 200px;
}
.dropzone .dz-message {
text-align: center;
margin: 50px 0;
}
.dropzone .dz-preview {
margin: 10px;
width: 17rem;
height: 17rem;
}
.dropzone .dz-preview .dz-image {
width: 100%;
height: 100%;
border-radius: 8px;
overflow: hidden;
position: static;
}
.dropzone .dz-preview .dz-image img {
width: 100%;
height: 100%;
object-fit: cover;
}
.dropzone .dz-preview .dz-details {
font-size: 10px;
}
/* HTML: <div class="loader"></div> */
.loader {
width: 60px;
aspect-ratio: 2;
--_g: no-repeat radial-gradient(circle closest-side, #35C1D0 90%, #0000);
background:
var(--_g) 0% 50%,
var(--_g) 50% 50%,
var(--_g) 100% 50%;
background-size: calc(100%/3) 50%;
animation: l3 1s infinite linear;
}
@keyframes l3 {
20% {
background-position: 0% 0%, 50% 50%, 100% 50%
}
40% {
background-position: 0% 100%, 50% 0%, 100% 50%
}
60% {
background-position: 0% 50%, 50% 100%, 100% 0%
}
80% {
background-position: 0% 50%, 50% 50%, 100% 100%
}
}
</style>
<div class="w-full grid gap-5 lg:gap-7.5 mx-auto">
<div class="card border border-agi-100 min-w-full">
<div class="card border border-agi-100 min-w-full">
<div class="card-header bg-agi-50">
<h3 class="card-title">
Data Jaminan
</h3>
<div class="flex items-center gap-2">
<a href="{{ route('surveyor.show', ['id' => $permohonan->id]) }}" class="btn btn-xs btn-info">
<i class="ki-filled ki-exit-left"></i> Back
</a>
</div>
</div>
<div class="card-body grid gap-5 grid-cols-2">
<div class="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
<label class="form-label max-w-56">Nama Debitur</label>
<div class="flex flex-wrap items-baseline w-full">
@if (isset($permohonan->debiture))
<p class="text-2sm text-gray-700">{{ $permohonan->debiture->name }}</p>
@endif
</div>
</div>
<div class="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
<label class="form-label max-w-56">Alamat Object</label>
<div class="flex flex-wrap items-baseline w-full">
@foreach ($permohonan->debiture->documents as $dokumen)
<span class="text-2sm text-gray-700">
{{ formatAlamat($dokumen->pemilik) }}
</span>
@endforeach
</div>
</div>
<div class="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
<label class="form-label max-w-56">Nomor Registrasi</label>
<div class="flex flex-wrap items-base line w-full">
<p class="text-2sm text-gray-700">{{ $permohonan->nomor_registrasi }}</p>
</div>
</div>
<div class="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
<label class="form-label max-w-56">Cab/Direktorat</label>
<div class="flex flex-wrap items-baseline w-full">
@if (isset($permohonan->branch))
<p class="text-2sm text-gray-700">{{ $permohonan->branch->name }}</p>
@endif
</div>
</div>
<div class="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
<label class="form-label max-w-56">Nomor Laporan</label>
<div class="flex flex-wrap items-base line w-full">
<p class="text-2sm text-gray-700">{{ $permohonan->nomor_registrasi }}</p>
</div>
</div>
<div class="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
<label class="form-label max-w-56">AO</label>
<div class="flex flex-wrap items-baseline w-full">
@if (isset($permohonan->user))
<p class="text-2sm text-gray-700">{{ $permohonan->user->name }}</p>
@endif
</div>
</div>
</div>
</div>
</div>
<form id="formFoto" method="POST" class="grid gap-5" enctype="multipart/form-data">
<input type="hidden" name="permohonan_id" value="{{ $permohonan->id }}">
<input type="hidden" name="dokument_id" value="{{ request('dokument') }}">
<input type="hidden" name="nomor_registrasi" value="{{ $permohonan->nomor_registrasi }}">
<div class="card border border-agi-100 bg-white rounded-lg shadow-md">
<div class="card-body">
<div class=" py-4 flex items-center justify-between">
<h1 class="text-md font-medium text-gray-900">Rute Menuju Lokasi</h1>
</div>
<div class="dropzone" id="rute-dropzone">
<div class="dz-message" data-foto-type="rute_menuju_lokasi">
<span>Seret dan lepas file di sini atau klik untuk unggah</span>
</div>
</div>
<div id="inputContainerGerbang" style="margin-top: 10px">
<div class="flex items-baseline flex-wrap lg:flex-nowrap w-full gap-4 mb-4">
<label class="form-label max-w-56">
<span class="form-label">Foto Gerbang & Nama Perumahan</span>
</label>
<div class="input-group w-full flex flex-col gap-2">
<input class="name_gerbang" type="hidden" name="name_gerbang" value="gerbang">
<img id="foto_gerbang-preview"
src="{{ isset($formFoto['foto_gerbang']) ? asset('storage/' . $formFoto['foto_gerbang']) : '' }}"
alt="Foto Gerbong" class="mt-2 max-w-full h-auto"
style="{{ isset($formFoto['foto_gerbang']) ? '' : 'display: none;' }} width: 30rem;">
<div class="input-group w-full flex gap-2">
<input id="inputRute" type="file" name="foto_gerbang"
class="file-input file-input-bordered w-full"
accept=".jpg,.jpeg,.png,.gif,.bmp,.tiff,.tif,.webp,.svg"
onchange="previewImage(this, 'foto_gerbang-preview')">
<button type="button" id="btnCamera" class="btn btn-light"
data-modal-toggle="#cameraModal">
<i class="ki-outline ki-abstract-33"></i> Camera
</button>
</div>
</div>
</div>
<span class="alert text-danger text-sm"></span>
</div>
<div id="ruteLainnya" style="margin-top: 10px">
@if (isset($formFoto['foto_rute_lainnya']) && is_array($formFoto['foto_rute_lainnya']))
@foreach ($formFoto['foto_rute_lainnya'] as $index => $photo)
<div class="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5 mb-5" id="photoContainer">
<label class="form-label max-w-56">
Masukkan nama rute lainnya {{ $index + 1 }}
</label>
<div class="flex flex-wrap items-baseline w-full gap-4">
<img id="foto_rute_lainnya-preview-{{ $index }}"
src="{{ asset('storage/' . $photo['foto_rute_lainnya']) }}" alt="Foto Rute "
class="mt-2 max-w-full h-auto" style="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_rute_lainnya[]"
value="{{ $photo['name_rute_lainnya'] }}">
</div>
<div class="input-group w-full flex flex-col gap-2">
<div class="input-group w-full flex gap-2">
<input type="file" name="foto_rute_lainnya[]"
class="file-input file-input-bordered w-full"
value="{{ $photo['foto_rute_lainnya'] }}"
accept=".jpg,.jpeg,.png,.gif,.bmp,.tiff,.tif,.webp,.svg"
onchange="previewImage(this, 'foto_rute_lainnya-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>
<button type="button" class="btn btn-danger btn-sm delete-btn"
id="btnDelete">
<i class="ki-filled ki-trash"></i>
</button>
</div>
</div>
</div>
@endforeach
@endif
</div>
<button type="button" class="btn btn-primary btn-sm" id="btnAddMore" style="margin-top: 10px">
<i class="ki-outline ki-plus text-2sm"></i> Lainnya
</button>
</div>
</div>
<div class="card rounded-lg shadow-md">
<div class="card-body">
<div class=" py-4 flex items-center justify-between">
<h1 class="text-md font-medium text-gray-900">Lingkungan</h1>
</div>
<div class="dropzone" id="lingkungan-dropzone">
<div class="dz-message" data-foto-type="foto_lingkungan">
<span>Seret dan lepas file di sini atau klik untuk unggah</span>
</div>
</div>
</div>
</div>
<div class="card border border-agi-100 bg-white rounded-lg shadow-md">
<div class="card-body">
<div class=" py-4 flex items-center justify-between">
<h1 class="text-md font-medium text-gray-900">Objek Jaminan</h1>
</div>
@php
$processedCategories = [];
$tanahBangunanTypes = ['KAPAL', 'PESAWAT', 'KENDARAAN', 'ALAT BERAT','MESIN'];
$dokumentName = null;
@endphp
@foreach ($permohonan->debiture->documents as $dokumen)
@if ($dokumen->jenisJaminan)
@php
$dokumentName =$dokumen->jenisJaminan->name;
$formKategori = json_decode($dokumen->jenisJaminan->form_kategori, true);
@endphp
@if (isset($formKategori) && $formKategori)
<input type="hidden" name="action"
value="{{ is_array($formKategori) ? implode(',', $formKategori) : $formKategori }}">
<input type="hidden" name="type"
value="{{ is_array($formKategori) ? implode(',', $formKategori) : $formKategori }}">
@if (is_array($formKategori))
@foreach ($formKategori as $kategori)
@php
$fotoObjekJaminanFiltered = $fotoObjekJaminan->filter(function ($item) use (
$kategori,
) {
return $item->kategori === $kategori;
});
@endphp
@if (!in_array($kategori, $processedCategories))
@if ($fotoObjekJaminanFiltered->count() > 0)
@foreach ($fotoObjekJaminanFiltered as $item)
<div
class="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5 {{ !$loop->first ? 'mt-2' : '' }}">
<div
class="flex items-baseline flex-wrap lg:flex-nowrap w-full gap-4">
<label class="form-label max-w-56">
<span class="form-label">{{ $item->name }}</span>
</label>
<input type="hidden" class="form-control"
name="name_objek[]" value="{{ $item->name }}" />
<div class="w-full grid gap-5">
@php
$matchedFoto =
collect(
$formFoto['object_jaminan'] ?? [],
)->firstWhere('name_objek', $item->name) ?? [];
@endphp
<img id="foto_object_jaminan_preview_{{ $loop->index }}"
src="{{ isset($matchedFoto['foto_objek']) ? asset('storage/' . $matchedFoto['foto_objek']) : '' }}"
alt="{{ $item->name }}" class="mb-2 h-auto"
style="{{ !empty($matchedFoto['foto_objek']) ? 'width: 30rem;' : 'display: none; width: 30rem;' }}"
onerror="this.style.display='none';" />
<div class="input-group w-full flex gap-2">
<input type="file" name="foto_objek[]"
class="file-input file-input-bordered w-full"
accept=".jpg,.jpeg,.png,.gif,.bmp,.tiff,.tif,.webp,.svg"
onchange="previewImage(this, 'foto_object_jaminan_preview_{{ $loop->index }}')">
<button type="button" id="btnCamera"
class="btn btn-light"
data-modal-toggle="#cameraModal">
<i class="ki-outline ki-abstract-33"></i>
Camera
</button>
</div>
<textarea name="deskripsi_objek[]" class="textarea" rows="3" placeholder="Deskripsi">{{ $matchedFoto['deskripsi_objek'] ?? '' }}</textarea>
</div>
<span class="alert text-danger text-sm"></span>
</div>
</div>
@endforeach
@endif
@php
$processedCategories[] = $kategori;
@endphp
@endif
@endforeach
@endif
@endif
@endif
@endforeach
@if (!in_array(strtoupper($dokumentName), $tanahBangunanTypes))
<div id="lantaiContainer" class="mt-2">
<!-- Lantai akan dinamis ditambahkan di sini -->
<div class="lantai-item mb-4" id="lantai-item-1">
<div class=" d-flex justify-content-between align-items-center">
<h5 class="mb-0">Lantai 1</h5>
<input type="hidden" name="lantai_nama[]" value="lantai_1">
<button type="button" class="btn btn-danger btn-sm btn-remove-lantai" data-id="1"
style="display:none;">
<i class="fa fa-trash"></i> Hapus Lantai
</button>
</div>
<div class="card-body">
<div class="dropzone" id="dropzone-lantai-1">
<div class="dz-message">
Seret dan lepas file di sini atau klik untuk unggah
</div>
</div>
</div>
</div>
</div>
<div class="mt-3">
<button type="button" id="btnAddLantai" class="btn btn-primary">
<i class="fa fa-plus"></i> Tambah Lantai
</button>
</div>
<div id="inputContainerBasement" class="w-full" style="margin-top: 10px">
<div class="flex items-baseline flex-wrap lg:flex-nowrap w-full gap-4">
<label class="form-label max-w-56">
<span class="form-label">Basement</span>
</label>
<div class="input-group w-full flex flex-col gap-2">
<input type="hidden" name="name_basement" value="basement">
<img id="foto_basement_preview"
src="{{ isset($formFoto['foto_basement']) ? asset('storage/' . old('foto_basement', $formFoto['foto_basement'])) : '#' }}"
alt="Gambar foto_basement" style="width: 30rem;" onerror="this.style.display='none';"
onchange="previewImage(this, 'foto_basement_preview')">
<div class="input-group w-full flex gap-2">
<input id="inputBasement" type="file" name="foto_basement"
class="file-input file-input-bordered w-full"
accept=".jpg,.jpeg,.png,.gif,.bmp,.tiff,.tif,.webp,.svg"
onchange="previewImage(this, 'foto_basement_preview')" capture="camera">
<button type="button" id="btnCamera" class="btn btn-light"
data-modal-toggle="#cameraModal">
<i class="ki-outline ki-abstract-33"></i> Camera
</button>
</div>
</div>
<button type="button" class="btn btn-danger btn-sm delete-btn" style="display: none;"
id="btnDelete">
<i class="ki-filled ki-trash"></i>
</button>
</div>
<span id="alertBasement" class="alert text-danger text-sm"></span>
</div>
<div id="lantaiLainnya" style="margin-top: 10px"></div>
<button type="button" class="btn btn-primary btn-sm" id="btnAddMoreObject"
style="margin-top: 10px">
<i class="ki-outline ki-plus text-2sm"></i>
Lainnya
</button>
@endif
</div>
</div>
<div class="card rounded-lg shadow-md">
<div class="card-body">
<div class=" py-4 flex items-center justify-between">
<h1 class="text-md font-medium text-gray-900">Pendamping</h1>
</div>
<div style="margin-top: 5px">
<div class="flex items-baseline flex-wrap lg:flex-nowrap w-full gap-4 mb-4">
<div class="w-full grid gap-5">
<img id="pendamping"
src="{{ isset($formFoto['pendamping']) ? asset('storage/' . old('pendamping', $formFoto['pendamping'])) : '#' }}"
alt="Gambar Pendamping" style="width: 30rem;" onerror="this.style.display='none';"
onchange="previewImage(this, 'pendamping')">
<div class="input-group w-full flex gap-2">
<input id="inputPendamping" type="file" name="pendamping"
class="file-input file-input-bordered w-full"
accept=".jpg,.jpeg,.png,.gif,.bmp,.tiff,.tif,.webp,.svg"
onchange="previewImage(this, 'pendamping')" capture="camera">
<button type="button" id="btnCamera" class="btn btn-light"
data-modal-toggle="#cameraModal">
<i class="ki-outline ki-abstract-33"></i> Camera
</button>
</div>
<button type="button" class="btn btn-danger btn-sm delete-btn" style="display: none;"
id="btnDelete">
<i class="ki-filled ki-trash"></i>
</button>
</div>
</div>
@error('pendamping')
<span class="alert text-danger text-sm">{{ $message }}</span>
@enderror
</div>
</div>
</div>
<div class="flex justify-end gap-2" style="margin-right: 20px; margin-top: 20px">
<button type="button" class="btn btn-success" id="saveButtonFoto" onclick="submitFoto()">
<span id="saveButtonFotoText">Save</span>
</button>
</div>
</form>
</div>
<!-- Modal Kamera -->
@include('lpj::surveyor.components.modal-kamera')
@endsection
@include('lpj::surveyor.js.fotojs')
@include('lpj::surveyor.js.utils')
@push('scripts')
<script src="https://unpkg.com/dropzone@5/dist/min/dropzone.min.js"></script>
<script>
// console.log('@json($formFoto)');
let jsonDataContoh = @json($formFoto);
Dropzone.autoDiscover = false;
document.addEventListener('DOMContentLoaded', function() {
function initDropzone(selector, paramName) {
try {
// Pastikan elemen ada sebelum membuat Dropzone
const dropzoneElement = document.querySelector(selector);
if (!dropzoneElement) {
console.error(`Dropzone element not found: ${selector}`);
return null;
}
return new Dropzone(selector, {
url: "{{ route('surveyor.storeFoto') }}",
paramName: paramName,
maxFilesize: 5,
acceptedFiles: 'image/*',
uploadMultiple: false,
parallelUploads: 1,
maxFiles: 5,
addRemoveLinks: true,
autoProcessQueue: true,
dictRemoveFile: 'Hapus',
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
},
error: function(file, response) {
console.error('Upload error:', response);
Swal.fire({
icon: 'error',
title: 'Upload Gagal',
text: response.message || 'Error tidak diketahui'
});
},
success: function(file, response) {
if (response.success) {
Swal.fire({
icon: 'success',
title: 'Upload Berhasil',
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 1500
});
}
},
removedfile: function(file) {
if (file.originalPath) {
$.ajax({
url: "{{ route('surveyor.hapusFoto') }}",
method: 'DELETE',
data: {
path: file.originalPath,
permohonan_id: {{ $permohonan->id ?? 0 }},
dokument_id: '{{ request('dokument') ?? '' }}',
param_name: paramName
},
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}'
},
success: function(file, response) {
if (response.success) {
Swal.fire({
icon: 'success',
title: 'Hapus Foto Berhasil',
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 1500
});
}
},
});
}
if (file.previewElement) {
file.previewElement.remove();
}
},
init: function() {
var myDropzone = this;
var loadingIndicator = $(`
<div class="loading-overlay" style="
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(255,255,255,0.7);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
">
<div class="loader"></div>
</div>
`);
var $dropzoneElement = $(selector);
$dropzoneElement.css('position', 'relative');
$dropzoneElement.append(loadingIndicator);
$.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() }}'
},
beforeSend: function() {
// Pastikan loading indicator terlihat
loadingIndicator.show();
},
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
};
myDropzone.emit("addedfile", mockFile);
myDropzone.emit("thumbnail", mockFile,
foto.path);
myDropzone.emit("complete", mockFile);
});
} else {
// Tambahkan pesan jika tidak ada foto
console.log('Tidak ada foto yang ditemukan');
}
},
error: function(xhr, status, error) {
console.error('Gagal memuat foto:', error);
},
complete: function() {
// Sembunyikan loading indicator
loadingIndicator.hide();
}
});
}
});
} catch (error) {
console.error('Dropzone initialization error:', error);
return null;
}
}
// 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('#rute-dropzone', 'rute_menuju_lokasi');
safeInitDropzone('#lingkungan-dropzone', 'foto_lingkungan');
// Event listener untuk menambah lantai
});
document.addEventListener('DOMContentLoaded', function() {
const lantaiContainer = document.getElementById('lantaiContainer');
const btnAddLantai = document.getElementById('btnAddLantai');
let lantaiCounter = 1;
let fotoLantaiUnit = {}; // Objek untuk menyimpan foto per lantai
// Objek untuk menyimpan instance Dropzone
const dropzoneInstances = {};
// Fungsi untuk memuat foto berdasarkan JSON
function loadFotoFromJSON(jsonData) {
if (jsonData && jsonData.foto_lantai_unit) {
fotoLantaiUnit = jsonData.foto_lantai_unit;
// Render foto untuk setiap lantai
Object.keys(fotoLantaiUnit).forEach(lantai => {
// Pastikan dropzone untuk lantai ini sudah dibuat
if (!dropzoneInstances[lantai]) {
// Jika belum ada, tambahkan lantai baru
while (lantaiCounter < lantai) {
const newLantaiElement = createLantaiElement();
lantaiContainer.appendChild(newLantaiElement);
initDropzonelantai(lantaiCounter);
}
}
const dropzoneElement = document.querySelector(`#dropzone-lantai-${lantai}`);
if (dropzoneElement) {
var dzInstance = dropzoneInstances[lantai];
fotoLantaiUnit[lantai].forEach(foto => {
// Normalisasi path
let normalizedPath = foto.path;
// Hapus prefix 'surveyor/' jika ada
if (normalizedPath.startsWith('surveyor/')) {
normalizedPath = normalizedPath.replace('surveyor/', '');
}
// Buat mock file untuk ditampilkan di Dropzone
var mockFile = {
name: foto.name || 'Foto Lantai',
size: foto.size || 12345,
path: normalizedPath, // Simpan path yang sudah dinormalisasi
originalPath: 'storage/surveyor/' + normalizedPath
};
// Pastikan instance Dropzone ada
if (dzInstance) {
dzInstance.emit("addedfile", mockFile);
dzInstance.emit("thumbnail", mockFile, 'storage/surveyor/' +
normalizedPath);
dzInstance.emit("complete", mockFile);
} else {
console.error(
`Dropzone instance for floor ${lantai} not found`);
}
});
} else {
console.error(`Dropzone element for floor ${lantai} not found`);
}
});
}
}
function ensureAllFloorsCreated(jsonData) {
if (jsonData && jsonData.foto_lantai_unit) {
const maxFloor = Math.max(...Object.keys(jsonData.foto_lantai_unit).map(Number));
while (lantaiCounter < maxFloor) {
const newLantaiElement = createLantaiElement();
lantaiContainer.appendChild(newLantaiElement);
initDropzonelantai(lantaiCounter);
}
}
}
function deleteFoto(lantai, fotoPath) {
return fetch("{{ route('surveyor.hapusLantai') }}", {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': '{{ csrf_token() }}'
},
body: JSON.stringify({
permohonan_id: {{ $permohonan->id ?? 0 }},
dokument_id: '{{ request('dokument') ?? '' }}',
lantai: lantai,
foto_path: fotoPath
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Hapus foto dari objek fotoLantaiUnit
fotoLantaiUnit[lantai] = fotoLantaiUnit[lantai].filter(
foto => foto.path !== fotoPath
);
return true;
}
return false;
})
.catch(error => {
console.error('Error:', error);
return false;
});
}
// Fungsi inisialisasi Dropzone
function initDropzonelantai(counter) {
dropzoneInstances[counter] = new Dropzone(`#dropzone-lantai-${counter}`, {
url: "{{ route('surveyor.storeFoto') }}",
paramName: "foto_lantai_unit[]",
maxFilesize: 5,
acceptedFiles: 'image/*',
maxFiles: 5,
addRemoveLinks: true,
autoProcessQueue: true,
parallelUploads: 5,
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}'
},
params: function(files, xhr, chunk) {
return {
permohonan_id: {{ $permohonan->id ?? 0 }},
dokument_id: '{{ request('dokument') ?? '' }}',
lantai_nama: [`lantai_${counter}`]
};
},
init: function() {
this.lantaiCounter = counter;
this.on("sending", function(file, xhr, formData) {
formData.append('lantai_index', this.lantaiCounter);
});
},
dictDefaultMessage: 'Seret foto atau klik untuk unggah',
dictRemoveFile: 'Hapus',
dictMaxFilesExceeded: 'Maksimal 5 file per lantai',
removedfile: function(file) {
// Gunakan lantaiCounter dari instance ini
const lantai = this.lantaiCounter;
if (file.path) {
deleteFoto(lantai, file.path).then(success => {
if (success) {
file.previewElement.remove();
}
});
} else {
file.previewElement.remove();
}
},
success: function(file, response) {
const lantai = this.lantaiCounter;
if (!fotoLantaiUnit[lantai]) {
fotoLantaiUnit[lantai] = [];
}
fotoLantaiUnit[lantai].push({
path: response.foto_path,
name: file.name
});
if (response) {
Swal.fire({
icon: 'success',
title: 'Upload Berhasil',
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 1500
});
}
},
error: function(file, errorMessage) {
console.error('Upload error', errorMessage);
}
});
}
// Fungsi membuat elemen lantai baru
function createLantaiElement() {
lantaiCounter++;
const lantaiElement = document.createElement('div');
lantaiElement.classList.add('lantai-item', 'mb-4');
lantaiElement.id = `lantai-item-${lantaiCounter}`;
lantaiElement.innerHTML = `
<div class="flex justify-between align-items-center">
<h5 class="mb-0">Lantai ${lantaiCounter}</h5>
<input type="hidden" name="lantai_nama[]" value="lantai_${lantaiCounter}">
<button type="button" class="btn btn-danger btn-sm btn-remove-lantai" data-id="${lantaiCounter}">
<i class="fa fa-trash"></i> Hapus Lantai
</button>
</div>
<div class="card-body">
<div class="dropzone" id="dropzone-lantai-${lantaiCounter}">
<div class="dz-message">
Seret dan lepas file di sini atau klik untuk unggah
</div>
</div>
</div>
`;
// Event listener untuk tombol hapus lantai
const removeButton = lantaiElement.querySelector('.btn-remove-lantai');
removeButton.addEventListener('click', function() {
const lantaiToRemove = parseInt(this.getAttribute('data-id'));
hapusLantai(lantaiToRemove);
});
return lantaiElement;
}
// Fungsi hapus lantai yang diperbaiki
function hapusLantai(lantai) {
// Konfirmasi penghapusan
Swal.fire({
title: `Apakah Anda yakin ingin menghapus Lantai ${lantai}?`,
text: "Semua foto pada lantai ini akan dihapus permanen!",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: 'Ya, Hapus!',
cancelButtonText: 'Batal'
}).then((result) => {
if (result.isConfirmed) {
// Cek apakah ada foto di lantai ini
const fotosLantai = fotoLantaiUnit[lantai] || [];
// Fungsi untuk menghapus foto-foto di lantai
const hapusFotoLantai = () => {
// Hapus instance Dropzone
if (dropzoneInstances[lantai]) {
dropzoneInstances[lantai].destroy();
delete dropzoneInstances[lantai];
}
// Hapus elemen lantai dari DOM
const lantaiElement = document.getElementById(`lantai-item-${lantai}`);
if (lantaiElement) {
lantaiElement.remove();
}
// Hapus dari objek fotoLantaiUnit
delete fotoLantaiUnit[lantai];
// Perbarui counter dan tampilan
updateLantaiCounter();
// Tampilkan notifikasi sukses
Swal.fire(
'Dihapus!',
`Lantai ${lantai} telah dihapus.`,
'success'
);
};
// Jika ada foto, hapus terlebih dahulu
if (fotosLantai.length > 0) {
// Buat promise untuk menghapus setiap foto
const deletePromises = fotosLantai.map(foto =>
deleteFoto(lantai, foto.path)
);
// Tunggu semua foto terhapus
Promise.all(deletePromises)
.then(() => {
// Setelah semua foto dihapus, lanjutkan proses penghapusan lantai
hapusFotoLantai();
})
.catch(error => {
console.error('Gagal menghapus foto:', error);
Swal.fire(
'Gagal!',
'Terjadi kesalahan saat menghapus foto.',
'error'
);
});
} else {
// Jika tidak ada foto, langsung hapus lantai
hapusFotoLantai();
}
}
});
}
// Fungsi updateLantaiCounter yang diperbaiki
function updateLantaiCounter() {
// Dapatkan semua elemen lantai yang tersisa
const lantaiElements = document.querySelectorAll('.lantai-item');
// Perbarui nomor lantai dan ID
lantaiElements.forEach((element, index) => {
const currentIndex = index + 1;
// Perbarui judul lantai
const lantaiTitle = element.querySelector('h5');
if (lantaiTitle) {
lantaiTitle.textContent = `Lantai ${currentIndex}`;
}
// Perbarui input hidden
const hiddenInput = element.querySelector('input[name="lantai_nama[]"]');
if (hiddenInput) {
hiddenInput.value = `lantai_${currentIndex}`;
}
// Perbarui ID elemen
element.id = `lantai-item-${currentIndex}`;
// Perbarui data-id pada tombol hapus
const removeButton = element.querySelector('.btn-remove-lantai');
if (removeButton) {
removeButton.setAttribute('data-id', currentIndex);
// Tambahkan event listener baru
removeButton.onclick = function() {
hapusLantai(currentIndex);
};
}
});
// Sembunyikan tombol hapus pada lantai pertama jika hanya satu lantai
if (lantaiElements.length === 1) {
const firstRemoveButton = document.querySelector('.btn-remove-lantai[data-id="1"]');
if (firstRemoveButton) {
firstRemoveButton.style.display = 'none';
}
}
// Update lantaiCounter global
lantaiCounter = lantaiElements.length;
}
// Modifikasi event listener untuk tombol tambah lantai
btnAddLantai.addEventListener('click', function() {
const newLantaiElement = createLantaiElement();
lantaiContainer.appendChild(newLantaiElement);
// Inisialisasi Dropzone untuk lantai baru
initDropzonelantai(lantaiCounter);
// Tampilkan tombol hapus untuk lantai pertama
const firstFloorRemoveBtn = document.querySelector('.btn-remove-lantai[data-id="1"]');
if (firstFloorRemoveBtn) {
firstFloorRemoveBtn.style.display = 'block';
}
});
initDropzonelantai(lantaiCounter);
// Pastikan semua lantai dibuat
ensureAllFloorsCreated(jsonDataContoh);
// Muat foto
loadFotoFromJSON(jsonDataContoh);
});
function submitFoto() {
showLoadingSwal('Mengirim data ke server...');
const formElement = $('#formFoto')[0];
const formData = new FormData(formElement);
$.ajax({
url: '{{ route('surveyor.storeFoto') }}',
type: 'POST',
data: formData,
processData: false,
contentType: false,
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}'
},
success: function(response) {
if (response.success) {
hideLoadingSwal();
Swal.fire({
title: 'Berhasil!',
text: response.message,
icon: 'success',
confirmButtonText: 'OK'
}).then((response) => {
if (response.isConfirmed) {
window.location.href =
'{{ route('surveyor.show', ['id' => $permohonan->id]) }}';
}
// console.log(response);
});
} else {
hideLoadingSwal();
Swal.fire({
title: 'Error!',
text: response.message || 'Terjadi kesalahan',
icon: 'error',
confirmButtonText: 'OK'
});
}
console.log(response);
},
error: function(xhr, status, error) {
let errors = xhr.responseJSON?.errors;
$('.alert').text('');
if (errors) {
$.each(errors, function(key, value) {
$(`#error-${key}`).text(value[0]);
});
}
hideLoadingSwal();
toastrErrorBuild(error);
}
});
}
</script>
@include('lpj::surveyor.js.camera-editor')
@endpush