585 lines
19 KiB
PHP
585 lines
19 KiB
PHP
@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 ── */
|
||
.page-header {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 14px;
|
||
margin-bottom: 28px;
|
||
flex-wrap: wrap;
|
||
}
|
||
.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;
|
||
flex-wrap: wrap;
|
||
gap: 10px;
|
||
}
|
||
.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; }
|
||
.premium-card-header h6 {
|
||
font-size: 14px;
|
||
font-weight: 700;
|
||
color: #1a2e1a;
|
||
margin: 0;
|
||
}
|
||
|
||
/* ── TAMBAH BUTTON ── */
|
||
.btn-tambah {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 7px;
|
||
padding: 8px 16px;
|
||
background: linear-gradient(135deg, #064e3b, #0d6e4f);
|
||
color: white;
|
||
border-radius: 10px;
|
||
font-size: 13px;
|
||
font-weight: 700;
|
||
text-decoration: none;
|
||
border: none;
|
||
cursor: pointer;
|
||
box-shadow: 0 3px 10px rgba(6,78,59,0.3);
|
||
transition: opacity 0.15s, transform 0.1s;
|
||
}
|
||
.btn-tambah:hover { opacity: 0.9; transform: translateY(-1px); color: white; text-decoration: none; }
|
||
|
||
/* ── TABLE WRAPPER (horizontal scroll on mobile) ── */
|
||
.table-responsive-wrapper {
|
||
width: 100%;
|
||
overflow-x: auto;
|
||
-webkit-overflow-scrolling: touch;
|
||
}
|
||
|
||
/* ── TABLE ── */
|
||
.premium-table {
|
||
width: 100%;
|
||
border-collapse: separate;
|
||
border-spacing: 0;
|
||
font-size: 13px;
|
||
min-width: 860px;
|
||
}
|
||
.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;
|
||
}
|
||
.premium-table tbody tr:hover td { background: #f8fdf8; }
|
||
.premium-table tbody tr:last-child td { border-bottom: none; }
|
||
|
||
/* ── MOBILE CARD VIEW ── */
|
||
.mobile-iuran-list { display: none; }
|
||
.iuran-card {
|
||
border-bottom: 1px solid #f0f5f0;
|
||
padding: 16px 18px;
|
||
}
|
||
.iuran-card:last-child { border-bottom: none; }
|
||
.iuran-card-header {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
justify-content: space-between;
|
||
margin-bottom: 10px;
|
||
gap: 10px;
|
||
}
|
||
.iuran-card-name {
|
||
font-size: 14px;
|
||
font-weight: 700;
|
||
color: #1a2e1a;
|
||
}
|
||
.iuran-card-meta {
|
||
font-size: 12px;
|
||
color: #8a9e8a;
|
||
margin-top: 2px;
|
||
}
|
||
.iuran-card-body {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 8px 16px;
|
||
margin-bottom: 12px;
|
||
}
|
||
.iuran-card-field label {
|
||
font-size: 10.5px;
|
||
font-weight: 700;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.4px;
|
||
color: #8a9e8a;
|
||
display: block;
|
||
margin-bottom: 2px;
|
||
}
|
||
.iuran-card-field span {
|
||
font-size: 13px;
|
||
color: #2a3a2a;
|
||
font-weight: 500;
|
||
}
|
||
.iuran-card-actions {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 6px;
|
||
align-items: center;
|
||
padding-top: 10px;
|
||
border-top: 1px solid #f0f5f0;
|
||
}
|
||
.iuran-card-bukti {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
/* ── 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: #d1fae5; color: #064e3b; }
|
||
.badge-red { background: #fdf0f0; color: #c53030; }
|
||
.badge-yellow { background: #fdfbea; color: #7a6010; }
|
||
.badge-blue { background: #eaf0fb; color: #1a4e8e; }
|
||
|
||
/* ── 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); text-decoration: none; }
|
||
.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-action.success { background: #d1fae5; color: #064e3b; }
|
||
|
||
/* ── BUKTI IMAGE ── */
|
||
.bukti-img {
|
||
width: 44px;
|
||
height: 44px;
|
||
border-radius: 8px;
|
||
object-fit: cover;
|
||
box-shadow: 0 2px 8px rgba(0,0,0,0.12);
|
||
cursor: pointer;
|
||
transition: transform 0.15s;
|
||
}
|
||
.bukti-img:hover { transform: scale(1.1); }
|
||
|
||
/* ── DATATABLES ── */
|
||
.dataTables_wrapper { padding: 0; }
|
||
.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;
|
||
max-width: 160px;
|
||
}
|
||
.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;
|
||
}
|
||
.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;
|
||
flex-wrap: wrap;
|
||
}
|
||
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 #1a6e3a !important;
|
||
color: #1a6e3a !important;
|
||
box-shadow: 0 0 0 3px rgba(26,110,58,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 BREAKPOINTS ── */
|
||
@media (max-width: 768px) {
|
||
.page-header h1 { font-size: 18px; }
|
||
.page-header p { font-size: 12px; }
|
||
|
||
/* Hide desktop table, show mobile cards */
|
||
.desktop-table-wrapper { display: none !important; }
|
||
.mobile-iuran-list { display: block; }
|
||
|
||
.premium-card-header { padding: 14px 16px; }
|
||
|
||
/* DataTables controls stacked */
|
||
.dataTables_wrapper .dataTables_length,
|
||
.dataTables_wrapper .dataTables_filter { width: 100%; }
|
||
.dataTables_wrapper .dataTables_filter input { max-width: 100%; width: 100%; margin-left: 0; margin-top: 4px; }
|
||
.dt-top-bar {
|
||
flex-direction: column !important;
|
||
align-items: flex-start !important;
|
||
gap: 8px !important;
|
||
padding: 14px 16px !important;
|
||
}
|
||
.dt-bottom-bar {
|
||
flex-direction: column !important;
|
||
align-items: flex-start !important;
|
||
gap: 8px !important;
|
||
padding: 14px 16px !important;
|
||
}
|
||
}
|
||
|
||
@media (min-width: 769px) {
|
||
.mobile-iuran-list { display: none !important; }
|
||
.desktop-table-wrapper { display: block !important; }
|
||
}
|
||
</style>
|
||
|
||
<div class="container-fluid">
|
||
|
||
{{-- PAGE HEADER --}}
|
||
<div class="page-header">
|
||
<div class="page-header-icon">
|
||
<i class="fas fa-money-bill-wave"></i>
|
||
</div>
|
||
<div>
|
||
<h1>Kelola Data Iuran</h1>
|
||
<p>Manajemen iuran dan pembayaran penghuni</p>
|
||
</div>
|
||
</div>
|
||
|
||
@if(session('success'))
|
||
<div class="alert-success-custom">
|
||
<i class="fas fa-check-circle"></i>
|
||
{{ session('success') }}
|
||
</div>
|
||
@endif
|
||
|
||
{{-- TABEL IURAN --}}
|
||
<div class="premium-card">
|
||
<div class="premium-card-header">
|
||
<div class="header-left">
|
||
<div class="header-icon green"><i class="fas fa-list-alt"></i></div>
|
||
<h6>Daftar Iuran</h6>
|
||
</div>
|
||
@if(auth()->user()->role == 'rt')
|
||
<a href="{{ route('iuran.create') }}" class="btn-tambah">
|
||
<i class="fas fa-plus" style="font-size:11px"></i> Tambah Iuran
|
||
</a>
|
||
@endif
|
||
</div>
|
||
|
||
{{-- ══ DESKTOP TABLE ══ --}}
|
||
<div class="desktop-table-wrapper" style="padding: 0;">
|
||
<div class="table-responsive-wrapper">
|
||
<table class="premium-table" id="dataTable" style="width:100%">
|
||
<thead>
|
||
<tr>
|
||
<th>#</th>
|
||
<th>Nama Penghuni</th>
|
||
<th>Bulan</th>
|
||
<th>Tahun</th>
|
||
<th>Jumlah</th>
|
||
<th>Jenis</th>
|
||
<th>Keterangan</th>
|
||
<th>Status</th>
|
||
<th>Tanggal</th>
|
||
<th>Bukti</th>
|
||
<th>Aksi</th>
|
||
</tr>
|
||
</thead>
|
||
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- ══ MOBILE CARD VIEW ══ --}}
|
||
<div class="mobile-iuran-list">
|
||
|
||
{{-- Mobile search bar --}}
|
||
<div style="padding: 14px 16px; border-bottom: 1px solid #f0f5f0;">
|
||
<input type="text" id="mobileSearch" placeholder=" Cari nama penghuni..." oninput="filterMobileCards(this.value)"
|
||
style="width:100%; border-radius:9px; border:1.5px solid #e0ede0; padding:8px 12px; font-size:13px; font-family:inherit; outline:none;">
|
||
</div>
|
||
|
||
<div id="mobileCardContainer">
|
||
@forelse($iuran as $i)
|
||
<div class="iuran-card" data-nama="{{ strtolower($i->penghuni->nama ?? '') }}">
|
||
<div class="iuran-card-header">
|
||
<div>
|
||
<div class="iuran-card-name">{{ $i->penghuni->nama ?? '-' }}</div>
|
||
<div class="iuran-card-meta">{{ $i->bulan }} {{ $i->tahun }} · {{ $i->jenis_iuran }}</div>
|
||
</div>
|
||
<div>
|
||
@if($i->status == 'lunas')
|
||
<span class="badge-pill-custom badge-green"><i class="fas fa-check-circle" style="font-size:10px"></i> Lunas</span>
|
||
@elseif($i->status == 'rt')
|
||
<span class="badge-pill-custom badge-blue"><i class="fas fa-clock" style="font-size:10px"></i> Menunggu Admin</span>
|
||
@elseif($i->bukti_pembayaran)
|
||
<span class="badge-pill-custom badge-yellow"><i class="fas fa-hourglass-half" style="font-size:10px"></i> Menunggu RT</span>
|
||
@else
|
||
<span class="badge-pill-custom badge-red"><i class="fas fa-times-circle" style="font-size:10px"></i> Belum Bayar</span>
|
||
@endif
|
||
</div>
|
||
</div>
|
||
|
||
<div class="iuran-card-body">
|
||
<div class="iuran-card-field">
|
||
<label>Jumlah</label>
|
||
<span style="color:#064e3b; font-weight:700;">Rp {{ number_format($i->jumlah, 0, ',', '.') }}</span>
|
||
</div>
|
||
<div class="iuran-card-field">
|
||
<label>Tanggal Bayar</label>
|
||
<span>{{ $i->tanggal_bayar ? \Carbon\Carbon::parse($i->tanggal_bayar)->translatedFormat('d M Y') : '-' }}</span>
|
||
</div>
|
||
<div class="iuran-card-field">
|
||
<label>Keterangan</label>
|
||
<span>{{ $i->keterangan ?? '-' }}</span>
|
||
</div>
|
||
@if($i->bukti_pembayaran)
|
||
<div class="iuran-card-field">
|
||
<label>Bukti</label>
|
||
<img src="{{ asset('bukti/' . $i->bukti_pembayaran) }}" class="bukti-img">
|
||
</div>
|
||
@endif
|
||
</div>
|
||
|
||
<div class="iuran-card-actions">
|
||
@if(auth()->user()->role == 'rt' && $i->status == 'belum' && $i->bukti_pembayaran)
|
||
<form action="{{ route('iuran.approve.rt', $i->id) }}" method="POST" style="display:inline;">
|
||
@csrf
|
||
<button class="btn-action warn"><i class="fas fa-check" style="font-size:10px"></i> Approve RT</button>
|
||
</form>
|
||
@endif
|
||
|
||
@if(auth()->user()->role == 'admin' && $i->status == 'menunggu')
|
||
<form action="{{ route('iuran.approve.admin', $i->id) }}" method="POST" style="display:inline;">
|
||
@csrf
|
||
<button class="btn-action success"><i class="fas fa-check-double" style="font-size:10px"></i> Approve Admin</button>
|
||
</form>
|
||
@endif
|
||
|
||
@if(auth()->user()->role == 'rt')
|
||
<a href="{{ route('iuran.edit', $i->id) }}" class="btn-action warn">
|
||
<i class="fas fa-edit" style="font-size:10px"></i> Edit
|
||
</a>
|
||
<form action="{{ route('iuran.destroy', $i->id) }}" method="POST" style="display:inline;">
|
||
@csrf
|
||
@method('DELETE')
|
||
<button class="btn-action danger" onclick="return confirm('Yakin hapus iuran ini?')">
|
||
<i class="fas fa-trash" style="font-size:10px"></i> Hapus
|
||
</button>
|
||
</form>
|
||
@endif
|
||
|
||
@if(!auth()->user() || (auth()->user()->role != 'rt' && auth()->user()->role != 'admin'))
|
||
<span style="font-size:12px; color:#ccc;">—</span>
|
||
@endif
|
||
</div>
|
||
</div>
|
||
@empty
|
||
<div style="text-align:center; padding: 40px; color: #aaa;">
|
||
<i class="fas fa-inbox" style="font-size:28px; display:block; margin-bottom:8px; opacity:0.4;"></i>
|
||
Belum ada data iuran
|
||
</div>
|
||
@endforelse
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
@endsection
|
||
|
||
@push('scripts')
|
||
<script>
|
||
$(document).ready(function () {
|
||
if ($.fn.DataTable) {
|
||
$('#dataTable').DataTable({
|
||
pageLength: 10,
|
||
lengthMenu: [5, 10, 25, 50],
|
||
dom: '<"d-flex justify-content-between align-items-center px-3 pt-3 dt-top-bar"lf>t<"d-flex justify-content-between align-items-center px-3 pb-3 dt-bottom-bar"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 iuran"
|
||
}
|
||
});
|
||
}
|
||
});
|
||
|
||
function filterMobileCards(query) {
|
||
var cards = document.querySelectorAll('#mobileCardContainer .iuran-card');
|
||
var q = query.toLowerCase();
|
||
cards.forEach(function(card) {
|
||
var nama = card.getAttribute('data-nama') || '';
|
||
card.style.display = nama.includes(q) ? '' : 'none';
|
||
});
|
||
}
|
||
</script>
|
||
@endpush
|