project-ta/resources/views/admin/penghuni/index.blade.php

1211 lines
42 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

@extends('layouts.app')
@section('content')
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; }
body { font-family: 'Plus Jakarta Sans', sans-serif; }
.page-header {
display: flex;
align-items: center;
gap: 14px;
margin-bottom: 28px;
}
.page-header-icon {
width: 46px;
height: 46px;
background: linear-gradient(135deg, #064e3b, #0d6e4f);
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 20px;
flex-shrink: 0;
box-shadow: 0 4px 14px rgba(6,78,59,0.3);
}
.page-header h1 {
font-size: 22px;
font-weight: 800;
color: #1a2e1a;
margin: 0;
line-height: 1.2;
}
.page-header p {
font-size: 13px;
color: #8a9e8a;
margin: 0;
}
/* ── ALERT ── */
.alert-success-custom {
background: #f0faf4;
border: 1px solid #a8e6be;
border-left: 4px solid #1a6e3a;
border-radius: 12px;
padding: 12px 16px;
color: #1a4e2a;
font-size: 13.5px;
font-weight: 500;
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 24px;
}
/* ── CARD ── */
.premium-card {
background: #ffffff;
border-radius: 16px;
border: 1px solid #e8f0e8;
box-shadow: 0 2px 12px rgba(0,0,0,0.05);
margin-bottom: 24px;
overflow: hidden;
}
.premium-card-header {
padding: 16px 22px;
background: #ffffff;
border-bottom: 1px solid #f0f5f0;
display: flex;
align-items: center;
justify-content: space-between;
}
.premium-card-header .header-left {
display: flex;
align-items: center;
gap: 10px;
}
.header-icon {
width: 34px;
height: 34px;
border-radius: 9px;
display: flex;
align-items: center;
justify-content: center;
font-size: 15px;
flex-shrink: 0;
}
.header-icon.green { background: #d1fae5; color: #064e3b; }
.header-icon.blue { background: #eaf0fb; color: #1a4e8e; }
.premium-card-header h6 {
font-size: 14px;
font-weight: 700;
color: #1a2e1a;
margin: 0;
}
.premium-card-body { padding: 20px 22px; }
/* ── KAVLING GRID ── */
.kavling-legend {
display: flex;
gap: 16px;
margin-bottom: 16px;
flex-wrap: wrap;
}
.legend-item {
display: flex;
align-items: center;
gap: 7px;
font-size: 12.5px;
color: #5a6e5a;
font-weight: 500;
}
.legend-dot {
width: 12px;
height: 12px;
border-radius: 4px;
}
.legend-dot.kosong { background: #064e3b; }
.legend-dot.terisi { background: #e53e3e; }
.kavling-grid {
display: grid;
grid-template-columns: repeat(10, 1fr);
gap: 8px;
}
.kavling {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 52px;
border-radius: 10px;
font-size: 13px;
font-weight: 700;
color: white;
cursor: pointer;
transition: transform 0.15s, box-shadow 0.15s;
position: relative;
user-select: none;
}
.kavling span.kav-label {
font-size: 9px;
font-weight: 500;
opacity: 0.75;
text-transform: uppercase;
letter-spacing: 0.5px;
margin-top: 1px;
}
.kosong {
background: linear-gradient(135deg, #064e3b, #0d6e4f);
box-shadow: 0 2px 8px rgba(6,78,59,0.3);
}
.terisi {
background: linear-gradient(135deg, #c53030, #e53e3e);
cursor: not-allowed;
box-shadow: 0 2px 8px rgba(197,48,48,0.25);
}
.kosong:hover {
box-shadow: 0 6px 18px rgba(6,78,59,0.4);
}
/* ══════════════════════════════════════
TABLE SCROLL WRAPPER
— membungkus seluruh DataTable wrapper
══════════════════════════════════════ */
.dt-scroll-outer {
width: 100%;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
/* scrollbar tipis agar tidak memakan ruang */
}
.dt-scroll-outer::-webkit-scrollbar {
height: 5px;
}
.dt-scroll-outer::-webkit-scrollbar-track {
background: #f0f5f0;
}
.dt-scroll-outer::-webkit-scrollbar-thumb {
background: #b0cdb0;
border-radius: 10px;
}
/* ── TABLE ── */
.premium-table {
width: 100%;
border-collapse: separate;
border-spacing: 0;
font-size: 13px;
}
/* Lebar minimum tabel agar semua kolom tampil */
#tablePenghuni { min-width: 1200px; }
#tableRumah { min-width: 880px; }
.premium-table thead tr th {
background: #f6fbf7;
color: #3a5a3a;
font-weight: 700;
font-size: 11.5px;
letter-spacing: 0.5px;
text-transform: uppercase;
padding: 11px 14px;
border-bottom: 2px solid #e0ede0;
white-space: nowrap;
}
.premium-table thead tr th:first-child { border-radius: 10px 0 0 0; }
.premium-table thead tr th:last-child { border-radius: 0 10px 0 0; }
.premium-table tbody tr td {
padding: 11px 14px;
border-bottom: 1px solid #f2f7f2;
color: #2a3a2a;
vertical-align: middle;
}
/* Kolom yang memang sebaiknya tidak wrap */
.premium-table tbody tr td.nowrap { white-space: nowrap; }
.premium-table tbody tr:hover td {
background: #f8fdf8;
}
.premium-table tbody tr:last-child td { border-bottom: none; }
/* badges */
.badge-pill-custom {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 4px 10px;
border-radius: 99px;
font-size: 11.5px;
font-weight: 600;
white-space: nowrap;
}
.badge-green { background: #eaf7f0; color: #1a6e3a; }
.badge-red { background: #fdf0f0; color: #c53030; }
.badge-yellow { background: #fdfbea; color: #7a6010; }
/* action buttons */
.btn-action {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 5px 11px;
border-radius: 8px;
font-size: 12px;
font-weight: 600;
cursor: pointer;
border: none;
text-decoration: none;
transition: opacity 0.15s, transform 0.1s;
}
.btn-action:hover { opacity: 0.85; transform: translateY(-1px); }
.btn-action:active { transform: translateY(0); }
.btn-action.info { background: #eaf0fb; color: #1a4e8e; }
.btn-action.warn { background: #fdf8ea; color: #8a6000; }
.btn-action.danger { background: #fdf0f0; color: #c53030; }
.btn-group-action {
display: flex;
align-items: center;
gap: 4px;
flex-wrap: nowrap;
}
/* ── MODAL ── */
.modal-content {
border-radius: 16px !important;
border: none !important;
overflow: hidden;
box-shadow: 0 20px 60px rgba(0,0,0,0.15) !important;
}
.modal-header-custom {
background: linear-gradient(135deg, #064e3b 0%, #065f46 50%, #10b981 100%);
padding: 18px 24px;
display: flex;
align-items: center;
gap: 12px;
}
.modal-header-custom h5 {
color: white;
font-size: 15px;
font-weight: 700;
margin: 0;
}
.modal-header-custom .modal-icon {
width: 34px;
height: 34px;
background: rgba(255,255,255,0.18);
border-radius: 9px;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 16px;
}
.modal-detail-body { padding: 22px 24px; }
.modal-detail-body button[type="submit"] {
background: linear-gradient(135deg, #064e3b, #10b981) !important;
}
.detail-row {
display: flex;
align-items: flex-start;
gap: 12px;
padding: 10px 0;
border-bottom: 1px solid #f2f7f2;
}
.detail-row:last-child { border-bottom: none; }
.detail-row .detail-icon {
width: 30px;
height: 30px;
background: #ecfdf5;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
color: #064e3b;
font-size: 13px;
flex-shrink: 0;
margin-top: 1px;
}
.detail-row .detail-label {
font-size: 11px;
color: #8a9e8a;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
margin-bottom: 2px;
}
.detail-row .detail-value {
font-size: 13.5px;
color: #1a2e1a;
font-weight: 600;
}
.detail-section-title {
font-size: 11px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 1px;
color: #064e3b;
padding: 14px 0 6px;
border-top: 2px dashed #d1fae5;
margin-top: 6px;
}
/* ══════════════════════════════════════
DATATABLE OVERRIDES
══════════════════════════════════════ */
.dataTables_wrapper {
padding: 0;
}
/* Baris atas: length + filter */
.dataTables_wrapper > div:first-child {
padding: 14px 22px 10px;
border-bottom: 1px solid #f0f5f0;
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 8px;
}
.dataTables_wrapper .dataTables_length label,
.dataTables_wrapper .dataTables_filter label {
font-size: 13px;
color: #5a6e5a;
font-weight: 500;
display: flex;
align-items: center;
gap: 8px;
margin: 0;
}
.dataTables_wrapper .dataTables_filter input {
border-radius: 9px;
border: 1.5px solid #e0ede0;
padding: 6px 12px;
font-size: 13px;
outline: none;
margin-left: 6px;
}
.dataTables_wrapper .dataTables_filter input:focus {
border-color: #1a6e3a;
box-shadow: 0 0 0 3px rgba(26,110,58,0.12);
}
.dataTables_wrapper .dataTables_length select {
border-radius: 9px;
border: 1.5px solid #e0ede0;
padding: 5px 10px;
font-size: 13px;
margin: 0 6px;
}
/* Baris bawah: info + paginate */
.dataTables_wrapper > div:last-child {
padding: 14px 22px;
border-top: 1px solid #f0f5f0;
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 8px;
}
.dataTables_wrapper .dataTables_info {
font-size: 12.5px;
color: #8a9e8a;
font-weight: 500;
padding: 0;
line-height: 36px;
}
div.dataTables_wrapper div.dataTables_paginate {
display: flex !important;
align-items: center;
gap: 3px;
margin: 0;
padding: 0;
}
div.dataTables_wrapper div.dataTables_paginate ul.pagination { margin: 0; }
div.dataTables_wrapper div.dataTables_paginate .paginate_button {
box-sizing: border-box !important;
width: 34px !important;
height: 34px !important;
min-width: 34px !important;
border-radius: 50% !important;
padding: 0 !important;
margin: 0 2px !important;
font-size: 13px !important;
font-weight: 600 !important;
border: 1.5px solid #e0ede0 !important;
color: #5a6e5a !important;
background: #ffffff !important;
display: inline-flex !important;
align-items: center !important;
justify-content: center !important;
line-height: 1 !important;
cursor: pointer !important;
text-decoration: none !important;
transition: all 0.15s ease !important;
box-shadow: none !important;
}
div.dataTables_wrapper div.dataTables_paginate .paginate_button:hover:not(.disabled):not(.current) {
background: #f0f7ff !important;
border-color: #90caf9 !important;
color: #1976d2 !important;
box-shadow: none !important;
}
div.dataTables_wrapper div.dataTables_paginate .paginate_button.current,
div.dataTables_wrapper div.dataTables_paginate .paginate_button.current:hover {
background: #ffffff !important;
border: 2px solid #2196f3 !important;
color: #2196f3 !important;
box-shadow: 0 0 0 3px rgba(33,150,243,0.12) !important;
}
div.dataTables_wrapper div.dataTables_paginate .paginate_button.disabled,
div.dataTables_wrapper div.dataTables_paginate .paginate_button.disabled:hover {
color: #c8d8c8 !important;
border-color: #edf5ed !important;
background: #fafafa !important;
cursor: default !important;
box-shadow: none !important;
}
/* ═══════════════════════════════════════════
RESPONSIVE
═══════════════════════════════════════════ */
@media (max-width: 992px) {
.page-header h1 { font-size: 18px; }
.page-header p { font-size: 12px; }
.kavling-grid { grid-template-columns: repeat(6, 1fr); gap: 6px; }
.kavling { height: 48px; font-size: 12px; }
.kavling span.kav-label { font-size: 8px; }
.dataTables_wrapper > div:first-child,
.dataTables_wrapper > div:last-child {
flex-direction: column;
align-items: flex-start !important;
padding: 12px 16px;
}
.dataTables_wrapper .dataTables_filter input { width: 100%; margin-left: 0; }
.dataTables_wrapper .dataTables_filter label { flex-direction: column; align-items: flex-start; width: 100%; }
.premium-card-body { padding: 16px; }
.premium-card-header { padding: 14px 16px; }
}
@media (max-width: 576px) {
.container-fluid { padding-left: 12px; padding-right: 12px; }
.page-header { gap: 10px; margin-bottom: 20px; }
.page-header-icon { width: 38px; height: 38px; font-size: 16px; border-radius: 10px; }
.page-header h1 { font-size: 15px; }
.page-header p { font-size: 11px; }
.alert-success-custom { font-size: 12.5px; padding: 10px 14px; }
.premium-card { border-radius: 12px; margin-bottom: 16px; }
.premium-card-header { padding: 12px 14px; }
.premium-card-header h6 { font-size: 13px; }
.premium-card-body { padding: 0; }
.kavling-grid { grid-template-columns: repeat(5, 1fr); gap: 5px; }
.kavling { height: 42px; font-size: 11px; border-radius: 8px; }
.kavling span.kav-label { display: none; }
.kavling-legend { gap: 12px; }
.legend-item { font-size: 11.5px; }
.premium-card-body.kav-body { padding: 12px; }
.badge-pill-custom { font-size: 10.5px; padding: 3px 8px; }
.btn-action { padding: 4px 8px; font-size: 11px; gap: 3px; }
.dataTables_wrapper > div:first-child,
.dataTables_wrapper > div:last-child {
flex-direction: column;
align-items: flex-start !important;
padding: 10px 12px;
}
.dataTables_wrapper .dataTables_info { line-height: 1.5; }
div.dataTables_wrapper div.dataTables_paginate .paginate_button {
width: 30px !important;
height: 30px !important;
min-width: 30px !important;
font-size: 12px !important;
}
.modal-dialog { margin: 10px; }
.modal-content { border-radius: 12px !important; }
.modal-header-custom { padding: 14px 16px; }
.modal-header-custom h5 { font-size: 13.5px; }
.modal-detail-body { padding: 16px; }
.detail-row .detail-value { font-size: 13px; }
}
@media (max-width: 380px) {
.kavling-grid { grid-template-columns: repeat(5, 1fr); gap: 4px; }
.kavling { height: 36px; font-size: 10px; border-radius: 6px; }
.page-header h1 { font-size: 14px; }
}
{{-- tambah style dulu di dalam <style> --}}
.sudah-input {
background: linear-gradient(135deg, #92400e, #b45309);
cursor: not-allowed;
box-shadow: 0 2px 8px rgba(146,64,14,0.25);
}
.legend-dot.sudah { background: #b45309; }
/* Legend tambahan */
.legend-dot.diinput { background: #fde68a; }
/* Denah cluster */
.denah-clusters {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0 24px;
}
.cluster-section { margin-bottom: 16px; }
.cluster-title {
font-size: 11px;
font-weight: 600;
color: #5a6e5a;
text-transform: uppercase;
letter-spacing: .5px;
margin-bottom: 6px;
}
.kavling-row {
display: flex;
flex-wrap: wrap;
gap: 5px;
}
.kavling-item {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 46px;
height: 46px;
border-radius: 8px;
cursor: pointer;
border: 1.5px solid transparent;
transition: transform .1s, box-shadow .1s;
user-select: none;
}
.kavling-item .kav-num { font-size: 11px; font-weight: 700; line-height: 1; }
.kavling-item .kav-lbl { font-size: 7px; font-weight: 500; opacity: .75; margin-top: 2px; text-transform: uppercase; }
.kavling-item.kosong { background: #d1fae5; border-color: #6ee7b7; color: #064e3b; }
.kavling-item.kosong:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(6,78,59,.25); }
.kavling-item.diinput { background: #fde68a; border-color: #f59e0b; color: #78350f; cursor: not-allowed; }
.kavling-item.terisi { background: #fecaca; border-color: #f87171; color: #7f1d1d; cursor: not-allowed; }
@media (max-width: 768px) {
.denah-clusters { grid-template-columns: 1fr; }
.kavling-item { width: 40px; height: 40px; }
}
</style>
<div class="container-fluid">
{{-- PAGE HEADER --}}
<div class="page-header">
<div class="page-header-icon"><i class="fas fa-home"></i></div>
<div>
<h1>Kelola Data Perumahan</h1>
<p>Manajemen kavling, penghuni, dan rumah</p>
</div>
</div>
@if(session('success'))
<div class="alert-success-custom">
<i class="fas fa-check-circle"></i>
{{ session('success') }}
</div>
@endif
@if(session('error'))
<div class="alert-success-custom" style="background:#fdf0f0; border-color:#fca5a5; border-left-color:#c53030; color:#c53030;">
<i class="fas fa-exclamation-circle"></i>
{{ session('error') }}
</div>
@endif
{{-- KAVLING VISUAL --}}
<div class="premium-card">
<div class="premium-card-header">
<div class="header-left">
<div class="header-icon green"><i class="fas fa-th"></i></div>
<h6>Denah Kavling</h6>
</div>
</div>
<div class="premium-card-body kav-body">
<div class="kavling-legend">
<div class="legend-item"><div class="legend-dot kosong"></div> Kosong tersedia</div>
<div class="legend-item"><div class="legend-dot diinput"></div> Sudah Diinput belum ada penghuni</div>
<div class="legend-item"><div class="legend-dot terisi"></div> Terisi ada penghuni</div>
</div>
@php
$clusterDef = [
['name' => 'Cluster Gardenia Blok A', 'blok' => 'A', 'max' => 24],
['name' => 'Cluster Gardenia Blok B', 'blok' => 'B', 'max' => 20],
['name' => 'Cluster Gardenia Blok C', 'blok' => 'C', 'max' => 24],
['name' => 'Cluster Gardenia Blok D', 'blok' => 'D', 'max' => 20],
['name' => 'Cluster Gardenia Blok E', 'blok' => 'E', 'max' => 20],
['name' => 'Cluster Gardenia Blok F', 'blok' => 'F', 'max' => 21],
['name' => 'Cluster Gardenia Blok G', 'blok' => 'G', 'max' => 32],
['name' => 'Cluster Edelweis Blok H', 'blok' => 'H', 'max' => 37],
['name' => 'Cluster Edelweis Blok I', 'blok' => 'I', 'max' => 31],
['name' => 'Blok J', 'blok' => 'J', 'max' => 17],
['name' => 'Blok K', 'blok' => 'K', 'max' => 16],
['name' => 'Blok L', 'blok' => 'L', 'max' => 10],
];
@endphp
<div class="denah-clusters">
@foreach($clusterDef as $cl)
<div class="cluster-section">
<div class="cluster-title">{{ $cl['name'] }}</div>
<div class="kavling-row">
@for($i = 1; $i <= $cl['max']; $i++)
@php
$dataRumah = $rumahList->where('blok', $cl['blok'])->where('no_rumah', $i)->first();
if (!$dataRumah) {
$kelas = 'kosong';
$lbl = 'Kosong';
} elseif ($dataRumah->status == 'Terisi') {
$kelas = 'terisi';
$lbl = 'Terisi';
} else {
$kelas = 'diinput';
$lbl = 'Input';
}
@endphp
<div class="kavling-item {{ $kelas }}"
@if($kelas == 'kosong')
onclick="pilihKavling('{{ $cl['blok'] }}', {{ $i }})"
@endif
title="{{ $cl['blok'] }}{{ $i }} — {{ $lbl }}">
<span class="kav-num">{{ $cl['blok'] }}{{ $i }}</span>
<span class="kav-lbl">{{ $lbl }}</span>
</div>
@endfor
</div>
</div>
@endforeach
</div>
</div>
</div>
{{-- DATA PENGHUNI --}}
<div class="premium-card">
<div class="premium-card-header">
<div class="header-left">
<div class="header-icon blue"><i class="fas fa-users"></i></div>
<h6>Data Penghuni</h6>
</div>
</div>
<div class="premium-card-body" style="padding:0;">
{{-- Wrapper scroll horizontal membungkus SELURUH DataTable --}}
<div class="dt-scroll-outer" id="wrap-penghuni">
<table class="premium-table" id="tablePenghuni">
<thead>
<tr>
<th>#</th>
<th>Nama</th>
<th>No KTP</th>
<th>Email</th>
<th>No HP</th>
<th>Alamat</th>
{{-- Header --}}
<th>Cluster</th>
<th>Blok</th>
<th>No Rumah</th>
{{-- Body --}}
@php
$clusterMap = [
'A'=>'Gardenia','B'=>'Gardenia','C'=>'Gardenia',
'D'=>'Gardenia','E'=>'Gardenia','F'=>'Gardenia','G'=>'Gardenia',
'H'=>'Edelweis','I'=>'Edelweis',
'J'=>'J','K'=>'K','L'=>'L',
];
$blok = $p->rumah->blok ?? '-';
$cluster = isset($clusterMap[$blok]) ? 'Cluster '.$clusterMap[$blok] : '-';
@endphp
<th>Status</th>
<th>Status Huni</th>
<th>Tgl Masuk</th>
<th>Tgl Keluar</th>
<th>Aksi</th>
</tr>
</thead>
<tbody>
@forelse($penghuni as $p)
@php
$clusterMap = [
'A'=>'Gardenia','B'=>'Gardenia','C'=>'Gardenia',
'D'=>'Gardenia','E'=>'Gardenia','F'=>'Gardenia','G'=>'Gardenia',
'H'=>'Edelweis','I'=>'Edelweis',
'J'=>'J','K'=>'K','L'=>'L',
];
$blok = $p->rumah->blok ?? '-';
$cluster = isset($clusterMap[$blok]) ? 'Cluster '.$clusterMap[$blok] : '-';
@endphp
<tr>
<td class="nowrap">{{ $loop->iteration }}</td>
<td class="nowrap"><strong>{{ $p->nama }}</strong></td>
<td class="nowrap">{{ $p->no_ktp }}</td>
<td class="nowrap">{{ $p->email }}</td>
<td class="nowrap">{{ $p->telepon }}</td>
<td>{{ $p->alamat }}</td>
<td class="nowrap">{{ $cluster }}</td>
<td class="nowrap">{{ $blok }}</td>
<td class="nowrap">{{ $p->rumah->no_rumah ?? '-' }}</td>
<td class="nowrap">
@if($p->status_huni == 'Kontrak' && $p->tanggal_keluar && now()->gt($p->tanggal_keluar))
<span class="badge-pill-custom badge-red"><i class="fas fa-times-circle" style="font-size:10px"></i> Tidak Aktif</span>
@else
<span class="badge-pill-custom badge-green"><i class="fas fa-check-circle" style="font-size:10px"></i> Aktif</span>
@endif
</td>
<td class="nowrap"><span class="badge-pill-custom badge-yellow">{{ $p->status_huni }}</span></td>
<td class="nowrap">{{ \Carbon\Carbon::parse($p->tanggal_masuk)->format('d-m-Y') }}</td>
<td class="nowrap">{{ $p->tanggal_keluar ?? '-' }}</td>
<td class="nowrap">
<div class="btn-group-action">
<a href="{{ route('penghuni.edit', $p->id) }}" class="btn-action warn">
<i class="fas fa-edit" style="font-size:11px"></i> Edit
</a>
<a href="{{ route('penghuni.delete', $p->id) }}" class="btn-action danger"
onclick="return confirm('Yakin hapus?')">
<i class="fas fa-trash" style="font-size:11px"></i> Hapus
</a>
</div>
</td>
</tr>
@empty
<tr>
<td colspan="14" style="text-align:center; padding:32px; color:#aaa;">
<i class="fas fa-inbox" style="font-size:28px; display:block; margin-bottom:8px; opacity:0.4;"></i>
Belum ada data penghuni
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
</div>
</div>
{{-- DATA RUMAH --}}
<div class="premium-card">
<div class="premium-card-header">
<div class="header-left">
<div class="header-icon green"><i class="fas fa-house-user"></i></div>
<h6>Data Rumah</h6>
</div>
</div>
<div class="premium-card-body" style="padding:0;">
<div class="dt-scroll-outer" id="wrap-rumah">
<table class="premium-table" id="tableRumah">
<thead>
<tr>
<th>#</th>
<th>Cluster</th>
<th>Blok</th>
<th>No Rumah</th>
<th>Status</th>
<th>Luas Tanah</th>
<th>Harga</th>
<th>Keterangan</th>
<th>Aksi</th>
</tr>
</thead>
<tbody>
@forelse($rumahList as $r)
@php
$clusterMap = [
'A'=>'Gardenia','B'=>'Gardenia','C'=>'Gardenia',
'D'=>'Gardenia','E'=>'Gardenia','F'=>'Gardenia','G'=>'Gardenia',
'H'=>'Edelweis','I'=>'Edelweis',
'J'=>'J','K'=>'K','L'=>'L',
];
$blokR = $r->blok;
$clusterR = isset($clusterMap[$blokR]) ? 'Cluster '.$clusterMap[$blokR] : '-';
@endphp
<tr>
<td class="nowrap">{{ $loop->iteration }}</td>
<td class="nowrap">{{ $clusterR }}</td>
<td class="nowrap"><strong>{{ $r->blok }}</strong></td>
<td class="nowrap">{{ $r->no_rumah }}</td>
<td class="nowrap">
@if($r->status == 'Kosong')
<span class="badge-pill-custom badge-green"><i class="fas fa-check-circle" style="font-size:10px"></i> Kosong</span>
@else
<span class="badge-pill-custom badge-red"><i class="fas fa-times-circle" style="font-size:10px"></i> Terisi</span>
@endif
</td>
<td class="nowrap">{{ $r->luas_tanah ? $r->luas_tanah . ' m²' : '-' }}</td>
<td class="nowrap">
@if($r->harga)
<strong>Rp {{ number_format($r->harga, 0, ',', '.') }}</strong>
@else -
@endif
</td>
<td>{{ $r->keterangan ?? '-' }}</td>
<td class="nowrap">
<div class="btn-group-action">
<button class="btn-action info btn-detail"
data-blok="{{ $r->blok }}"
data-nomor="{{ $r->no_rumah }}"
data-status="{{ $r->status }}"
data-nama="{{ $r->penghuni->nama ?? 'Kosong' }}"
data-email="{{ $r->penghuni->email ?? '-' }}"
data-telepon="{{ $r->penghuni->telepon ?? '-' }}">
<i class="fas fa-eye" style="font-size:11px"></i> Detail
</button>
<a href="{{ route('rumah.edit', $r->id) }}" class="btn-action warn">
<i class="fas fa-edit" style="font-size:11px"></i> Edit
</a>
<form action="{{ route('rumah.destroy', $r->id) }}" method="POST" style="display:inline;">
@csrf
@method('DELETE')
<button class="btn-action danger" onclick="return confirm('Yakin hapus?')">
<i class="fas fa-trash" style="font-size:11px"></i> Hapus
</button>
</form>
</div>
</td>
</tr>
@empty
<tr>
<td colspan="9" style="text-align:center; padding:32px; color:#aaa;">
<i class="fas fa-inbox" style="font-size:28px; display:block; margin-bottom:8px; opacity:0.4;"></i>
Belum ada data rumah
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
</div>
</div>
</div>
{{-- MODAL DETAIL --}}
<div class="modal fade" id="modalDetail">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header-custom">
<div class="modal-icon"><i class="fas fa-home"></i></div>
<h5>Detail Rumah &amp; Penghuni</h5>
</div>
<div class="modal-detail-body">
<div class="detail-row">
<div class="detail-icon"><i class="fas fa-map-marker-alt"></i></div>
<div>
<div class="detail-label">Blok</div>
<div class="detail-value" id="d_blok"></div>
</div>
</div>
<div class="detail-row">
<div class="detail-icon"><i class="fas fa-hashtag"></i></div>
<div>
<div class="detail-label">Nomor Rumah</div>
<div class="detail-value" id="d_nomor"></div>
</div>
</div>
<div class="detail-row">
<div class="detail-icon"><i class="fas fa-info-circle"></i></div>
<div>
<div class="detail-label">Status</div>
<div class="detail-value" id="d_status"></div>
</div>
</div>
<div class="detail-section-title"><i class="fas fa-user" style="margin-right:6px;"></i>Data Penghuni</div>
<div class="detail-row">
<div class="detail-icon"><i class="fas fa-user"></i></div>
<div>
<div class="detail-label">Nama</div>
<div class="detail-value" id="d_nama"></div>
</div>
</div>
<div class="detail-row">
<div class="detail-icon"><i class="fas fa-envelope"></i></div>
<div>
<div class="detail-label">Email</div>
<div class="detail-value" id="d_email"></div>
</div>
</div>
<div class="detail-row">
<div class="detail-icon"><i class="fas fa-phone"></i></div>
<div>
<div class="detail-label">No HP</div>
<div class="detail-value" id="d_telepon"></div>
</div>
</div>
<div style="text-align:right; margin-top:18px;">
<button class="btn-action info" data-dismiss="modal">
<i class="fas fa-times" style="font-size:11px"></i> Tutup
</button>
</div>
</div>
</div>
</div>
</div>
{{-- MODAL TAMBAH RUMAH --}}
<div class="modal fade" id="modalRumah">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<form action="{{ route('rumah.store') }}" method="POST" enctype="multipart/form-data">
@csrf
<div class="modal-header-custom">
<div class="modal-icon"><i class="fas fa-plus"></i></div>
<h5>Tambah Data Rumah</h5>
</div>
<div class="modal-detail-body">
<div style="display:grid; gap:12px;">
<div>
<div class="detail-label" style="margin-bottom:5px;">Blok</div>
<select name="blok" id="blok_input" class="form-control" required
style="border-radius:9px; border:1.5px solid #e0ede0; font-size:13.5px; padding:9px 12px;"
onchange="updateNoRumah()">
<option value="">-- Pilih Blok --</option>
<option value="A">Cluster Gardenia Blok A (124)</option>
<option value="B">Cluster Gardenia Blok B (120)</option>
<option value="C">Cluster Gardenia Blok C (124)</option>
<option value="D">Cluster Gardenia Blok D (120)</option>
<option value="E">Cluster Gardenia Blok E (120)</option>
<option value="F">Cluster Gardenia Blok F (121)</option>
<option value="G">Cluster Gardenia Blok G (132)</option>
<option value="H">Cluster Edelweis Blok H (137)</option>
<option value="I">Cluster Edelweis Blok I (131)</option>
<option value="J">Blok J (117)</option>
<option value="K">Blok K (116)</option>
<option value="L">Blok L (110)</option>
</select>
</div>
<div>
<div class="detail-label" style="margin-bottom:5px;">No Rumah</div>
<select name="no_rumah" id="no_rumah" class="form-control" required
style="border-radius:9px; border:1.5px solid #e0ede0; font-size:13.5px; padding:9px 12px;">
<option value="">-- Pilih blok dulu --</option>
</select>
</div>
<div>
<div class="detail-label" style="margin-bottom:5px;">Status</div>
<select name="status" class="form-control" style="border-radius:9px; border:1.5px solid #e0ede0; font-size:13.5px; padding:9px 12px;">
<option value="Kosong">Kosong</option>
<option value="Terisi">Terisi</option>
</select>
</div>
<div>
<div class="detail-label" style="margin-bottom:5px;">Luas Tanah ()</div>
<input type="number" name="luas_tanah" class="form-control" placeholder="Luas tanah" style="border-radius:9px; border:1.5px solid #e0ede0; font-size:13.5px; padding:9px 12px;">
</div>
<div>
<div class="detail-label" style="margin-bottom:5px;">Harga</div>
<input type="number" name="harga" class="form-control" placeholder="Harga jual" style="border-radius:9px; border:1.5px solid #e0ede0; font-size:13.5px; padding:9px 12px;">
</div>
<div>
<div class="detail-label" style="margin-bottom:5px;">Keterangan</div>
<textarea name="keterangan" class="form-control" placeholder="Keterangan tambahan" rows="2" style="border-radius:9px; border:1.5px solid #e0ede0; font-size:13.5px; padding:9px 12px; resize:none;"></textarea>
</div>
<div>
<div class="detail-label" style="margin-bottom:5px;">Foto Kavling</div>
<input type="file" name="foto" class="form-control" id="fotoInput" accept="image/*" style="border-radius:9px; border:1.5px solid #e0ede0; font-size:13px; padding:8px 12px;">
<div class="text-center mt-2">
<img id="previewFoto" src="" style="max-height:140px; display:none; border-radius:10px; object-fit:cover;" class="img-fluid">
</div>
</div>
</div>
<div style="text-align:right; margin-top:18px; display:flex; gap:8px; justify-content:flex-end;">
<button type="button" class="btn-action info" data-dismiss="modal">Batal</button>
<button type="submit" class="btn-action" style="background:linear-gradient(135deg,#1a6e3a,#2e9e58); color:white;">
<i class="fas fa-save" style="font-size:11px"></i> Simpan
</button>
</div>
</div>
</form>
</div>
</div>
</div>
<script>
// Mapping blok → max nomor
const blokMax = {
'A':24,'B':20,'C':24,'D':20,'E':20,
'F':21,'G':32,'H':37,'I':31,'J':17,'K':16,'L':10
};
function updateNoRumah(selectedNo) {
var blok = document.getElementById('blok_input').value;
var select = document.getElementById('no_rumah');
select.innerHTML = '';
if (!blok) {
select.innerHTML = '<option value="">-- Pilih blok dulu --</option>';
return;
}
var max = blokMax[blok] || 10;
var defaultOpt = document.createElement('option');
defaultOpt.value = '';
defaultOpt.textContent = '-- Pilih No Rumah --';
select.appendChild(defaultOpt);
for (var i = 1; i <= max; i++) {
var opt = document.createElement('option');
opt.value = i;
opt.textContent = i;
if (selectedNo && parseInt(selectedNo) === i) opt.selected = true;
select.appendChild(opt);
}
}
function pilihKavling(blok, no) {
// Set blok
document.getElementById('blok_input').value = blok;
// Generate opsi no rumah sesuai blok, lalu pilih nomor yg diklik
updateNoRumah(no);
$('#modalRumah').modal('show');
}
document.getElementById('fotoInput') && document.getElementById('fotoInput').addEventListener('change', function(e) {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = function(ev) {
const img = document.getElementById('previewFoto');
img.src = ev.target.result;
img.style.display = 'block';
};
reader.readAsDataURL(file);
});
document.getElementById('fotoInput') && document.getElementById('fotoInput').addEventListener('change', function(e) {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = function(ev) {
const img = document.getElementById('previewFoto');
img.src = ev.target.result;
img.style.display = 'block';
};
reader.readAsDataURL(file);
});
</script>
@endsection
@section('scripts')
<script>
$(document).ready(function () {
if ($.fn.DataTable) {
// Inisialisasi DataTable — TANPA scrollX agar tidak konflik dengan wrapper custom
var dtPenghuni = $('#tablePenghuni').DataTable({
pageLength: 10,
lengthMenu: [5, 10, 25, 50],
dom: '<"d-flex justify-content-between align-items-center flex-wrap px-3 pt-3"lf>t<"d-flex justify-content-between align-items-center flex-wrap px-3 pb-3"ip>',
language: {
search: "Cari:",
lengthMenu: "Tampilkan _MENU_ data",
info: "Menampilkan _START__END_ dari _TOTAL_ data",
infoEmpty: "Tidak ada data",
paginate: { first: "«", last: "»", next: "", previous: "" },
emptyTable: "Belum ada data penghuni"
},
// Setelah DataTable merender, pindahkan wrapper ke dalam dt-scroll-outer
initComplete: function () {
var wrapper = $('#tablePenghuni').closest('.dataTables_wrapper');
$('#wrap-penghuni').append(wrapper);
}
});
var dtRumah = $('#tableRumah').DataTable({
pageLength: 10,
lengthMenu: [5, 10, 25, 50],
dom: '<"d-flex justify-content-between align-items-center flex-wrap px-3 pt-3"lf>t<"d-flex justify-content-between align-items-center flex-wrap px-3 pb-3"ip>',
language: {
search: "Cari:",
lengthMenu: "Tampilkan _MENU_ data",
info: "Menampilkan _START__END_ dari _TOTAL_ data",
infoEmpty: "Tidak ada data",
paginate: { first: "«", last: "»", next: "", previous: "" },
emptyTable: "Belum ada data rumah"
},
initComplete: function () {
var wrapper = $('#tableRumah').closest('.dataTables_wrapper');
$('#wrap-rumah').append(wrapper);
}
});
}
$(document).on('click', '.btn-detail', function () {
var btn = $(this);
$('#d_blok').text(btn.data('blok'));
$('#d_nomor').text(btn.data('nomor'));
$('#d_status').text(btn.data('status'));
$('#d_nama').text(btn.data('nama'));
$('#d_email').text(btn.data('email'));
$('#d_telepon').text(btn.data('telepon'));
$('#modalDetail').modal('show');
});
});
</script>
@endsection