perbaikan foto dan penambahan basic data foto objek jaminan, print-out
This commit is contained in:
@@ -25,6 +25,7 @@ use Modules\Location\Models\District;
|
||||
use Modules\Location\Models\Village;
|
||||
use Modules\Lpj\Models\PosisiKavling;
|
||||
use Modules\Lpj\Models\KondisiFisikTanah;
|
||||
use Modules\Lpj\Models\FotoObjekJaminan;
|
||||
use Modules\Lpj\Models\KetinggianTanah;
|
||||
use Modules\Lpj\Models\SifatBangunan;
|
||||
use Modules\Lpj\Models\JenisJaminan;
|
||||
@@ -284,16 +285,18 @@ class SurveyorController extends Controller
|
||||
{
|
||||
$validatedData = $this->validateFotoRequest($request);
|
||||
try {
|
||||
|
||||
$log = [];
|
||||
$photoCategories = [
|
||||
'rute_menuju_lokasi' => ['foto_rute', 'name_rute'],
|
||||
'object_jaminan' => ['foto_objek', 'name_objek', 'deskripsi_objek'],
|
||||
'lingkungan' => ['foto_lingkungan', 'name_lingkungan'],
|
||||
'foto_lantai_unit' => ['foto_lantai_unit', 'name_lantai_unit'],
|
||||
'foto_lantai_lainnya' => ['foto_lantai_lainnya', 'name_lantai_lainnya'],
|
||||
'foto_rute_lainnya' => ['foto_rute_lainnya', 'name_rute_lainnya'],
|
||||
'rute_menuju_lokasi',
|
||||
'foto_lingkungan',
|
||||
];
|
||||
|
||||
$lainnya =[
|
||||
'foto_rute_lainnya' => ['foto_rute_lainnya', 'name_rute_lainnya'],
|
||||
'foto_lantai_lainnya' => ['foto_lantai_lainnya', 'name_lantai_lainnya']
|
||||
];
|
||||
|
||||
|
||||
$inspeksi = Inspeksi::firstOrNew([
|
||||
'permohonan_id' => $request->input('permohonan_id'),
|
||||
'dokument_id' => $request->input('dokument_id')
|
||||
@@ -306,37 +309,62 @@ class SurveyorController extends Controller
|
||||
|
||||
$formatFotojson = $existingData;
|
||||
|
||||
if ($request->has('foto_lantai_unit')) {
|
||||
$formatFotojson['foto_lantai_unit'] = $this->processFotoLantaiUnit($request);
|
||||
if ($request->hasFile('foto_objek')) {
|
||||
$existingObjekJaminan = $formatFotojson['object_jaminan'] ?? [];
|
||||
$formatFotojson['object_jaminan'] = $this->processObjekJaminanPhotos(
|
||||
$request,
|
||||
$existingObjekJaminan
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($photoCategories as $category => $fields) {
|
||||
if ($request->has('foto_lantai_unit')) {
|
||||
$existingLantaiUnit = $formatFotojson['foto_lantai_unit'] ?? [];
|
||||
$newLantaiUnit = $this->processFotoLantaiUnit($request);
|
||||
|
||||
foreach ($newLantaiUnit as $key => $newFiles) {
|
||||
$existingLantaiUnit[$key] = array_merge($existingLantaiUnit[$key] ?? [], $newFiles);
|
||||
}
|
||||
|
||||
$formatFotojson['foto_lantai_unit'] = $existingLantaiUnit;
|
||||
$log['foto_lantai_unit'] = $formatFotojson['foto_lantai_unit'];
|
||||
}
|
||||
|
||||
foreach ($photoCategories as $key) {
|
||||
if ($request->has($key)) {
|
||||
$newPhotos = $this->processPhotoCategories($request, $key);
|
||||
$existingPhotos = $formatFotojson[$key] ?? [];
|
||||
$formatFotojson[$key] = array_merge($existingPhotos, $newPhotos);
|
||||
$log[$key] = $formatFotojson[$key];
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($lainnya as $category => $fields) {
|
||||
$photoField = $fields[0];
|
||||
$nameField = $fields[1];
|
||||
$descriptionField = $fields[2] ?? null;
|
||||
|
||||
if ($request->hasFile($photoField)) {
|
||||
$newPhotos = $this->processPhotoCategory(
|
||||
$newPhotos = $this->processPhotoLainnya(
|
||||
$request,
|
||||
$fields,
|
||||
$existingData[$category] ?? [],
|
||||
$category // Pass category to the function
|
||||
$existingData[$category] ?? []
|
||||
);
|
||||
|
||||
$formatFotojson[$category] = $newPhotos;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Process single files
|
||||
$singleFiles = ['foto_basement', 'foto_gerbang', 'pendamping'];
|
||||
foreach ($singleFiles as $file) {
|
||||
if ($request->hasFile($file)) {
|
||||
// Delete old file if exists
|
||||
if (isset($existingData[$file])) {
|
||||
$this->deleteFile($existingData[$file]);
|
||||
// Hapus file lama jika ada
|
||||
if (isset($formatFotojson[$file])) {
|
||||
$this->deleteOfFile($formatFotojson[$file]);
|
||||
}
|
||||
|
||||
// Upload dan simpan file baru
|
||||
$formatFotojson[$file] = $this->uploadFile($request->file($file), $file);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,7 +372,7 @@ class SurveyorController extends Controller
|
||||
$inspeksi->foto_form = json_encode($formatFotojson);
|
||||
$inspeksi->save();
|
||||
|
||||
return response()->json(['success' => true, 'message' => 'Data berhasil disimpan', 'data' => $formatFotojson], 200);
|
||||
return response()->json(['success' => true, 'message' => 'Data berhasil disimpan', 'data' => $formatFotojson, 'log' => $log ], 200);
|
||||
} catch (Exception $e) {
|
||||
return response()->json(['success' => false, 'message' => 'Failed to upload: ' . $e->getMessage()], 500);
|
||||
}
|
||||
@@ -353,19 +381,134 @@ class SurveyorController extends Controller
|
||||
/**
|
||||
* Process a photo category and its subcategories
|
||||
*/
|
||||
private function processPhotoCategory(Request $request, array $fields, array $existingPhotos = [], $category = null)
|
||||
private function processPhotoCategories(Request $request, string $categoryKey)
|
||||
{
|
||||
$processedPhotos = [];
|
||||
$categoryPhotos = $request->file($categoryKey, []);
|
||||
if (is_array($categoryPhotos)) {
|
||||
$categoryPhotos = array_merge(...array_values($categoryPhotos));
|
||||
}
|
||||
$namePrefix = str_replace('_', ' ', $categoryKey);
|
||||
|
||||
foreach ($categoryPhotos as $index => $file) {
|
||||
// Validate the file
|
||||
if (!$file instanceof \Illuminate\Http\UploadedFile || !$file->isValid()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Generate a unique filename for the photo
|
||||
$filename = $this->generateUniqueFileName($file, "{$categoryKey}_{$index}");
|
||||
|
||||
if (isset($processedPhotos[$categoryKey])) {
|
||||
$processedPhotos[$categoryKey][0][] = [
|
||||
'path' => $this->uploadFile($file, $filename),
|
||||
'name' => ucfirst($namePrefix) . ' - ' . ($index + 1),
|
||||
];
|
||||
} else {
|
||||
$processedPhotos[$categoryKey] = [
|
||||
[
|
||||
[
|
||||
'path' => $this->uploadFile($file, $filename),
|
||||
'name' => ucfirst($namePrefix) . ' - ' . ($index + 1),
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $processedPhotos;
|
||||
}
|
||||
|
||||
private function processObjekJaminanPhotos(Request $request, array $existingPhotos = [])
|
||||
{
|
||||
$photoField = 'foto_objek';
|
||||
$nameField = 'name_objek';
|
||||
$descriptionField = 'deskripsi_objek';
|
||||
|
||||
// Mulai dengan data lama
|
||||
$result = $existingPhotos;
|
||||
|
||||
if ($request->hasFile($photoField)) {
|
||||
$newFiles = $request->file($photoField, []);
|
||||
$newNames = $request->input($nameField, []);
|
||||
$newDescriptions = $request->input($descriptionField, []);
|
||||
|
||||
foreach ($newFiles as $key => $file) {
|
||||
// Cari atau buat entri berdasarkan nama objek
|
||||
$existingIndex = $this->findObjekJaminanIndexByName($result, $newNames[$key]);
|
||||
|
||||
// Buat entri baru untuk file yang diunggah
|
||||
$newPhotoEntry = [
|
||||
$nameField => $newNames[$key],
|
||||
$photoField => $this->uploadFile($file, $photoField . '.' . $key),
|
||||
$descriptionField => $newDescriptions[$key] ?? '',
|
||||
];
|
||||
|
||||
// Jika sudah ada, update; jika belum, tambahkan
|
||||
if ($existingIndex !== false) {
|
||||
// Hapus file lama jika ada
|
||||
if (isset($result[$existingIndex][$photoField])) {
|
||||
$this->deleteOfFile($result[$existingIndex][$photoField]);
|
||||
}
|
||||
$result[$existingIndex] = $newPhotoEntry;
|
||||
} else {
|
||||
$result[] = $newPhotoEntry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pastikan array tetap terurut dengan benar
|
||||
return array_values($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cari index objek jaminan berdasarkan nama objek
|
||||
*/
|
||||
private function findObjekJaminanIndexByName(array $existingPhotos, string $name)
|
||||
{
|
||||
foreach ($existingPhotos as $index => $photo) {
|
||||
if (isset($photo['name_objek']) && $photo['name_objek'] === $name) {
|
||||
return $index;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private function processFotoLantaiUnit(Request $request)
|
||||
{
|
||||
$processedFotoLantaiUnit = [];
|
||||
$fotoLantaiUnit = $request->file('foto_lantai_unit', []);
|
||||
|
||||
foreach ($fotoLantaiUnit as $lantaiKey => $files) {
|
||||
$processedFiles = [];
|
||||
|
||||
foreach ($files as $index => $file) {
|
||||
if (!$file || !$file->isValid()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$filename = $this->generateUniqueFileName($file, "lantai_unit_{$lantaiKey}_{$index}");
|
||||
$processedFiles[] = [
|
||||
'path' => $this->uploadFile($file, $filename),
|
||||
'name' => "Foto Lantai {$lantaiKey} - " . ($index + 1),
|
||||
];
|
||||
}
|
||||
|
||||
if (!empty($processedFiles)) {
|
||||
$processedFotoLantaiUnit[$lantaiKey] = $processedFiles;
|
||||
}
|
||||
}
|
||||
|
||||
return $processedFotoLantaiUnit;
|
||||
}
|
||||
|
||||
private function processPhotoLainnya(Request $request, array $fields, array $existingPhotos = [])
|
||||
{
|
||||
$result = $existingPhotos; // Start with existing photos
|
||||
$photoField = $fields[0];
|
||||
$nameField = $fields[1];
|
||||
$descriptionField = $fields[2] ?? null;
|
||||
|
||||
if ($category === 'object_jaminan') {
|
||||
// If it's 'object_jaminan', do not overwrite existing photos, just add new ones
|
||||
$existingPhotos = $existingPhotos ?: [];
|
||||
$result = $existingPhotos;
|
||||
}
|
||||
|
||||
if ($request->hasFile($photoField)) {
|
||||
$newFiles = $request->file($photoField, []);
|
||||
$newNames = $request->input($nameField, []);
|
||||
@@ -375,7 +518,7 @@ class SurveyorController extends Controller
|
||||
foreach ($newFiles as $key => $file) {
|
||||
// Create new photo entry
|
||||
$newPhotoEntry = [
|
||||
$nameField => $newNames[$key] ?? '',
|
||||
$nameField => $newNames[$key] ?? '', // Use new name if provided
|
||||
$photoField => $this->uploadFile($file, $photoField . '.' . $key)
|
||||
];
|
||||
|
||||
@@ -392,70 +535,12 @@ class SurveyorController extends Controller
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
public function replaceFotoLantaiUnit(Request $request)
|
||||
{
|
||||
// Pastikan foto lantai unit ada dalam request
|
||||
if ($request->has('foto_lantai_unit')) {
|
||||
$fotoLantaiUnit = $request->file('foto_lantai_unit', []);
|
||||
|
||||
// Target lantai dan foto yang ingin diubah
|
||||
$lantaiKey = $request->input('lantai_key'); // Misal: 1
|
||||
$indexToReplace = $request->input('index'); // Misal: 0
|
||||
|
||||
// Cek jika lantaiKey ada dan file yang akan diganti ada
|
||||
if (isset($fotoLantaiUnit[$lantaiKey]) && isset($fotoLantaiUnit[$lantaiKey][$indexToReplace])) {
|
||||
$file = $fotoLantaiUnit[$lantaiKey][$indexToReplace];
|
||||
|
||||
// Pastikan file valid
|
||||
if ($file && $file->isValid()) {
|
||||
// Generate filename baru untuk foto yang diganti
|
||||
$filename = $this->generateUniqueFileName($file, "lantai_unit_{$lantaiKey}_{$indexToReplace}");
|
||||
|
||||
// Gantikan foto yang lama dengan yang baru
|
||||
$processedFoto = [
|
||||
'path' => $this->uploadFile($file, $filename . '.' . $file->getClientOriginalExtension()),
|
||||
'name' => "Foto Lantai {$lantaiKey} - " . ($indexToReplace + 1),
|
||||
];
|
||||
|
||||
// Update foto lantai unit yang sudah diproses
|
||||
$fotoLantaiUnit[$lantaiKey][$indexToReplace] = $processedFoto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Kembalikan data foto lantai unit yang sudah diperbarui
|
||||
return response()->json(['foto_lantai_unit' => $fotoLantaiUnit]);
|
||||
}
|
||||
|
||||
|
||||
// Fungsi helper untuk generate nama file unik
|
||||
private function generateUniqueFileName($file, $prefix = '')
|
||||
{
|
||||
$extension = $file->getClientOriginalExtension();
|
||||
return $prefix . '_' . uniqid() . '.' . $extension;
|
||||
}
|
||||
|
||||
private function categoryHasNewFiles(Request $request, array $fields): bool
|
||||
{
|
||||
$photoField = $fields[0]; // First element is usually the photo field
|
||||
return $request->hasFile($photoField) ||
|
||||
(is_array($request->file($photoField)) && count($request->file($photoField)) > 0);
|
||||
}
|
||||
|
||||
private function deleteFilesForCategory($categoryData)
|
||||
{
|
||||
if (!is_array($categoryData)) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($categoryData as $item) {
|
||||
if (isset($item['foto'])) {
|
||||
$this->deleteOfFile($item['foto']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function deleteOfFile($filePath)
|
||||
{
|
||||
if ($filePath && Storage::exists($filePath)) {
|
||||
@@ -475,7 +560,7 @@ class SurveyorController extends Controller
|
||||
'pendamping' => 'nullable|image|mimes:jpeg,png,jpg,gif,svg,webp,bmp,tiff,heic,heif|max:'. $maxSize,
|
||||
'foto_objek.*' => 'required|image|mimes:jpeg,png,jpg,gif,svg,webp,bmp,tiff,heic,heif|max:'. $maxSize,
|
||||
'name_objek.*' => 'required|string|max:255',
|
||||
'foto_lingkungan.*' => 'required|image|mimes:jpeg,png,jpg,gif,svg,webp,bmp,tiff,heic,heif|max:'. $maxSize,
|
||||
|
||||
'name_lingkungan.*' => 'required|string|max:255',
|
||||
'foto_rute.*' => 'required|image|mimes:jpeg,png,jpg,gif,svg,webp,bmp,tiff,heic,heif|max:'. $maxSize,
|
||||
'name_rute.*' => 'required|string|max:255',
|
||||
@@ -492,8 +577,7 @@ class SurveyorController extends Controller
|
||||
|
||||
|
||||
'name_lantai_unit' => 'array',
|
||||
'foto_lantai_unit' => 'array',
|
||||
'foto_lantai_unit.*' => 'array',
|
||||
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -1113,6 +1197,7 @@ class SurveyorController extends Controller
|
||||
|
||||
$dokumentId = $validated['dokument'];
|
||||
$jaminanId = $validated['jenisjaminan'];
|
||||
$fotoObjekJaminan = FotoObjekJaminan::all();
|
||||
|
||||
$permohonan = $this->getPermohonanJaminanId($id, $dokumentId, $jaminanId);
|
||||
|
||||
@@ -1127,7 +1212,7 @@ class SurveyorController extends Controller
|
||||
$formFoto = json_decode($inpeksi->foto_form, true);
|
||||
}
|
||||
$fotoJaminan = null;
|
||||
return view('lpj::surveyor.components.foto', compact('permohonan', 'surveyor', 'branches', 'provinces', 'fotoJaminan', 'formFoto'));
|
||||
return view('lpj::surveyor.components.foto', compact('permohonan', 'surveyor', 'branches', 'provinces', 'fotoJaminan', 'formFoto', 'fotoObjekJaminan'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1312,6 +1397,7 @@ class SurveyorController extends Controller
|
||||
'posisi-unit' => ['Posisi unit', 'posisi-unit', PosisiUnit::class],
|
||||
'bentuk-unit' => ['Bentuk unit', 'bentuk-unit', BentukUnit::class],
|
||||
'fasilitas-objek' => ['Fasilitas Umum Dekat Objek', 'fasilitas-objek', FasilitasObjek::class],
|
||||
'foto-objek-jaminan' => ['Foto Objek Jaminan', 'foto-objek-jaminan', FotoObjekJaminan::class],
|
||||
];
|
||||
|
||||
|
||||
@@ -1344,6 +1430,10 @@ class SurveyorController extends Controller
|
||||
$validate['spek_kategori_bagunan_id'] = $request->spek_kategori_bagunan_id;
|
||||
}
|
||||
|
||||
if ($type == 'foto-objek-jaminan') {
|
||||
$validate['kategori'] = $request->kategori;
|
||||
}
|
||||
|
||||
// Check if the provided type exists in the modelClasses
|
||||
if (!$modelClass) {
|
||||
return redirect()
|
||||
@@ -1552,6 +1642,7 @@ class SurveyorController extends Controller
|
||||
'Fasilitas Umum Dekat Objek' => FasilitasObjek::class,
|
||||
'Merupakan Daerah' => MerupakanDaerah::class,
|
||||
'Jenis unit' => JenisUnit::class,
|
||||
'Foto Objek Jaminan' => FotoObjekJaminan::class,
|
||||
];
|
||||
|
||||
|
||||
@@ -1695,6 +1786,7 @@ class SurveyorController extends Controller
|
||||
'merupakan-daerah' => MerupakanDaerah::class,
|
||||
'jenis-unit' => JenisUnit::class,
|
||||
'perkerasan-jalan' => PerkerasanJalan::class,
|
||||
'foto-objek-jaminan' => FotoObjekJaminan::class
|
||||
];
|
||||
|
||||
|
||||
@@ -1770,6 +1862,7 @@ class SurveyorController extends Controller
|
||||
'posisi-unit' => ['Posisi unit', 'posisi-unit'],
|
||||
'bentuk-unit' => ['Bentuk unit', 'bentuk-unit'],
|
||||
'fasilitas-objek' => ['Fasilitas Umum Dekat Objek', 'fasilitas-objek'],
|
||||
'foto-objek-jaminan' => ['Foto Objek Jaminan', 'foto-objek-jaminan'],
|
||||
];
|
||||
|
||||
private function getAssetData(array $data): array
|
||||
|
||||
@@ -38,6 +38,7 @@ class SurveyorRequest extends FormRequest
|
||||
'bentuk-unit' => 'bentuk_unit',
|
||||
'fasilitas-objek' => 'fasilitas_objek',
|
||||
'perkerasan-jalan' => 'perkerasan_jalan',
|
||||
'foto-objek-jaminan' => 'foto_objek_jaminan',
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
24
app/Models/FotoObjekJaminan.php
Normal file
24
app/Models/FotoObjekJaminan.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Lpj\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
// use Modules\Lpj\Database\Factories\FotoObjekJaminanFactory;
|
||||
|
||||
class FotoObjekJaminan extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $table = 'foto_objek_jaminan';
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*/
|
||||
protected $guarded = ['id'];
|
||||
|
||||
// protected static function newFactory(): FotoObjekJaminanFactory
|
||||
// {
|
||||
// // return FotoObjekJaminanFactory::new();
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('foto_objek_jaminan', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('code');
|
||||
$table->string('name');
|
||||
$table->string('kategori');
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
$table->unsignedBigInteger('created_by')->nullable();
|
||||
$table->unsignedBigInteger('updated_by')->nullable();
|
||||
$table->unsignedBigInteger('deleted_by')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('foto_objek_jaminan');
|
||||
}
|
||||
};
|
||||
86
database/seeders/FotoObjekJaminanSeeder.php
Normal file
86
database/seeders/FotoObjekJaminanSeeder.php
Normal file
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Lpj\Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Modules\Lpj\Models\FotoObjekJaminan;
|
||||
|
||||
class FotoObjekJaminanSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
$data = [
|
||||
'tanah' => [
|
||||
['name' => 'Tampak Depan Objek', 'kategori' => 'tanah'],
|
||||
['name' => 'Tampak Samping Kiri', 'kategori' => 'tanah'],
|
||||
['name' => 'Tampak Samping Kanan', 'kategori' => 'tanah'],
|
||||
['name' => 'Nomor Rumah/Unit', 'kategori' => 'tanah'],
|
||||
],
|
||||
'apartemen-kantor' => [
|
||||
['name' => 'Tampak Loby', 'kategori' => 'apartemen-kantor'],
|
||||
['name' => 'Tampak Lift', 'kategori' => 'apartemen-kantor'],
|
||||
['name' => 'Tampak Samping Kiri Unit', 'kategori' => 'apartemen-kantor'],
|
||||
['name' => 'Tampak Samping Kanan Unit', 'kategori' => 'apartemen-kantor'],
|
||||
['name' => 'Tampak Depan Unit', 'kategori' => 'apartemen-kantor'],
|
||||
['name' => 'Nomor Unit', 'kategori' => 'apartemen-kantor'],
|
||||
],
|
||||
'kendaraan' => [
|
||||
['name' => 'Tampak Depan Objek', 'kategori' => 'kendaraan'],
|
||||
['name' => 'Tampak Kanan Objek', 'kategori' => 'kendaraan'],
|
||||
['name' => 'Tampak Samping Kiri Objek', 'kategori' => 'kendaraan'],
|
||||
['name' => 'Tampak Belakang Objek', 'kategori' => 'kendaraan'],
|
||||
['name' => 'Tampak Bagian Dalam', 'kategori' => 'kendaraan'],
|
||||
['name' => 'Nomor Panel Instrument', 'kategori' => 'kendaraan'],
|
||||
['name' => 'Tampak Odometer', 'kategori' => 'kendaraan'],
|
||||
['name' => 'Tampak Aksesoris Tambahan', 'kategori' => 'kendaraan'],
|
||||
['name' => 'Tampak Nomor Rangka', 'kategori' => 'kendaraan'],
|
||||
['name' => 'Tampak Nomor Mesin', 'kategori' => 'kendaraan'],
|
||||
['name' => 'Tampak Penilai dan Pendamping di lapangan', 'kategori' => 'kendaraan'],
|
||||
],
|
||||
'kapal' => [
|
||||
['name' => 'Tampak Depan', 'kategori' => 'kapal'],
|
||||
['name' => 'Tampak Kanan', 'kategori' => 'kapal'],
|
||||
['name' => 'Tampak Samping Kiri', 'kategori' => 'kapal'],
|
||||
['name' => 'Tampak Belakang', 'kategori' => 'kapal'],
|
||||
['name' => 'Tampak Bagian Dalam', 'kategori' => 'kapal'],
|
||||
['name' => 'Nomor Panel Instrument', 'kategori' => 'kapal'],
|
||||
['name' => 'Tampak Hours Meters', 'kategori' => 'kapal'],
|
||||
['name' => 'Tampak Aksesoris Tambahan', 'kategori' => 'kapal'],
|
||||
['name' => 'Tampak Nomor Rangka', 'kategori' => 'kapal'],
|
||||
['name' => 'Tampak Nomor Mesin', 'kategori' => 'kapal'],
|
||||
['name' => 'Tampak Penilai dan Pendamping di lapangan', 'kategori' => 'kapal'],
|
||||
],
|
||||
'mesin' => [
|
||||
['name' => 'Tampak Depan', 'kategori' => 'mesin'],
|
||||
['name' => 'Tampak Kanan', 'kategori' => 'mesin'],
|
||||
['name' => 'Tampak Samping Kiri', 'kategori' => 'mesin'],
|
||||
['name' => 'Tampak Belakang', 'kategori' => 'mesin'],
|
||||
['name' => 'Tampak Bagian Dalam', 'kategori' => 'mesin'],
|
||||
['name' => 'Nomor Panel Instrument', 'kategori' => 'mesin'],
|
||||
['name' => 'Tampak Hours Meters', 'kategori' => 'mesin'],
|
||||
['name' => 'Tampak Aksesoris Tambahan', 'kategori' => 'mesin'],
|
||||
['name' => 'Tampak Nomor Rangka', 'kategori' => 'mesin'],
|
||||
['name' => 'Tampak Nomor Mesin', 'kategori' => 'mesin'],
|
||||
['name' => 'Foto Tampak Aksesoris Tambahan Lainnya', 'kategori' => 'mesin'],
|
||||
['name' => 'Tampak Penilai dan Pendamping di lapangan', 'kategori' => 'mesin'],
|
||||
],
|
||||
];
|
||||
|
||||
$counter = 1;
|
||||
|
||||
// Add `code` field to each item
|
||||
foreach ($data as $kategori => &$items) {
|
||||
foreach ($items as &$item) {
|
||||
$item['code'] = 'FO' . str_pad($counter, 3, '0', STR_PAD_LEFT);
|
||||
$counter++;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($data as $kategori => $views) {
|
||||
FotoObjekJaminan::insert($views);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,7 @@ class LpjDatabaseSeeder extends Seeder
|
||||
DokumenJaminanSeeder::class,
|
||||
DetailDokumenJaminanSeeder::class,
|
||||
PermohonanSeeder::class,
|
||||
FotoObjekJaminanSeeder::class,
|
||||
// PenawaranSeeder::class,
|
||||
// DetailPenawaranSeeder::class,
|
||||
// PenilaianSeeder::class,
|
||||
|
||||
11
module.json
11
module.json
@@ -849,6 +849,17 @@
|
||||
"administrator",
|
||||
"admin"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Foto Objek Jaminan",
|
||||
"path": "basicdata.foto-objek-jaminan",
|
||||
"classes": "",
|
||||
"attributes": [],
|
||||
"permission": "",
|
||||
"roles": [
|
||||
"administrator",
|
||||
"admin"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,24 +1,45 @@
|
||||
<div>
|
||||
@if (isset($formFoto['rute_menuju_lokasi']))
|
||||
@foreach ($formFoto['rute_menuju_lokasi'] as $item)
|
||||
@if (isset($formFoto['rute_menuju_lokasi']['rute_menuju_lokasi']))
|
||||
@foreach ($formFoto['rute_menuju_lokasi']['rute_menuju_lokasi'][0] as $index => $item)
|
||||
<div class="border photo-item">
|
||||
<h2 class="text-gray-600 font-semibold text-xl">
|
||||
{{ $item['name_rute'] . ' ' . $loop->index + 1 }}
|
||||
{{ $item['name'] . ' ' . $loop->index + 1 }}
|
||||
</h2>
|
||||
|
||||
@php
|
||||
$imagePath = $statusLpj
|
||||
? asset('storage/' . $item['foto_rute'])
|
||||
: storage_path('app/public/' . $item['foto_rute']);
|
||||
? asset('storage/' . $item['path'])
|
||||
: storage_path('app/public/' . $item['path']);
|
||||
@endphp
|
||||
|
||||
@if ($statusLpj || file_exists(storage_path('app/public/' . $item['foto_rute'])))
|
||||
<img src="{{ $imagePath }}" alt="{{ $item['foto_rute'] }}" class="photo-image">
|
||||
@if ($statusLpj || file_exists(storage_path('app/public/' . $item['path'])))
|
||||
<img src="{{ $imagePath }}" alt="{{ $item['path'] }}" class="photo-image">
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
@endif
|
||||
|
||||
@if (isset($formFoto['foto_rute_lainnya']))
|
||||
@foreach ($formFoto['foto_rute_lainnya'] as $index => $item)
|
||||
<div class="border photo-item">
|
||||
<h2 class="text-gray-600 font-semibold text-xl">
|
||||
{{ $item['name_rute_lainnya'] }}
|
||||
</h2>
|
||||
|
||||
@php
|
||||
$imagePath = $statusLpj
|
||||
? asset('storage/' . $item['foto_rute_lainnya'])
|
||||
: storage_path('app/public/' . $item['foto_rute_lainnya']);
|
||||
@endphp
|
||||
|
||||
@if ($statusLpj || file_exists(storage_path('app/public/' . $item['foto_rute_lainnya'])))
|
||||
<img src="{{ $imagePath }}" alt="{{ $item['foto_rute_lainnya'] }}" class="photo-image">
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
@endif
|
||||
|
||||
|
||||
@if (isset($formFoto['object_jaminan']))
|
||||
@foreach ($formFoto['object_jaminan'] as $item)
|
||||
<div class="border photo-item">
|
||||
@@ -39,6 +60,49 @@
|
||||
@endforeach
|
||||
@endif
|
||||
|
||||
|
||||
@if (isset($formFoto['foto_lantai_unit']))
|
||||
@foreach ($formFoto['foto_lantai_unit'] as $index => $floorPhotos)
|
||||
@foreach ($floorPhotos as $index => $item)
|
||||
<div class="border photo-item">
|
||||
<h2 class="text-gray-600 font-semibold text-xl">
|
||||
{{ $item['name'] ?? 'Foto Lantai ' . $floorNumber . ' - ' . ($index + 1) }}
|
||||
</h2>
|
||||
|
||||
@php
|
||||
$imagePath = $statusLpj
|
||||
? asset('storage/' . $item['path'])
|
||||
: storage_path('app/public/' . $item['path']);
|
||||
@endphp
|
||||
|
||||
@if ($statusLpj || file_exists(storage_path('app/public/' . $item['path'])))
|
||||
<img src="{{ $imagePath }}" alt="{{ $item['path'] }}" class="photo-image">
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
@endforeach
|
||||
@endif
|
||||
|
||||
@if (isset($formFoto['foto_lingkungan']['foto_lingkungan']))
|
||||
@foreach ($formFoto['foto_lingkungan']['foto_lingkungan'][0] as $index => $item)
|
||||
<div class="border photo-item">
|
||||
<h2 class="text-gray-600 font-semibold text-xl">
|
||||
{{ $item['name'] . ' ' . $loop->index + 1 }}
|
||||
</h2>
|
||||
|
||||
@php
|
||||
$imagePath = $statusLpj
|
||||
? asset('storage/' . $item['path'])
|
||||
: storage_path('app/public/' . $item['path']);
|
||||
@endphp
|
||||
|
||||
@if ($statusLpj || file_exists(storage_path('app/public/' . $item['path'])))
|
||||
<img src="{{ $imagePath }}" alt="{{ $item['path'] }}" class="photo-image">
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
@endif
|
||||
|
||||
@if (isset($formFoto['foto_basement']))
|
||||
<div class="border photo-item">
|
||||
<h2 class="text-gray-600 font-semibold text-xl">
|
||||
|
||||
@@ -5,18 +5,39 @@
|
||||
</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
@if (isset($formFoto))
|
||||
@foreach ($formFoto['rute_menuju_lokasi'] as $item)
|
||||
@if (isset($formFoto['rute_menuju_lokasi']['rute_menuju_lokasi']))
|
||||
@foreach ($formFoto['rute_menuju_lokasi']['rute_menuju_lokasi'][0] as $index => $item)
|
||||
<div class="flex items-center justify-between mt-5">
|
||||
<div class="grid gap-5">
|
||||
<h2 class="text-gray-600 font-semibold text-xl">
|
||||
{{ $item['name_rute'] . ' ' . $loop->index + 1 }}
|
||||
{{ $item['name'] ?? 'Rute menuju lokasi - ' . ($index + 1) }}
|
||||
</h2>
|
||||
<div class="flex items-center">
|
||||
<img src="{{ Storage::url($item['path']) }}" alt="Gambar {{ $index + 1 }}" class="w-full h-auto object-cover">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<img src="{{ Storage::url($item['foto_rute']) }}" alt="">
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header" id="basic_settings">
|
||||
<h3 class="card-title">
|
||||
Rute Lainnya
|
||||
</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
@if (isset($formFoto['foto_rute_lainnya']))
|
||||
@foreach ($formFoto['foto_rute_lainnya'] as $index => $item)
|
||||
<div class="flex items-center justify-between mt-5">
|
||||
<div class="grid gap-5">
|
||||
<h2 class="text-gray-600 font-semibold text-xl">
|
||||
{{ $item['name_rute_lainnya'] ?? 'Rute menuju lokasi - ' . ($index + 1) }}
|
||||
</h2>
|
||||
<div class="flex items-center">
|
||||
<img src="{{ Storage::url($item['foto_rute_lainnya']) }}" alt="Gambar {{ $index + 1 }}" class="w-full h-auto object-cover">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -43,7 +64,7 @@
|
||||
<div class="flex items-center">
|
||||
|
||||
|
||||
<img src="{{ Storage::url($item['foto_objek']) }}" alt="">
|
||||
<img src="{{ Storage::url($item['foto_objek']) }}" alt="" class="w-full h-auto object-cover">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -53,6 +74,57 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header" id="basic_settings">
|
||||
<h3 class="card-title">Lantai</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
@if (isset($formFoto['foto_lantai_unit']))
|
||||
@foreach ($formFoto['foto_lantai_unit'] as $floorNumber => $floorPhotos)
|
||||
<div class="mt-5">
|
||||
@foreach ($floorPhotos as $index => $item)
|
||||
<div class="flex items-center justify-between mt-3">
|
||||
<div class="grid gap-3">
|
||||
<h3 class="text-gray-600 font-semibold text-lg">
|
||||
{{ $item['name'] ?? 'Foto Lantai ' . $floorNumber . ' - ' . ($index + 1) }}
|
||||
</h3>
|
||||
<div class="flex items-center">
|
||||
<img src="{{ Storage::url($item['path']) }}" alt="Gambar {{ $floorNumber }}-{{ $index + 1 }}" class="w-full h-auto object-cover">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endforeach
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header" id="basic_settings">
|
||||
<h3 class="card-title">
|
||||
Lingkungan </h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
@if (isset($formFoto['foto_lingkungan']['foto_lingkungan']))
|
||||
@foreach ($formFoto['foto_lingkungan']['foto_lingkungan'][0] as $index => $item)
|
||||
<div class="flex items-center justify-between mt-5">
|
||||
<div class="grid gap-5">
|
||||
<h2 class="text-gray-600 font-semibold text-xl">
|
||||
{{ $item['name'] ?? 'Rute menuju lokasi - ' . ($index + 1) }}
|
||||
</h2>
|
||||
<div class="flex items-center">
|
||||
<img src="{{ Storage::url($item['path']) }}" alt="Gambar {{ $index + 1 }}" class="w-full h-auto object-cover">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
@endif
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@if (isset($formFoto['foto_basement']))
|
||||
<div class="card">
|
||||
<div class="card-header" id="basic_settings">
|
||||
@@ -79,6 +151,30 @@
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header" id="basic_settings">
|
||||
<h3 class="card-title">
|
||||
Lantai Lainnya
|
||||
</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
@if (isset($formFoto['foto_lantai_lainnya']))
|
||||
@foreach ($formFoto['foto_lantai_lainnya'] as $index => $item)
|
||||
<div class="flex items-center justify-between mt-5">
|
||||
<div class="grid gap-5">
|
||||
<h2 class="text-gray-600 font-semibold text-xl">
|
||||
{{ $item['name_lantai_lainnya'] ?? 'Rute menuju lokasi - ' . ($index + 1) }}
|
||||
</h2>
|
||||
<div class="flex items-center">
|
||||
<img src="{{ Storage::url($item['foto_lantai_lainnya']) }}" alt="Gambar {{ $index + 1 }}" class="w-full h-auto object-cover">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (isset($formFoto['foto_gerbang']))
|
||||
<div class="card">
|
||||
<div class="card-header" id="basic_settings">
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<title>Laporan Penilai Jaminan</title>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<title>Laporan Penilai jaminan</title>
|
||||
<style>
|
||||
body {
|
||||
|
||||
@@ -240,7 +240,7 @@
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="menu-item">
|
||||
{{-- <div class="menu-item">
|
||||
<a class="menu-link"
|
||||
onclick="rap('{{ $permohonan->id }}', '{{ $dokumen->id }}', '{{ $inspeksiId }}', {{ $dokumen->jenis_jaminan_id }})">
|
||||
<span class="menu-icon">
|
||||
@@ -251,7 +251,7 @@
|
||||
RAP
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div> --}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,77 +1,115 @@
|
||||
@extends('layouts.main')
|
||||
|
||||
@section('content')
|
||||
|
||||
<div class="card w-full bg-white rounded-lg shadow-md h-100vh">
|
||||
<div class="card-header flex justify-between items-center">
|
||||
<h3 class="card-title uppercase">
|
||||
Laporan
|
||||
</h3>
|
||||
<a href="{{ url()->previous() }}" class="btn btn-xs btn-info flex items-center">
|
||||
<i class="ki-filled ki-exit-left"></i> Back
|
||||
</a>
|
||||
</div>
|
||||
<div class="card-body relative flex flex-col h-[calc(100vh-4rem)]">
|
||||
<!-- Loading Spinner -->
|
||||
<div id="loading" class="absolute inset-0 flex items-center justify-center bg-gray-100 bg-opacity-50">
|
||||
<div class="loader ease-linear rounded-full border-4 border-t-4 border-gray-200 h-12 w-12"></div>
|
||||
<p class="text-gray-600 mt-2">Loading...</p>
|
||||
<div class="card w-full bg-white rounded-lg shadow-md h-100vh">
|
||||
<div class="card-header flex justify-between items-center">
|
||||
<h3 class="card-title uppercase">
|
||||
Laporan
|
||||
</h3>
|
||||
<a href="{{ url()->previous() }}" class="btn btn-xs btn-info flex items-center">
|
||||
<i class="ki-filled ki-exit-left"></i> Back
|
||||
</a>
|
||||
</div>
|
||||
@php
|
||||
$inspeksiId = null;
|
||||
$documentId = null;
|
||||
$jenisJaminanId = null;
|
||||
|
||||
<!-- Iframe -->
|
||||
<iframe id="reportIframe" style="display:none" width="100%" height="600px"></iframe>
|
||||
foreach ($permohonan->debiture->documents as $item) {
|
||||
if (!empty($item->inspeksi)) {
|
||||
$inspeksiId = $item->inspeksi[0]->id; // Asumsi mengambil inspeksi pertama
|
||||
}
|
||||
$documentId = $item->id;
|
||||
$jenisJaminanId = $item->jenis_jaminan_id;
|
||||
}
|
||||
@endphp
|
||||
<div class="card-body relative flex flex-col h-[calc(100vh-4rem)] overflow-hidden">
|
||||
<!-- Loading Spinner -->
|
||||
<div id="loading" class="absolute inset-0 flex items-center justify-center bg-gray-100 bg-opacity-50">
|
||||
<div class="loader ease-linear rounded-full border-4 border-t-4 border-gray-200 h-12 w-12"></div>
|
||||
<p class="text-gray-600 mt-2">Loading...</p>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between mt-4">
|
||||
<button id="zoomIn" class="btn btn-outline btn-primary">
|
||||
<i class="ki-filled ki-plus"></i>
|
||||
</button>
|
||||
<button id="zoomOut" class="btn btn-outline btn-warning">
|
||||
<i class="ki-filled ki-minus"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="iframe-container" style="width: 100%; border: 1px solid #ccc; height: 800px; overflow: hidden; margin: 10px;">
|
||||
<iframe id="reportIframe" width="100%" height="100%" style="border: none; transform-origin: top left;">
|
||||
</iframe>
|
||||
</div>
|
||||
|
||||
<div class="card-footer flex justify-end">
|
||||
<a href="{{ route('penilai.print-out') }}?permohonanId={{ $permohonan->id }}&documentId={{ $documentId }}&inspeksiId={{ $inspeksiId }}&jaminanId={{ $jenisJaminanId }}&statusLpj=0" class="btn btn-primary">
|
||||
<i class="ki-filled ki-printer"></i> Print
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
|
||||
@php
|
||||
$inspeksiId = null;
|
||||
$documentId = null;
|
||||
$jenisJaminanId = null;
|
||||
|
||||
foreach ($permohonan->debiture->documents as $item) {
|
||||
if (!empty($item->inspeksi)) {
|
||||
$inspeksiId = $item->inspeksi[0]->id; // Asumsi mengambil inspeksi pertama
|
||||
}
|
||||
$documentId = $item->id;
|
||||
$jenisJaminanId = $item->jenis_jaminan_id;
|
||||
}
|
||||
@endphp
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const iframe = document.getElementById('reportIframe');
|
||||
const loading = document.getElementById('loading');
|
||||
const url = `{{ route('penilai.print-out') }}?permohonanId={{ $permohonan->id }}&documentId={{ $documentId }}&inspeksiId={{ $inspeksiId }}&jaminanId={{ $jenisJaminanId }}&statusLpj=true`;
|
||||
const iframe = document.getElementById('reportIframe');
|
||||
const loading = document.getElementById('loading');
|
||||
const zoomInButton = document.getElementById('zoomIn');
|
||||
const zoomOutButton = document.getElementById('zoomOut');
|
||||
|
||||
// Show loading indicator
|
||||
loading.style.display = 'flex';
|
||||
fetch(url)
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error('Network response was not ok ' + response.statusText);
|
||||
}
|
||||
return response.text();
|
||||
})
|
||||
.then(html => {
|
||||
// Load the content into iframe
|
||||
const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
|
||||
iframeDoc.open();
|
||||
iframeDoc.write(html);
|
||||
iframeDoc.close();
|
||||
// Initial zoom level
|
||||
let zoomLevel = 1;
|
||||
const url = `{{ route('penilai.print-out') }}?permohonanId={{ $permohonan->id }}&documentId={{ $documentId }}&jaminanId={{ $jenisJaminanId }}&statusLpj=true`;
|
||||
|
||||
// Hide loading indicator and show iframe
|
||||
loading.style.display = 'none';
|
||||
iframe.style.display = 'block';
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('There has been a problem with your fetch operation:', error);
|
||||
loading.innerHTML = `<p class="text-red-500">Failed to load the report. Please try again later.</p>`;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
// Display the loading spinner
|
||||
loading.style.display = 'flex';
|
||||
|
||||
// Load the content into the iframe
|
||||
fetch(url)
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error('Network response was not ok ' + response.statusText);
|
||||
}
|
||||
return response.text();
|
||||
})
|
||||
.then(html => {
|
||||
// Load the content into the iframe
|
||||
const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
|
||||
iframeDoc.open();
|
||||
iframeDoc.write(html);
|
||||
iframeDoc.close();
|
||||
loading.style.display = 'none';
|
||||
iframe.style.display = 'block';
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Problem with fetch operation:', error);
|
||||
loading.innerHTML = `<p class="text-red-500">Failed to load the report. Please try again later.</p>`;
|
||||
});
|
||||
|
||||
// Zoom in function
|
||||
zoomInButton.addEventListener('click', function () {
|
||||
zoomLevel += 0.1; // Increase zoom level
|
||||
iframe.style.transform = `scale(${zoomLevel})`;
|
||||
iframe.style.transformOrigin = 'top left';
|
||||
iframe.style.width = `${100 / zoomLevel}%`;
|
||||
iframe.style.height = `${800 / zoomLevel}px`;
|
||||
});
|
||||
|
||||
// Zoom out function
|
||||
zoomOutButton.addEventListener('click', function () {
|
||||
zoomLevel = Math.max(0.5, zoomLevel - 0.1);
|
||||
iframe.style.transform = `scale(${zoomLevel})`;
|
||||
iframe.style.transformOrigin = 'top left';
|
||||
iframe.style.width = `${100 / zoomLevel}%`;
|
||||
iframe.style.height = `${800 / zoomLevel}px`;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* Loader styles */
|
||||
|
||||
@@ -78,86 +78,21 @@
|
||||
<input type="hidden" name="permohonan_id" value="{{ $permohonan->id }}">
|
||||
<input type="hidden" name="dokument_id" value="{{ request('dokument') }}">
|
||||
|
||||
<div class="card bg-white rounded-lg shadow-md">
|
||||
<div class="card rounded-lg shadow-md">
|
||||
<div class="card-body">
|
||||
<div class=" text-white py-4 flex items-center justify-between">
|
||||
<div class=" py-4 flex items-center justify-between">
|
||||
<h1 class="text-md font-medium text-gray-900">Rute Menuju Lokasi</h1>
|
||||
<button id="btnRute" type="button" class="btn btn-primary btn-sm">
|
||||
<i class="ki-filled ki-plus text-lg"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@if (isset($formFoto['rute_menuju_lokasi']))
|
||||
@foreach ($formFoto['rute_menuju_lokasi'] as $index => $photo)
|
||||
<div id="inputContainerRute" style="margin-top: 10px">
|
||||
<div class="flex w-full items-center justify-center gap-4 mb-4"
|
||||
id="photoContainer-{{ $index }}">
|
||||
<label class="form-label max-w-56">
|
||||
<span class="form-label">Foto Rute Menuju Lokasi {{ $index + 1 }}</span>
|
||||
</label>
|
||||
<div class="input-group w-full flex flex-col gap-2">
|
||||
<div class="preview-container">
|
||||
<img id="foto_rute-preview-{{ $index }}"
|
||||
src="{{ asset('storage/' . $photo['foto_rute']) }}"
|
||||
alt="Foto Rute {{ $index }}" class="mt-2 h-auto"
|
||||
style="display: block; width: 30rem;">
|
||||
</div>
|
||||
<div class="input-group w-full gap-2">
|
||||
<input class="name_rute" type="hidden" name="name_rute[]"
|
||||
value="rute_{{ $index }}">
|
||||
<input id="inputRute-{{ $index }}" type="file" name="foto_rute[]"
|
||||
class="file-input file-input-bordered w-full" accept="image/*"
|
||||
capture="camera"
|
||||
onchange="previewImage(this, 'foto_rute-preview-{{ $index }}')">
|
||||
|
||||
<div id="inputContainerRute" style="margin-top: 10px">
|
||||
|
||||
|
||||
<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>
|
||||
|
||||
<!-- Delete button to remove photo -->
|
||||
<button type="button" class="btn btn-danger btn-sm delete-btn" id="btnDelete">
|
||||
<i class="ki-filled ki-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
@else
|
||||
<div id="inputContainerRute" style="margin-top: 10px">
|
||||
<div class="flex w-full items-center justify-center gap-4 mb-4">
|
||||
<label class="form-label max-w-56">
|
||||
<span class="form-label">Foto Rute Menuju Lokasi</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="input-group w-full flex flex-col gap-2">
|
||||
<div class="preview-container">
|
||||
<img id="foto_rute-preview" src="" alt="Foto Rute" class="mt-2 h-auto"
|
||||
style="display: none; width: 30rem;">
|
||||
</div>
|
||||
<div class="input-group w-full gap-2">
|
||||
<input class="name_rute" type="hidden" name="name_rute[]" value="rute">
|
||||
<input id="inputRute" type="file" name="foto_rute[]"
|
||||
class="file-input file-input-bordered w-full" accept="image/*"
|
||||
capture="camera" onchange="previewImage(this, 'foto_rute-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>
|
||||
<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 class="alert text-danger text-sm"></span>
|
||||
</div>
|
||||
@endif
|
||||
<div id="inputContainerGerbang" style="margin-top: 10px">
|
||||
<div class="flex w-full items-center justify-center gap-4 mb-4">
|
||||
<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>
|
||||
@@ -183,12 +118,11 @@
|
||||
<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">
|
||||
<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">
|
||||
<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;">
|
||||
@@ -220,16 +154,19 @@
|
||||
</div>
|
||||
@endforeach
|
||||
@endif
|
||||
|
||||
</div>
|
||||
<button type="button" class="btn btn-primary btn-sm" id="btnAddMore" style="margin-top: 10px">
|
||||
<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 bg-white rounded-lg shadow-md">
|
||||
<div class="card rounded-lg shadow-md">
|
||||
<div class="card-body">
|
||||
<div class="text-white py-4 flex items-center justify-between">
|
||||
<div class=" py-4 flex items-center justify-between">
|
||||
<h1 class="text-md font-medium text-gray-900">Objek Jaminan</h1>
|
||||
</div>
|
||||
|
||||
@@ -250,113 +187,56 @@
|
||||
|
||||
@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))
|
||||
@php
|
||||
$objekViews = [];
|
||||
if ($kategori === 'tanah') {
|
||||
$objekViews = [
|
||||
['label' => 'Tampak Depan Objek', 'index' => 0],
|
||||
['label' => 'Tampak Samping Kiri', 'index' => 1],
|
||||
['label' => 'Tampak Samping Kanan', 'index' => 2],
|
||||
['label' => 'Nomor Rumah/Unit', 'index' => 3],
|
||||
];
|
||||
} elseif ($kategori === 'apartemen-kantor') {
|
||||
$objekViews = [
|
||||
['label' => 'Tampak Loby', 'index' => 0],
|
||||
['label' => 'Tampak Lift', 'index' => 1],
|
||||
['label' => 'Tampak Samping Kiri Unit', 'index' => 2],
|
||||
['label' => 'Tampak Samping Kanan Unit', 'index' => 3],
|
||||
['label' => 'Tampak Depan Unit', 'index' => 4],
|
||||
['label' => 'Nomor Unit', 'index' => 5],
|
||||
];
|
||||
} elseif ($kategori === 'kendaraan') {
|
||||
$objekViews = [
|
||||
['label' => 'Tampak Depan Objek', 'index' => 0],
|
||||
['label' => 'Tampak Kanan Objek', 'index' => 1],
|
||||
['label' => 'Tampak Samping Kiri Objek', 'index' => 2],
|
||||
['label' => 'Tampak Belakang Objek', 'index' => 3],
|
||||
['label' => 'Tampak Bagian Dalam', 'index' => 4],
|
||||
['label' => 'Nomor Panel Instrument', 'index' => 5],
|
||||
['label' => 'Tampak Odometer', 'index' => 6],
|
||||
['label' => 'Tampak Aksesoris Tambahan', 'index' => 7],
|
||||
['label' => 'Tampak Nomor Rangka', 'index' => 8],
|
||||
['label' => 'Tampak Nomor Mesin', 'index' => 9],
|
||||
[
|
||||
'label' => 'Tampak Penilai dan Pendamping di lapangan',
|
||||
'index' => 10,
|
||||
],
|
||||
];
|
||||
} elseif ($kategori === 'kapal') {
|
||||
$objekViews = [
|
||||
['label' => 'Tampak Depan', 'index' => 0],
|
||||
['label' => 'Tampak Kanan', 'index' => 1],
|
||||
['label' => 'Tampak Samping Kiri', 'index' => 2],
|
||||
['label' => 'Tampak Belakang', 'index' => 3],
|
||||
['label' => 'Tampak Bagian Dalam', 'index' => 4],
|
||||
['label' => 'Nomor Panel Instrument', 'index' => 5],
|
||||
['label' => 'Tampak Hours Meters', 'index' => 6],
|
||||
['label' => 'Tampak Aksesoris Tambahan', 'index' => 7],
|
||||
['label' => 'Tampak Nomor Rangka', 'index' => 8],
|
||||
['label' => 'Tampak Nomor Mesin', 'index' => 9],
|
||||
[
|
||||
'label' => 'Tampak Penilai dan Pendamping di lapangan',
|
||||
'index' => 10,
|
||||
],
|
||||
];
|
||||
} elseif ($kategori === 'mesin') {
|
||||
$objekViews = [
|
||||
['label' => 'Tampak Depan', 'index' => 0],
|
||||
['label' => 'Tampak Kanan', 'index' => 1],
|
||||
['label' => 'Tampak Samping Kiri', 'index' => 2],
|
||||
['label' => 'Tampak Belakang', 'index' => 3],
|
||||
['label' => 'Tampak Bagian Dalam', 'index' => 4],
|
||||
['label' => 'Nomor Panel Instrument', 'index' => 5],
|
||||
['label' => 'Tampak Hours Meters', 'index' => 6],
|
||||
['label' => 'Tampak Aksesoris Tambahan', 'index' => 7],
|
||||
['label' => 'Tampak Nomor Rangka', 'index' => 8],
|
||||
['label' => 'Tampak Nomor Mesin', 'index' => 9],
|
||||
[
|
||||
'label' => 'Foto Tampak Aksesoris Tambahan Lainnya',
|
||||
'index' => 10,
|
||||
],
|
||||
[
|
||||
'label' => 'Tampak Penilai dan Pendamping di lapangan',
|
||||
'index' => 10,
|
||||
],
|
||||
];
|
||||
}
|
||||
@endphp
|
||||
|
||||
|
||||
@if (count($objekViews) > 0)
|
||||
@foreach ($objekViews as $view)
|
||||
<div class="flex flex-wrap gap-4 {{ !$loop->first ? 'mt-2' : '' }}">
|
||||
<div class="flex w-full gap-4">
|
||||
<label class="form-label max-w-56"><span
|
||||
class="form-label">{{ $view['label'] }}</span></label>
|
||||
@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="{{ $view['label'] }}" />
|
||||
name="name_objek[]" value="{{ $item->name }}" />
|
||||
<div class="w-full grid gap-5">
|
||||
<img id="foto_object_jaminan_preview_{{ $view['index'] }}"
|
||||
src="{{ isset($formFoto['object_jaminan'][$view['index']]['foto_objek']) ? asset('storage/' . $formFoto['object_jaminan'][$view['index']]['foto_objek']) : '' }}"
|
||||
alt="{{ $view['label'] }}" class="mb-2 h-auto"
|
||||
style="{{ isset($formFoto['object_jaminan'][$view['index']]['foto_objek']) ? 'width: 30rem;' : 'display: none;' }}"
|
||||
@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;' }}"
|
||||
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="image/*" capture="camera"
|
||||
onchange="previewImage(this, 'foto_object_jaminan_preview_{{ $view['index'] }}')">
|
||||
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
|
||||
<i class="ki-outline ki-abstract-33"></i>
|
||||
Camera
|
||||
</button>
|
||||
</div>
|
||||
<textarea name="deskripsi_objek[]" class="textarea" rows="3" placeholder="Deskripsi">{{ isset($formFoto['object_jaminan'][$view['index']]) ? str_replace($view['label'] . ': ', '', $formFoto['object_jaminan'][$view['index']]['deskripsi_objek']) : '' }}</textarea>
|
||||
<textarea name="deskripsi_objek[]" class="textarea" rows="3" placeholder="Deskripsi">{{ $matchedFoto['deskripsi_objek'] ?? '' }}</textarea>
|
||||
</div>
|
||||
<span class="alert text-danger text-sm"></span>
|
||||
</div>
|
||||
<span class="alert text-danger text-sm"></span>
|
||||
</div>
|
||||
@endforeach
|
||||
@endif
|
||||
@@ -371,185 +251,83 @@
|
||||
@endif
|
||||
@endforeach
|
||||
|
||||
@if (isset($formFoto['foto_lantai_unit']))
|
||||
<div class="flex flex-wrap gap-4 w-full">
|
||||
<div class="w-full">
|
||||
<div class="text-white py-4 flex items-center justify-between w-full">
|
||||
<label class="form-label">
|
||||
<span class="form-label">Lantai</span>
|
||||
</label>
|
||||
<button type="button" id="btnAddLantai" class="btn btn-primary btn-sm">
|
||||
<i class="ki-filled ki-plus text-lg"></i> Tambah Lantai
|
||||
</button>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-4 w-full">
|
||||
<div class="w-full">
|
||||
<div class=" py-4 flex items-center justify-between w-full">
|
||||
<label class="form-label">
|
||||
<span class="form-label">Lantai</span>
|
||||
</label>
|
||||
|
||||
<div id="lantaiContainer" class="w-full">
|
||||
@foreach ($formFoto['foto_lantai_unit'] as $lantaiKey => $lantaiFotos)
|
||||
<div class="lantai-item w-full mb-4">
|
||||
<div class="flex w-full items-center justify-between">
|
||||
<label class="form-label">Lantai {{ $lantaiKey }}</label>
|
||||
<button type="button" class="btn btn-danger btn-sm btnRemoveLantai"
|
||||
style="{{ $lantaiKey == 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">
|
||||
@foreach ($lantaiFotos as $foto)
|
||||
@if (is_array($foto) && isset($foto['path']) && isset($foto['name']))
|
||||
<div class="preview-item relative">
|
||||
<img src="{{ asset('storage/' . $foto['path']) }}"
|
||||
alt="{{ $foto['name'] }}"
|
||||
class="w-full h-40 object-cover rounded-lg">
|
||||
<button type="button"
|
||||
class="absolute top-2 right-2 btn btn-sm btn-danger btn-icon btnRemoveFoto"
|
||||
data-path="{{ $foto['path'] }}">
|
||||
<i class="ki-solid ki-cross"></i>
|
||||
</button>
|
||||
</div>
|
||||
@else
|
||||
<p>Invalid photo data.</p>
|
||||
@endif
|
||||
@endforeach
|
||||
</div>
|
||||
<input type="file" name="foto_lantai_unit[{{ $lantaiKey }}][]"
|
||||
class="file-input hidden" multiple accept="image/*"
|
||||
onchange="handleFileInput(this)" data-lantai="{{ $lantaiKey }}">
|
||||
<button type="button" class="btn btn-light btn-sm btnUploadFiles mt-2">
|
||||
<i class="ki-outline ki-upload"></i> Unggah Gambar
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="lantaiContainer" class="w-full">
|
||||
</div>
|
||||
<div class="py-4 flex items-center justify-end w-full">
|
||||
<button type="button" id="btnAddLantai" class="btn btn-primary btn-sm">
|
||||
<i class="ki-filled ki-plus text-lg"></i> Tambah Lantai
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
<div class="flex flex-wrap gap-4 w-full">
|
||||
<div class="w-full">
|
||||
<div class="text-white py-4 flex items-center justify-between w-full">
|
||||
<label class="form-label">
|
||||
<span class="form-label">Lantai</span>
|
||||
</label>
|
||||
<button type="button" id="btnAddLantai" class="btn btn-primary btn-sm">
|
||||
<i class="ki-filled ki-plus text-lg"></i> Tambah Lantai
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div id="lantaiContainer" class="w-full">
|
||||
<!-- Template Lantai -->
|
||||
<div class="lantai-item w-full mb-4">
|
||||
<div class="flex w-full items-center justify-between">
|
||||
<label class="form-label">Lantai 1</label>
|
||||
<button type="button" class="btn btn-danger btn-sm btnRemoveLantai"
|
||||
style="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="foto_lantai_unit[1][]" class="file-input hidden"
|
||||
multiple accept="image/*" onchange="handleFileInput(this)"
|
||||
data-lantai="1">
|
||||
<button type="button" class="btn btn-light btn-sm btnUploadFiles mt-2">
|
||||
<i class="ki-outline ki-upload"></i> Unggah Gambar
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card bg-white rounded-lg shadow-md">
|
||||
<div class="card-body">
|
||||
<div class="text-white py-4 flex items-center justify-between">
|
||||
<h1 class="text-md font-medium text-gray-900">Lingkungan</h1>
|
||||
<button id="btnLingkungan" type="button" class="btn btn-primary btn-sm">
|
||||
<i class="ki-filled ki-plus text-lg"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@if (isset($formFoto['lingkungan']) && is_array($formFoto['lingkungan']) && count($formFoto['lingkungan']) > 0)
|
||||
@foreach ($formFoto['lingkungan'] as $key => $item)
|
||||
<div id="inputContainerLingkungan" style="margin-top: 10px">
|
||||
<div class="flex w-full items-center justify-center gap-4 mb-4">
|
||||
<label class="form-label max-w-56">
|
||||
<span class="form-label">Lingkungan {{ $key + 1 }}</span>
|
||||
</label>
|
||||
<div class="w-full grid gap-5">
|
||||
<img id="foto_lingkungan_preview_{{ $key }}"
|
||||
src="{{ asset('storage/' . old('foto_lingkungan.' . $key, $item['foto_lingkungan'])) }}"
|
||||
alt="Gambar Lingkungan" style="width: 30rem;">
|
||||
<input type="hidden" name="name_lingkungan[]" value="lingkungan">
|
||||
<div class="input-group w-full flex gap-2">
|
||||
<input id="inputLingkungan_{{ $key }}" type="file"
|
||||
name="foto_lingkungan[]" class="file-input file-input-bordered w-full"
|
||||
accept="image/*" capture="camera"
|
||||
onchange="previewImage(this, 'foto_lingkungan_preview_{{ $key }}')">
|
||||
<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>
|
||||
<span class="alert text-danger text-sm"></span>
|
||||
</div>
|
||||
@endforeach
|
||||
@else
|
||||
<div id="inputContainerLingkungan" style="margin-top: 10px">
|
||||
<div class="flex w-full items-center justify-center gap-4 mb-4">
|
||||
<label class="form-label max-w-56">
|
||||
<span class="form-label">Lingkungan</span>
|
||||
</label>
|
||||
<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 type="hidden" name="name_lingkungan[]" value="lingkungan">
|
||||
<img id="foto_lingkungan_preview_0"
|
||||
src="{{ isset($formFoto['lingkungan']) ? asset('storage/' . old('lingkungan', $formFoto['lingkungan'])) : '#' }}"
|
||||
alt="Gambar Lingkungan" style="width: 30rem;"
|
||||
onerror="this.style.display='none';">
|
||||
<input id="inputLingkungan_0" type="file" name="foto_lingkungan[]"
|
||||
class="file-input file-input-bordered w-full" accept="image/*" capture="camera"
|
||||
onchange="previewImage(this, 'foto_lingkungan_preview_0')">
|
||||
<input id="inputBasement" type="file" name="foto_basement"
|
||||
class="file-input file-input-bordered w-full" accept="image/*"
|
||||
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>
|
||||
<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 class="alert text-danger text-sm"></span>
|
||||
<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>
|
||||
@endif
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card bg-white rounded-lg shadow-md">
|
||||
<div class="card rounded-lg shadow-md">
|
||||
<div class="card-body">
|
||||
<div class=" text-white py-4 flex items-center justify-between">
|
||||
<div class=" py-4 flex items-center justify-between">
|
||||
<h1 class="text-md font-medium text-gray-900">Lingkungan</h1>
|
||||
</div>
|
||||
|
||||
<div id="inputContainerLingkungan" style="margin-top: 10px">
|
||||
</div>
|
||||
</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 w-full items-center justify-center gap-4 mb-4">
|
||||
|
||||
<label class="form-label max-w-56">
|
||||
<span class="form-label">Pendamping</span>
|
||||
</label>
|
||||
<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';"
|
||||
@@ -579,17 +357,11 @@
|
||||
</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>
|
||||
<div class="spinner-border spinner-border-sm text-light" role="status" style="display: none;"
|
||||
id="saveButtonSpinner">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -602,167 +374,86 @@
|
||||
@push('scripts')
|
||||
<script>
|
||||
// console.log('@json($formFoto)');
|
||||
|
||||
|
||||
// Inisialisasi saat dokumen siap
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const lantaiContainer = document.getElementById("lantaiContainer");
|
||||
const btnAddLantai = document.getElementById("btnAddLantai");
|
||||
// Transform and initialize files for each category
|
||||
|
||||
const updateRemoveButtonVisibility = () => {
|
||||
const lantaiItems = lantaiContainer.querySelectorAll(".lantai-item");
|
||||
lantaiItems.forEach((item, index) => {
|
||||
const btnRemove = item.querySelector(".btnRemoveLantai");
|
||||
const labelLantai = item.querySelector(".form-label");
|
||||
// Foto Lantai Unit
|
||||
const existingFilesLantai = @json($formFoto['foto_lantai_unit'] ?? []);
|
||||
const processedFilesLantai = Object.entries(existingFilesLantai || {}).flatMap(([lantaiIndex, files]) =>
|
||||
files.map(file => ({
|
||||
...file,
|
||||
item: lantaiIndex,
|
||||
url: file.path ? `/storage/${file.path}` : null
|
||||
}))
|
||||
);
|
||||
|
||||
// Update label lantai
|
||||
labelLantai.textContent = `Lantai ${index + 1}`;
|
||||
|
||||
// Tampilkan tombol hapus jika lebih dari 1 lantai
|
||||
btnRemove.style.display = lantaiItems.length > 1 ? "inline-block" : "none";
|
||||
});
|
||||
};
|
||||
|
||||
const attachEventListeners = (lantaiItem) => {
|
||||
// Event listener untuk tombol Hapus
|
||||
lantaiItem.querySelector(".btnRemoveLantai").addEventListener("click", () => {
|
||||
lantaiItem.remove();
|
||||
updateRemoveButtonVisibility();
|
||||
});
|
||||
|
||||
// Event listener untuk tombol Unggah Gambar
|
||||
lantaiItem.querySelector(".btnUploadFiles").addEventListener("click", () => {
|
||||
lantaiItem.querySelector(".file-input").click();
|
||||
});
|
||||
};
|
||||
|
||||
// Tambahkan lantai baru
|
||||
btnAddLantai.addEventListener("click", () => {
|
||||
const lantaiCount = lantaiContainer.children.length + 1;
|
||||
|
||||
const lantaiItem = document.createElement("div");
|
||||
lantaiItem.classList.add("lantai-item", "w-full", "mb-4");
|
||||
lantaiItem.innerHTML = `
|
||||
<div class="flex w-full items-center justify-between">
|
||||
<label class="form-label">Lantai ${lantaiCount}</label>
|
||||
<button type="button" class="btn btn-danger btn-sm btnRemoveLantai">
|
||||
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="foto_lantai_unit[${lantaiCount}][]"
|
||||
class="file-input hidden"
|
||||
multiple
|
||||
accept="image/*"
|
||||
data-lantai="${lantaiCount}"
|
||||
onchange="handleFileInput(this)">
|
||||
<button type="button" class="btn btn-light btn-sm btnUploadFiles">
|
||||
<i class="ki-outline ki-upload"></i> Unggah Gambar
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
lantaiContainer.appendChild(lantaiItem);
|
||||
attachEventListeners(lantaiItem);
|
||||
updateRemoveButtonVisibility();
|
||||
const lantaiUploader = new DynamicFileUploader({
|
||||
containerId: 'lantaiContainer',
|
||||
addButtonId: 'btnAddLantai',
|
||||
name: 'Lantai',
|
||||
fileInputName: 'foto_lantai_unit',
|
||||
existingFiles: processedFilesLantai,
|
||||
maxFiles: 10,
|
||||
accept: 'image/*',
|
||||
});
|
||||
|
||||
window.handleFileInput = (input) => {
|
||||
const lantaiNomor = input.getAttribute('data-lantai');
|
||||
const previewContainer = input.closest(".dropzone").querySelector(".preview-container");
|
||||
// Foto Lingkungan
|
||||
const existingFilesLingkungan = @json($formFoto['foto_lingkungan']['foto_lingkungan'] ?? []);
|
||||
const processedFilesLingkungan = existingFilesLingkungan.flatMap(files =>
|
||||
files.map(file => ({
|
||||
...file,
|
||||
url: file.path ? `/storage/${file.path}` : null
|
||||
}))
|
||||
);
|
||||
|
||||
// Tidak reset preview, tambahkan gambar baru
|
||||
Array.from(input.files).forEach((file) => {
|
||||
if (file.type.startsWith('image/')) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
const imgWrapper = document.createElement("div");
|
||||
imgWrapper.classList.add("relative", "preview-item");
|
||||
const lingkunganUploader = new DynamicFileUploader({
|
||||
containerId: 'inputContainerLingkungan',
|
||||
fileInputName: 'foto_lingkungan',
|
||||
|
||||
const img = document.createElement("img");
|
||||
img.src = e.target.result;
|
||||
img.alt = `Foto Lantai ${lantaiNomor}`;
|
||||
img.classList.add("rounded", "w-full", "h-40", "object-cover");
|
||||
|
||||
// Tombol hapus gambar
|
||||
const removeBtn = document.createElement("button");
|
||||
removeBtn.innerHTML = '<i class="ki-outline ki-trash"></i>';
|
||||
removeBtn.classList.add(
|
||||
"absolute", "top-0", "right-0",
|
||||
"btn", "btn-danger", "text-white",
|
||||
"rounded-full", "w-6", "h-6",
|
||||
"flex", "items-center", "justify-center"
|
||||
);
|
||||
removeBtn.addEventListener("click", () => {
|
||||
removeImageFromPreview(input, imgWrapper, file);
|
||||
});
|
||||
|
||||
imgWrapper.appendChild(img);
|
||||
imgWrapper.appendChild(removeBtn);
|
||||
previewContainer.appendChild(imgWrapper);
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function removeImageFromPreview(input, imgWrapper, fileToRemove) {
|
||||
// Hapus dari preview
|
||||
imgWrapper.remove();
|
||||
|
||||
// Hapus file dari input
|
||||
const dataTransfer = new DataTransfer();
|
||||
Array.from(input.files)
|
||||
.filter(file => file !== fileToRemove)
|
||||
.forEach(file => dataTransfer.items.add(file));
|
||||
|
||||
input.files = dataTransfer.files;
|
||||
}
|
||||
|
||||
window.handleDrop = (event) => {
|
||||
event.preventDefault();
|
||||
const dropzone = event.target.closest(".dropzone");
|
||||
const fileInput = dropzone.querySelector(".file-input");
|
||||
const previewContainer = dropzone.querySelector(".preview-container");
|
||||
const dataTransfer = new DataTransfer();
|
||||
|
||||
// Tambahkan file yang sudah ada di input
|
||||
Array.from(fileInput.files).forEach((file) => dataTransfer.items.add(file));
|
||||
|
||||
// Tambahkan file baru yang di-drop
|
||||
Array.from(event.dataTransfer.files).forEach((file) => {
|
||||
// Cek duplikasi
|
||||
const isDuplicate = Array.from(fileInput.files).some(
|
||||
existFile => existFile.name === file.name && existFile.size === file.size
|
||||
);
|
||||
|
||||
if (!isDuplicate) {
|
||||
dataTransfer.items.add(file);
|
||||
}
|
||||
});
|
||||
|
||||
fileInput.files = dataTransfer.files;
|
||||
handleFileInput(fileInput);
|
||||
};
|
||||
existingFiles: processedFilesLingkungan,
|
||||
maxFiles: 10,
|
||||
accept: 'image/*',
|
||||
});
|
||||
|
||||
|
||||
|
||||
// Inisialisasi lantai pertama
|
||||
const initialLantaiItem = lantaiContainer.querySelector(".lantai-item");
|
||||
if (initialLantaiItem) {
|
||||
attachEventListeners(initialLantaiItem);
|
||||
}
|
||||
|
||||
updateRemoveButtonVisibility();
|
||||
});
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
// Rute Menuju Lokasi
|
||||
const existingFilesRute = @json($formFoto['rute_menuju_lokasi']['rute_menuju_lokasi'] ?? []);
|
||||
const processedFilesRute = existingFilesRute.flatMap(files =>
|
||||
files.map(file => ({
|
||||
...file,
|
||||
url: file.path ? `/storage/${file.path}` : null
|
||||
}))
|
||||
);
|
||||
|
||||
const ruteUploader = new DynamicFileUploader({
|
||||
containerId: 'inputContainerRute',
|
||||
fileInputName: 'rute_menuju_lokasi',
|
||||
existingFiles: processedFilesRute,
|
||||
maxFiles: 10,
|
||||
accept: 'image/*',
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
function submitFoto() {
|
||||
showLoadingSwal('Mengirim data ke server...');
|
||||
|
||||
const formElement = $('#formFoto')[0];
|
||||
const formData = new FormData(formElement);
|
||||
for (let [key, value] of formData.entries()) {
|
||||
if (value instanceof File) {
|
||||
console.log(`${key}: File name = ${value.name}, File size = ${value.size}, File type = ${value.type}`);
|
||||
} else {
|
||||
console.log(`${key}: ${value}`);
|
||||
}
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: '{{ route('surveyor.storeFoto') }}',
|
||||
@@ -784,8 +475,8 @@
|
||||
confirmButtonText: 'OK'
|
||||
}).then((response) => {
|
||||
if (response.isConfirmed) {
|
||||
window.location.href =
|
||||
'{{ route('surveyor.show', ['id' => $permohonan->id]) }}';
|
||||
// window.location.href =
|
||||
// '{{ route('surveyor.show', ['id' => $permohonan->id]) }}';
|
||||
}
|
||||
console.log(response);
|
||||
|
||||
|
||||
@@ -80,6 +80,29 @@
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if (isset($header[1]) && $header[1] == 'foto-objek-jaminan')
|
||||
<div class="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
|
||||
<label class="form-label max-w-56">Form Kategori</label>
|
||||
<div class="flex flex-wrap items-baseline w-full">
|
||||
<select
|
||||
class="input tomselect w-full @error('kategori') border-danger bg-danger-light @enderror select2"
|
||||
name="kategori">
|
||||
|
||||
<option value="">Pilih Kategori</option>
|
||||
@foreach (['tanah', 'bangunan', 'kapal', 'kendaraan', 'mesin', 'pesawat', 'alat-berat', 'apartemen-kantor'] as $item)
|
||||
<option value="{{ $item }}"
|
||||
@if (isset($model) && $model->kategori == $item) {{ 'selected' }} @endif>
|
||||
{{ $item }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@error('form_kategori')
|
||||
<em class="alert text-danger text-sm">{{ $message }}</em>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
||||
<div class="flex justify-end">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
<span class="sort"> <span class="sort-label">{{ isset($header[0]) ? $header[0] : '' }}</span>
|
||||
<span class="sort-icon"> </span> </span>
|
||||
</th>
|
||||
@if ($header[1] == 'spek-bangunan')
|
||||
@if ($header[1] == 'spek-bangunan' || $header[1] == 'foto-objek-jaminan')
|
||||
<th class="min-w-[250px]" data-datatable-column="code">
|
||||
<span class="sort"> <span class="sort-label"> Kategori </span>
|
||||
<span class="sort-icon"> </span> </span>
|
||||
@@ -140,6 +140,15 @@
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
...(header == 'foto-objek-jaminan' && {
|
||||
kategories:{
|
||||
title: 'Kategori',
|
||||
render: (item, data)=>{
|
||||
return data.kategori;
|
||||
}
|
||||
}
|
||||
}),
|
||||
actions: {
|
||||
title: 'Status',
|
||||
render: (item, data) => {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -495,6 +495,7 @@
|
||||
'posisi-unit' => 'Posisi unit',
|
||||
'bentuk-unit' => 'Bentuk unit',
|
||||
'fasilitas-objek' => 'Fasilitas Umum Dekat Objek',
|
||||
'foto-objek-jaminan' => 'Foto Objek Jaminan',
|
||||
];
|
||||
|
||||
|
||||
|
||||
@@ -312,6 +312,7 @@ Route::middleware(['auth'])->group(function () {
|
||||
'posisi-unit' => 'Posisi unit',
|
||||
'bentuk-unit' => 'Bentuk unit',
|
||||
'fasilitas-objek' => 'Fasilitas Umum Dekat Objek',
|
||||
'foto-objek-jaminan' => 'Foto Objek Jaminan',
|
||||
|
||||
];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user