This commit is contained in:
Putrid1ana 2025-05-24 21:02:25 +07:00
parent 4adc6df40b
commit af29398f05
18 changed files with 509 additions and 304 deletions

View File

@ -17,12 +17,12 @@ public function index(Request $request)
{ {
$query = Booking::query(); $query = Booking::query();
// Filter pencarian berdasarkan status_booking // Filter pencarian berdasarkan bulan dari tanggal_booking
if ($request->has('search') && !empty($request->search)) { if ($request->has('search') && !empty($request->search)) {
$query->where('status_booking', 'like', '%' . $request->search . '%'); $query->whereMonth('tanggal_checkout', $request->search);
} }
$bookings = $query->orderBy('tanggal_booking', 'desc')->paginate(10); $bookings = $query->orderBy('tanggal_checkout', 'desc')->paginate(10);
return view('admin.booking', compact('bookings')); return view('admin.booking', compact('bookings'));
} }
@ -220,4 +220,25 @@ public function approvePerpanjangan($id)
return redirect()->route('admin.booking')->with('success', 'Perpanjangan berhasil dikonfirmasi.'); return redirect()->route('admin.booking')->with('success', 'Perpanjangan berhasil dikonfirmasi.');
} }
public function markAsCompleted($id_booking)
{
$booking = Booking::findOrFail($id_booking);
// Pastikan hanya booking yang dikonfirmasi bisa selesai
if ($booking->status_booking === 'Dikonfirmasi') {
$booking->update(['status_booking' => 'Selesai']);
// Update status kamar menjadi tersedia
$room = $booking->room;
if ($room) {
$room->update(['status' => 'tersedia']);
}
return redirect()->route('admin.booking')->with('success', 'Booking telah diselesaikan.');
}
return redirect()->route('admin.booking')->with('error', 'Booking belum dikonfirmasi.');
}
} }

View File

@ -6,19 +6,43 @@
use App\Models\User; use App\Models\User;
use App\Models\Room; use App\Models\Room;
use App\Models\Booking; use App\Models\Booking;
use Carbon\Carbon;
class DashboardAdminController extends Controller class DashboardAdminController extends Controller
{ {
public function index() public function index()
{ {
// Mengambil data dari database $totalUsers = User::count();
$totalUsers = User::count(); $totalRooms = Room::count();
$totalRooms = Room::count(); $totalBookings = Booking::count();
$totalBookings = Booking::count();
$pendingBookings = Booking::where('status_booking', 'pending')->with('user', 'room')->get();
// Mengirim data ke view // Ambil semua booking yang sudah dikonfirmasi
return view('admin.dashboard', compact('totalUsers', 'totalRooms', 'totalBookings', 'pendingBookings')); $confirmedBookings = Booking::with('user', 'room')
->where('status_booking', 'Dikonfirmasi')
->get();
// Buat array untuk simpan sisa hari per booking
$daysLeftPerBooking = [];
foreach ($confirmedBookings as $booking) {
if ($booking->tanggal_checkout) {
$daysLeftPerBooking[$booking->id_booking] = now()->diffInDays(Carbon::parse($booking->tanggal_checkout), false);
} else {
$daysLeftPerBooking[$booking->id_booking] = null;
}
} }
// Ambil booking pending untuk ditampilkan di tabel
$pendingBookings = Booking::where('status_booking', 'pending')->with('user', 'room')->get();
return view('admin.dashboard', compact(
'totalUsers',
'totalRooms',
'totalBookings',
'pendingBookings',
'confirmedBookings',
'daysLeftPerBooking'
));
}
} }

View File

@ -57,7 +57,14 @@ public function index(Request $request)
return $p - $q; return $p - $q;
}, $pemasukan, $pengeluaran); }, $pemasukan, $pengeluaran);
// Kirim data ke view // Ambil data status kamar (tersedia, terisi, maintenance)
$data_kamar = [
'Terisi' => Room::where('status', 'terisi')->count(),
'Kosong' => Room::where('status', 'tersedia')->count(),
'Rusak' => Room::where('status', 'maintenance')->count(),
];
// Kirim semua data ke view
return view('pemilik.dashboard', compact( return view('pemilik.dashboard', compact(
'totalUsers', 'totalUsers',
'totalRooms', 'totalRooms',
@ -70,7 +77,8 @@ public function index(Request $request)
'pengeluaran', 'pengeluaran',
'keuntungan', 'keuntungan',
'tahunList', 'tahunList',
'tahunTerpilih' 'tahunTerpilih',
'data_kamar'
)); ));
} }
} }

View File

@ -41,20 +41,26 @@ public function create()
* Menyimpan data pengeluaran baru ke database. * Menyimpan data pengeluaran baru ke database.
*/ */
public function store(Request $request) public function store(Request $request)
{ {
$request->validate([ $request->validate([
'keterangan' => 'required|string|max:255', 'keterangan' => 'required|string|max:255',
'jumlah_pengeluaran' => 'required|numeric|min:0', 'jumlah_pengeluaran' => 'required',
'tanggal_pengeluaran'=> 'required|date', 'tanggal_pengeluaran'=> 'required|date',
]); ]);
Expense::create($request->only(['keterangan', 'jumlah_pengeluaran', 'tanggal_pengeluaran'])); // Hilangkan titik/koma agar jumlah valid
$jumlah = str_replace(['.', ','], '', $request->jumlah_pengeluaran);
// Update data keuangan Expense::create([
$this->updateFinance(); 'keterangan' => $request->keterangan,
'jumlah_pengeluaran' => $jumlah,
'tanggal_pengeluaran' => $request->tanggal_pengeluaran,
]);
return redirect()->route('admin.expense')->with('success', 'Pengeluaran berhasil ditambahkan.'); $this->updateFinance();
}
return redirect()->route('admin.expense')->with('success', 'Pengeluaran berhasil ditambahkan.');
}
/** /**
* Menampilkan form untuk mengedit pengeluaran. * Menampilkan form untuk mengedit pengeluaran.
@ -69,21 +75,28 @@ public function edit($id_pengeluaran)
* Memperbarui data pengeluaran di database. * Memperbarui data pengeluaran di database.
*/ */
public function update(Request $request, $id_pengeluaran) public function update(Request $request, $id_pengeluaran)
{ {
$request->validate([ $request->validate([
'keterangan' => 'required|string|max:255', 'keterangan' => 'required|string|max:255',
'jumlah_pengeluaran' => 'required|numeric|min:0', 'jumlah_pengeluaran' => 'required',
'tanggal_pengeluaran'=> 'required|date', 'tanggal_pengeluaran'=> 'required|date',
]); ]);
$pengeluaran = Expense::findOrFail($id_pengeluaran); $pengeluaran = Expense::findOrFail($id_pengeluaran);
$pengeluaran->update($request->only(['keterangan', 'jumlah_pengeluaran', 'tanggal_pengeluaran']));
// Update data keuangan // Hilangkan titik/koma dari input user
$this->updateFinance(); $jumlah = str_replace(['.', ','], '', $request->jumlah_pengeluaran);
return redirect()->route('admin.expense')->with('success', 'Pengeluaran berhasil diperbarui.'); $pengeluaran->update([
} 'keterangan' => $request->keterangan,
'jumlah_pengeluaran' => $jumlah,
'tanggal_pengeluaran' => $request->tanggal_pengeluaran,
]);
$this->updateFinance();
return redirect()->route('admin.expense')->with('success', 'Pengeluaran berhasil diperbarui.');
}
/** /**
* Menghapus data pengeluaran dari database. * Menghapus data pengeluaran dari database.
@ -104,16 +117,32 @@ public function destroy($id_pengeluaran)
*/ */
private function updateFinance() private function updateFinance()
{ {
$tanggalHariIni = now()->format('Y-m-d');
$totalPemasukan = Transaksi::sum('jumlah_pembayaran'); $totalPemasukan = Transaksi::sum('jumlah_pembayaran');
$totalPengeluaran = Expense::sum('jumlah_pengeluaran'); $totalPengeluaran = Expense::sum('jumlah_pengeluaran');
$totalKeuntungan = $totalPemasukan - $totalPengeluaran; $totalKeuntungan = $totalPemasukan - $totalPengeluaran;
Finance::create([ // Cek apakah sudah ada data finance untuk hari ini
'tanggal' => now()->format('Y-m-d'), $finance = Finance::where('tanggal', $tanggalHariIni)->first();
'pemasukan' => $totalPemasukan,
'pengeluaran' => $totalPengeluaran, if ($finance) {
'keuntungan' => $totalKeuntungan, // Update data yang sudah ada
'keterangan' => 'Update otomatis dari data pengeluaran' $finance->update([
]); 'pemasukan' => $totalPemasukan,
'pengeluaran' => $totalPengeluaran,
'keuntungan' => $totalKeuntungan,
'keterangan' => 'Update otomatis dari data pengeluaran'
]);
} else {
// Buat data baru
Finance::create([
'tanggal' => $tanggalHariIni,
'pemasukan' => $totalPemasukan,
'pengeluaran' => $totalPengeluaran,
'keuntungan' => $totalKeuntungan,
'keterangan' => 'Update otomatis dari data pengeluaran'
]);
}
} }
} }

View File

@ -5,14 +5,26 @@
use Illuminate\Http\Request; use Illuminate\Http\Request;
use App\Models\Room; use App\Models\Room;
use App\Models\Booking; use App\Models\Booking;
use Carbon\Carbon;
class KamarController extends Controller class KamarController extends Controller
{ {
public function index() public function index()
{ {
$booking = Booking::where('id_user', auth()->id())->orderBy('tanggal_booking', 'desc')->first(); $booking = Booking::where('id_user', auth()->id())
$rooms = Room::all(); ->orderBy('tanggal_booking', 'desc')
return view('users.peta', compact('booking', 'rooms')); ->first();
}
$rooms = Room::all();
$daysLeft = null;
if ($booking && $booking->status_booking === 'Dikonfirmasi' && $booking->tanggal_checkout) {
$today = Carbon::now();
$checkoutDate = Carbon::parse($booking->tanggal_checkout);
$daysLeft = $today->diffInDays($checkoutDate, false);
}
return view('users.peta', compact('booking', 'rooms', 'daysLeft'));
}
} }

View File

@ -36,7 +36,15 @@ public function index(Request $request)
$row->bulan = $months[$row->bulan] ?? $row->bulan; $row->bulan = $months[$row->bulan] ?? $row->bulan;
} }
return view('admin.keuangan', compact('filteredLaporan', 'years', 'months')); // Hitung total pemasukan, pengeluaran, dan keuntungan bersih
$totalPemasukan = $filteredLaporan->sum('total_pemasukan');
$totalPengeluaran = $filteredLaporan->sum('total_pengeluaran');
$totalKeuntungan = $filteredLaporan->sum('keuntungan_bersih');
// Kirim ke view
return view('admin.keuangan', compact(
'filteredLaporan', 'years', 'months',
'totalPemasukan', 'totalPengeluaran', 'totalKeuntungan'
));
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 KiB

View File

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 74 KiB

View File

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 74 KiB

View File

@ -50,21 +50,11 @@
<i class="bi bi-trash-fill"></i> <i class="bi bi-trash-fill"></i>
</a> </a>
{{-- <!-- Tombol Konfirmasi Pemesanan hanya muncul jika status booking 'Pending' --> @if ($booking->status_booking === 'Dikonfirmasi')
@if($booking->status_booking == 'Pending') <a href="{{ route('admin.bookingselesai', $booking->id_booking) }}" class="btn btn-success btn-sm mt-1">
<form action="{{ route('admin.bookingconfirm', $booking->id_booking) }}" method="POST" style="display:inline-block; margin-top: 5px;"> Tandai Selesai
@csrf </a>
<button type="submit" class="btn btn-primary btn-sm">Konfirmasi Pemesanan</button>
</form>
@endif @endif
<!-- Tombol Batalkan Booking hanya muncul jika status booking 'Dikonfirmasi' -->
@if($booking->status_booking == 'Dikonfirmasi')
<form action="{{ route('admin.bookingcancel', $booking->id_booking) }}" method="POST" style="display:inline-block; margin-top: 5px;">
@csrf
<button type="submit" class="btn btn-danger btn-sm">Batalkan Booking</button>
</form>
@endif --}}
</td> </td>
</tr> </tr>
@endforeach @endforeach

View File

@ -19,7 +19,7 @@
<div class="mb-3"> <div class="mb-3">
<label for="jumlah_pengeluaran" class="form-label">Jumlah (Rp)</label> <label for="jumlah_pengeluaran" class="form-label">Jumlah (Rp)</label>
<input type="number" name="jumlah_pengeluaran" id="jumlah_pengeluaran" class="form-control" step="0.01" required> <input type="text" name="jumlah_pengeluaran" id="jumlah_pengeluaran" class="form-control" required placeholder="Contoh: 1.200.000">
</div> </div>
<div class="d-flex justify-content-between"> <div class="d-flex justify-content-between">

View File

@ -2,7 +2,28 @@
@section('content') @section('content')
<div class="container-fluid p-4" style="background-color: #F5F5F5; border-radius: 10px;"> <div class="container-fluid p-4" style="background-color: #F5F5F5; border-radius: 10px;">
<h3 class="fw-bold" style="color: #063986;">Selamat Datang Di Kos Calista</h3> <h3 class="fw-bold" style="color: #063986;">Selamat Datang Di Kos Calista</h3>
{{-- Notifikasi sisa masa booking customer (kalau ada booking terakhir) --}}
@isset($booking)
@if (!is_null($daysLeft))
@if ($daysLeft > 0)
<div class="alert alert-warning mt-3 fw-semibold text-dark">
Sisa booking customer: <strong>{{ $daysLeft }} hari</strong>
</div>
@elseif ($daysLeft === 0)
<div class="alert alert-danger mt-3 fw-semibold">
Hari ini adalah <strong>hari terakhir</strong> masa booking customer!
</div>
@else
<div class="alert alert-secondary mt-3 fw-semibold">
Masa booking customer sudah <strong>berakhir</strong>.
</div>
@endif
@endif
@endisset
<div class="row mt-4"> <div class="row mt-4">
{{-- Statistik --}}
<div class="col-md-4"> <div class="col-md-4">
<div class="card border shadow-sm"> <div class="card border shadow-sm">
<div class="card-body text-center p-4"> <div class="card-body text-center p-4">
@ -45,6 +66,8 @@
</div> </div>
</div> </div>
</div> </div>
{{-- Tabel Pending Booking --}}
<div class="row mt-5"> <div class="row mt-5">
<div class="col-12"> <div class="col-12">
<div class="card border shadow-sm"> <div class="card border shadow-sm">
@ -64,6 +87,7 @@
<th>Kamar</th> <th>Kamar</th>
<th>Tanggal Pemesanan</th> <th>Tanggal Pemesanan</th>
<th>Status</th> <th>Status</th>
<th>Aksi</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -102,7 +126,6 @@
</tr> </tr>
@endforeach @endforeach
</tbody> </tbody>
</table> </table>
</div> </div>
@endif @endif
@ -110,5 +133,38 @@
</div> </div>
</div> </div>
</div> </div>
{{-- Tampilkan Booking yang sudah dikonfirmasi beserta sisa hari --}}
<div class="row mt-5">
<div class="col-12">
<h5 class="fw-bold text-primary mb-3">Sisa Hari Booking</h5>
@foreach ($confirmedBookings as $booking)
<div class="mb-3 p-3 border rounded bg-light">
<p><strong>Customer:</strong> {{ $booking->user->name }}</p>
<p><strong>Booking Kamar:</strong> {{ $booking->room->room_type }}</p>
@php
$daysLeft = $daysLeftPerBooking[$booking->id_booking] ?? null;
@endphp
@if(!is_null($daysLeft))
@if($daysLeft > 0)
<div class="alert alert-warning mb-0">
Sisa booking: <strong>{{ $daysLeft }} hari</strong>
</div>
@elseif($daysLeft === 0)
<div class="alert alert-danger mb-0">
Hari ini <strong>terakhir</strong> masa booking!
</div>
@else
<div class="alert alert-secondary mb-0">
Masa booking sudah <strong>berakhir</strong>
</div>
@endif
@endif
</div>
@endforeach
</div>
</div>
</div> </div>
</div>
@endsection @endsection

View File

@ -42,7 +42,7 @@
<td>{{ ($rooms->currentPage() - 1) * $rooms->perPage() + $loop->iteration }}</td> <td>{{ ($rooms->currentPage() - 1) * $rooms->perPage() + $loop->iteration }}</td>
<td>{{ $room->room_number }}</td> <td>{{ $room->room_number }}</td>
<td>{{ $room->room_type }}</td> <td>{{ $room->room_type }}</td>
<td>Rp {{ number_format($room->harga, 0, ',', '.') }}</td> <td>Rp {{ number_format((int) $room->harga, 0, ',', '.') }}</td>
<td>{{ ucfirst($room->status) }}</td> <td>{{ ucfirst($room->status) }}</td>
<td>{{ $room->lantai }}</td> <td>{{ $room->lantai }}</td>
<td>{{ $room->fasilitas }}</td> <td>{{ $room->fasilitas }}</td>

View File

@ -36,7 +36,7 @@
<tr> <tr>
<td>{{ $index + 1 }}</td> <td>{{ $index + 1 }}</td>
<td>{{ $item->booking->user->name }} - Kamar {{ $item->booking->room->room_number }}</td> <td>{{ $item->booking->user->name }} - Kamar {{ $item->booking->room->room_number }}</td>
<td>Rp {{ number_format($item->jumlah_pembayaran, 2, ',', '.') }}</td> <td>Rp {{ number_format((int) $item->jumlah_pembayaran, 0, ',', '.') }}</td>
<td>{{ $item->metode_pembayaran ?? 'Belum dipilih' }}</td> <td>{{ $item->metode_pembayaran ?? 'Belum dipilih' }}</td>
<td>{{ ucfirst($item->status_transaksi) }}</td> <td>{{ ucfirst($item->status_transaksi) }}</td>
<td> <td>

View File

@ -1,213 +1,219 @@
@extends('layouts.app1') @extends('layouts.app1')
@section('content') @section('content')
<div class="container-fluid p-4" style="background-color: #F5F5F5; border-radius: 10px;"> <div class="container-fluid p-4" style="background-color: #F5F5F5; border-radius: 10px;">
<h3 class="fw-bold" style="color: #063986;">Selamat Datang Di Kos Calista</h3> <h3 class="fw-bold" style="color: #063986;">Selamat Datang Di Kos Calista</h3>
<div class="row mt-4"> <div class="row mt-4">
<div class="col-md-4"> <div class="col-md-4">
<div class="card border shadow-sm"> <div class="card border shadow-sm">
<div class="card-body text-center p-4"> <div class="card-body text-center p-4">
<div class="d-flex justify-content-center"> <div class="d-flex justify-content-center">
<div class="rounded-circle d-flex align-items-center justify-content-center" <div class="rounded-circle d-flex align-items-center justify-content-center"
style="width: 60px; height: 60px; background-color: #0080B5;"> style="width: 60px; height: 60px; background-color: #0080B5;">
<i class="bi bi-person-badge-fill text-white" style="font-size: 30px;"></i> <i class="bi bi-person-badge-fill text-white" style="font-size: 30px;"></i>
</div>
</div> </div>
<h3 class="fw-bold mt-3 mb-0">{{ $totalUsers }}</h3>
<p class="mb-0">Total Customer</p>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card border shadow-sm">
<div class="card-body text-center p-4">
<div class="d-flex justify-content-center">
<div class="rounded-circle d-flex align-items-center justify-content-center"
style="width: 60px; height: 60px; background-color: #0080B5;">
<i class="bi bi-door-closed-fill text-white" style="font-size: 30px;"></i>
</div>
</div>
<h3 class="fw-bold mt-3 mb-0">{{ $totalRooms }}</h3>
<p class="mb-0">Total Kamar</p>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card border shadow-sm">
<div class="card-body text-center p-4">
<div class="d-flex justify-content-center">
<div class="rounded-circle d-flex align-items-center justify-content-center"
style="width: 60px; height: 60px; background-color: #0080B5;">
<i class="bi bi-journal-check text-white" style="font-size: 30px;"></i>
</div>
</div>
<h3 class="fw-bold mt-3 mb-0">{{ $totalBookings }}</h3>
<p class="mb-0">Total Booking</p>
</div> </div>
<h3 class="fw-bold mt-3 mb-0">{{ $totalUsers }}</h3>
<p class="mb-0">Total Customer</p>
</div> </div>
</div> </div>
</div> </div>
<div class="col-md-4">
<div class="card border shadow-sm"> <div class="row mt-4">
<div class="card-body text-center p-4"> <div class="col-12 text-center mb-3">
<div class="d-flex justify-content-center"> <div class="d-flex justify-content-center gap-3 flex-wrap">
<div class="rounded-circle d-flex align-items-center justify-content-center" <div>
style="width: 60px; height: 60px; background-color: #0080B5;"> <label for="bulanSelect" class="form-label fw-semibold mb-1">Pilih Bulan</label>
<i class="bi bi-door-closed-fill text-white" style="font-size: 30px;"></i> <select id="bulanSelect" class="form-select">
</div> <option value="0">Semua Bulan</option>
@foreach($labels as $index => $bulan)
<option value="{{ $index + 1 }}">{{ $bulan }}</option>
@endforeach
</select>
</div>
<div>
<label for="tahunSelect" class="form-label fw-semibold mb-1">Pilih Tahun</label>
<select id="tahunSelect" class="form-select" onchange="location.href='?tahun=' + this.value">
@foreach($tahunList as $tahun)
<option value="{{ $tahun }}" {{ $tahun == $tahunTerpilih ? 'selected' : '' }}>{{ $tahun }}
</option>
@endforeach
</select>
</div> </div>
<h3 class="fw-bold mt-3 mb-0">{{ $totalRooms }}</h3>
<p class="mb-0">Total Kamar</p>
</div> </div>
</div> </div>
</div>
<div class="col-md-4"> <!-- Grafik Keuangan -->
<div class="card border shadow-sm"> <div class="col-md-6">
<div class="card-body text-center p-4"> <div class="card border shadow-sm">
<div class="d-flex justify-content-center"> <div class="card-body p-4">
<div class="rounded-circle d-flex align-items-center justify-content-center" <h5 class="text-center fw-bold">Keuangan</h5>
style="width: 60px; height: 60px; background-color: #0080B5;"> <canvas id="keuanganBarChart" style="max-height: 300px;"></canvas>
<i class="bi bi-journal-check text-white" style="font-size: 30px;"></i>
</div>
</div> </div>
<h3 class="fw-bold mt-3 mb-0">{{ $totalBookings }}</h3>
<p class="mb-0">Total Booking</p>
</div> </div>
</div> </div>
</div>
</div>
<!-- Grafik Keuangan --> <!-- Grafik Kamar -->
<div class="row mt-4"> <div class="col-md-6">
<div class="col-12 text-center mb-3"> <div class="card border shadow-sm">
<div class="d-flex justify-content-center gap-3 flex-wrap"> <div class="card-body p-4">
<div> <h5 class="text-center fw-bold">Data Kamar</h5>
<label for="bulanSelect" class="form-label fw-semibold mb-1">Pilih Bulan</label> <canvas id="dataKamarPieChart" style="max-height: 300px;"></canvas>
<select id="bulanSelect" class="form-select"> </div>
<option value="all">Semua Bulan</option> </div>
@foreach($labels as $index => $bulan)
<option value="{{ $index }}">{{ $bulan }}</option>
@endforeach
</select>
</div> </div>
<div>
<label for="tahunSelect" class="form-label fw-semibold mb-1">Pilih Tahun</label>
<select id="tahunSelect" class="form-select">
@foreach($tahunList as $tahun)
<option value="{{ $tahun }}" {{ $tahun == $tahunTerpilih ? 'selected' : '' }}>{{ $tahun }}</option>
@endforeach
</select>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card border shadow-sm">
<div class="card-body p-4">
<h5 class="text-center fw-bold">Bar Chart Keuangan</h5>
<canvas id="keuanganBarChart"></canvas>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card border shadow-sm">
<div class="card-body p-4">
<h5 class="text-center fw-bold">Pie Chart Keuangan</h5>
<canvas id="keuanganPieChart"></canvas>
</div>
</div>
</div>
</div>
@endsection @endsection
@push('scripts') @push('scripts')
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script> <script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2"></script>
document.addEventListener("DOMContentLoaded", function () { <script>
const labels = {!! json_encode($labels) !!}; document.addEventListener("DOMContentLoaded", function () {
const pemasukan = {!! json_encode($pemasukan) !!}; const labels = {!! json_encode($labels) !!};
const pengeluaran = {!! json_encode($pengeluaran) !!}; const pemasukan = {!! json_encode($pemasukan) !!};
const keuntungan = {!! json_encode($keuntungan) !!}; const pengeluaran = {!! json_encode($pengeluaran) !!};
const keuntungan = {!! json_encode($keuntungan) !!};
const dataKamar = {!! json_encode($data_kamar ?? []) !!}; // ✅ benar
// === BAR CHART === // BAR CHART KEUANGAN
const ctxBar = document.getElementById('keuanganBarChart').getContext('2d'); new Chart(document.getElementById('keuanganBarChart').getContext('2d'), {
new Chart(ctxBar, { type: 'bar',
type: 'bar', data: {
data: { labels: labels,
labels: labels, datasets: [
datasets: [ {
{ label: 'Pemasukan',
label: 'Pemasukan', data: pemasukan,
data: pemasukan, backgroundColor: 'rgba(54, 162, 235, 0.6)',
backgroundColor: 'rgba(54, 162, 235, 0.6)', borderColor: 'rgba(54, 162, 235, 1)',
borderColor: 'rgba(54, 162, 235, 1)', borderWidth: 1
borderWidth: 1 },
}, {
{ label: 'Pengeluaran',
label: 'Pengeluaran', data: pengeluaran,
data: pengeluaran, backgroundColor: 'rgba(255, 99, 132, 0.6)',
backgroundColor: 'rgba(255, 99, 132, 0.6)', borderColor: 'rgba(255, 99, 132, 1)',
borderColor: 'rgba(255, 99, 132, 1)', borderWidth: 1
borderWidth: 1 },
}, {
{ label: 'Keuntungan',
label: 'Keuntungan', data: keuntungan,
data: keuntungan, type: 'line',
type: 'line', borderColor: 'rgba(75, 192, 192, 1)',
borderColor: 'rgba(75, 192, 192, 1)', backgroundColor: 'rgba(75, 192, 192, 0.2)',
backgroundColor: 'rgba(75, 192, 192, 0.2)', borderWidth: 2,
borderWidth: 2, tension: 0.3,
tension: 0.3, fill: false
fill: false }
} ]
] },
}, options: {
options: { responsive: true,
responsive: true, interaction: {
interaction: { mode: 'index',
mode: 'index', intersect: false,
intersect: false, },
}, stacked: false,
stacked: false, scales: {
scales: { y: {
y: { beginAtZero: true,
beginAtZero: true, ticks: {
ticks: { callback: value => 'Rp ' + value.toLocaleString('id-ID')
callback: function(value) { }
return 'Rp ' + value.toLocaleString('id-ID'); }
},
plugins: {
tooltip: {
callbacks: {
label: context => `${context.dataset.label}: Rp ${context.parsed.y.toLocaleString('id-ID')}`
}
}
}
} }
});
// PIE CHART DATA KAMAR (Tampilkan jumlah kamar sebagai label)
const ctxKamar = document.getElementById('dataKamarPieChart').getContext('2d');
const kamarLabels = Object.keys(dataKamar);
const kamarData = Object.values(dataKamar);
new Chart(ctxKamar, {
type: 'pie',
data: {
labels: kamarLabels,
datasets: [{
data: kamarData,
backgroundColor: [
'rgba(75, 192, 192, 0.7)', // Terisi
'rgba(255, 206, 86, 0.7)', // Kosong
'rgba(255, 99, 132, 0.7)' // Rusak
],
borderColor: [
'rgba(75, 192, 192, 1)',
'rgba(255, 206, 86, 1)',
'rgba(255, 99, 132, 1)'
],
borderWidth: 1
}]
},
options: {
responsive: true,
plugins: {
tooltip: {
callbacks: {
label: (context) => {
const value = context.parsed;
return `${context.label}: ${value} kamar`;
} }
} }
}, },
plugins: { legend: {
tooltip: { position: 'bottom'
callbacks: { },
label: function(context) { datalabels: {
return context.dataset.label + ': Rp ' + context.parsed.y.toLocaleString('id-ID'); color: '#000',
} formatter: (value) => `${value} kamar`,
} font: {
weight: 'bold',
size: 14
} }
} }
} }
}); },
plugins: [ChartDataLabels] // ← tambahkan kembali plugin ini
// === PIE CHART ===
const bulanSelect = document.getElementById('bulanSelect');
const ctxPie = document.getElementById('keuanganPieChart').getContext('2d');
let pieChart = new Chart(ctxPie, {
type: 'pie',
data: {
labels: ['Pemasukan', 'Pengeluaran', 'Keuntungan'],
datasets: [{
data: [pemasukan[0], pengeluaran[0], keuntungan[0]],
backgroundColor: [
'rgba(54, 162, 235, 0.7)',
'rgba(255, 99, 132, 0.7)',
'rgba(75, 192, 192, 0.7)'
],
borderColor: [
'rgba(54, 162, 235, 1)',
'rgba(255, 99, 132, 1)',
'rgba(75, 192, 192, 1)'
],
borderWidth: 1
}]
},
options: {
responsive: true,
plugins: {
tooltip: {
callbacks: {
label: function(context) {
return context.label + ': Rp ' + context.parsed.toLocaleString('id-ID');
}
}
}
}
}
});
// Event listener untuk ubah bulan
bulanSelect.addEventListener('change', function () {
const i = parseInt(this.value);
pieChart.data.datasets[0].data = [pemasukan[i], pengeluaran[i], keuntungan[i]];
pieChart.update();
});
}); });
</script> });
@endpush </script>
@endpush

View File

@ -51,11 +51,42 @@ class="{{ $room->status == 'tersedia' ? 'text-green-600' : ($room->status == 'te
@endif @endif
@if (!empty($room->deskripsi)) @if (!empty($room->deskripsi))
<div class="mb-4"> @php
<h3 class="text-md font-semibold text-gray-800 mb-1">Deskripsi:</h3> // Pisahkan berdasarkan dua bagian utama: 'Fasilitas umum :' dan 'Aturan di Kos Calista'
<p class="text-gray-700 leading-relaxed text-sm">{!! nl2br(e($room->deskripsi)) !!}</p> $fasilitas = '';
</div> $aturan = '';
@endif
if (preg_match('/Fasilitas umum\s*:\s*(.+?)\s*Aturan di Kos Calista\s*/s', $room->deskripsi, $match)) {
$fasilitas = trim($match[1]);
}
if (preg_match('/Aturan di Kos Calista\s*(.+)/s', $room->deskripsi, $match)) {
$aturan = trim($match[1]);
}
// Ambil item berdasarkan pola angka di depan (1. xxx 2. xxx ...)
preg_match_all('/\d+\.\s*([^0-9]+)/', $fasilitas, $fasilitasList);
preg_match_all('/\d+\.\s*([^0-9]+)/', $aturan, $aturanList);
@endphp
<div class="mb-4">
<h3 class="text-md font-semibold text-gray-800 mb-1">Fasilitas Umum:</h3>
<ul class="list-disc pl-5 text-gray-700 text-sm leading-relaxed">
@foreach ($fasilitasList[1] as $item)
<li>{{ trim($item) }}</li>
@endforeach
</ul>
</div>
<div class="mb-4">
<h3 class="text-md font-semibold text-gray-800 mb-1">Aturan di Kos Calista:</h3>
<ul class="list-decimal pl-5 text-gray-700 text-sm leading-relaxed">
@foreach ($aturanList[1] as $item)
<li>{{ trim($item) }}</li>
@endforeach
</ul>
</div>
@endif
<div class="mt-6"> <div class="mt-6">
<a href="{{ route('users.peta') }}" <a href="{{ route('users.peta') }}"

View File

@ -11,46 +11,65 @@
<body class="bg-gradient-to-br from-blue-400 to-white min-h-screen flex items-center justify-center p-6 font-sans"> <body class="bg-gradient-to-br from-blue-400 to-white min-h-screen flex items-center justify-center p-6 font-sans">
<div class="max-w-6xl mx-auto py-6 px-4"> <div class="max-w-6xl mx-auto py-6 px-4">
<!-- Header --> <!-- Header -->
<header class="bg-black text-white px-6 py-4 rounded-lg flex justify-between items-center shadow-md"> <header class="bg-black text-white px-6 py-4 rounded-lg flex justify-between items-center shadow-md">
<h1 class="text-2xl font-bold">Kos Calista</h1> <h1 class="text-2xl font-bold">Kos Calista</h1>
<div class="flex items-center gap-4">
<i class="fa fa-female text-2xl"></i> <div class="flex items-center gap-6">
<!-- Dropdown -->
<div class="relative group"> {{-- Notifikasi sisa masa booking --}}
<button class="bg-white text-blue-800 font-semibold px-4 py-2 rounded shadow hover:bg-gray-100 transition"> @isset($daysLeft)
Menu @if ($daysLeft > 0)
</button> <div class="bg-yellow-400 text-black px-4 py-1 rounded text-sm font-medium">
<div class="absolute right-0 mt-2 w-44 bg-white border border-gray-200 rounded shadow-md opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-200 z-10"> Sisa booking: <strong>{{ $daysLeft }} hari</strong>
@isset($booking)
<a href="{{ route('users.detail-pesanan', ['id_booking' => $booking->id_booking]) }}"
class="block px-4 py-2 text-black hover:bg-gray-100">
Detail Pesanan
</a>
<!-- Menambahkan opsi perpanjangan sewa -->
<a href="{{ route('users.perpanjangan-sewa', ['id_booking' => $booking->id_booking]) }}"
class="block px-4 py-2 text-black hover:bg-gray-100">
Perpanjang Sewa
</a>
@else
<span class="block px-4 py-2 text-gray-400 cursor-not-allowed">
Detail Pesanan
</span>
@endisset
<!-- Menambahkan opsi Profile -->
<a href="{{ route('users.profile') }}" class="block px-4 py-2 text-black hover:bg-gray-100">
Profile
</a>
<form action="{{ route('logout') }}" method="POST">
@csrf
<button type="submit" class="w-full text-left px-4 py-2 text-black hover:bg-gray-100">
Logout
</button>
</form>
</div>
</div> </div>
@elseif ($daysLeft === 0)
<div class="bg-red-500 text-white px-4 py-1 rounded text-sm font-medium">
Hari ini <strong>terakhir</strong> masa booking!
</div>
@else
<div class="bg-gray-600 text-white px-4 py-1 rounded text-sm font-medium">
Masa booking sudah <strong>berakhir</strong>
</div>
@endif
@endisset
<i class="fa fa-female text-2xl"></i>
<!-- Dropdown -->
<div class="relative group">
<button class="bg-white text-blue-800 font-semibold px-4 py-2 rounded shadow hover:bg-gray-100 transition">
Menu
</button>
<div class="absolute right-0 mt-2 w-44 bg-white border border-gray-200 rounded shadow-md opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-200 z-10">
@isset($booking)
<a href="{{ route('users.detail-pesanan', ['id_booking' => $booking->id_booking]) }}"
class="block px-4 py-2 text-black hover:bg-gray-100">
Detail Pesanan
</a>
<a href="{{ route('users.perpanjangan-sewa', ['id_booking' => $booking->id_booking]) }}"
class="block px-4 py-2 text-black hover:bg-gray-100">
Perpanjang Sewa
</a>
@else
<span class="block px-4 py-2 text-gray-400 cursor-not-allowed">
Detail Pesanan
</span>
@endisset
<a href="{{ route('users.profile') }}" class="block px-4 py-2 text-black hover:bg-gray-100">
Profile
</a>
<form action="{{ route('logout') }}" method="POST">
@csrf
<button type="submit" class="w-full text-left px-4 py-2 text-black hover:bg-gray-100">
Logout
</button>
</form>
</div> </div>
</header> </div>
</div>
</header>
<!-- Denah Kos --> <!-- Denah Kos -->
<section class="mt-8 bg-white p-6 rounded-lg shadow-lg"> <section class="mt-8 bg-white p-6 rounded-lg shadow-lg">

View File

@ -98,9 +98,9 @@
Route::get('/', [CustomerController::class, 'index'])->name('admin.customer'); Route::get('/', [CustomerController::class, 'index'])->name('admin.customer');
Route::get('/create', [CustomerController::class, 'create'])->name('admin.createcustomer'); Route::get('/create', [CustomerController::class, 'create'])->name('admin.createcustomer');
Route::post('/store', [CustomerController::class, 'store'])->name('admin.storecustomer'); Route::post('/store', [CustomerController::class, 'store'])->name('admin.storecustomer');
Route::get('/edit/{id}', [CustomerController::class, 'edit'])->name('admin.editcustomer'); Route::get('/edit/{id_user}', [CustomerController::class, 'edit'])->name('admin.editcustomer');
Route::put('/update/{id}', [CustomerController::class, 'update'])->name('admin.updatecustomer'); Route::put('/update/{id_user}', [CustomerController::class, 'update'])->name('admin.updatecustomer');
Route::get('/delete/{id}', [CustomerController::class, 'destroy'])->name('admin.deletecustomer'); Route::get('/delete/{id_user}', [CustomerController::class, 'destroy'])->name('admin.deletecustomer');
}); });
// Rooms // Rooms
@ -134,6 +134,7 @@
Route::put('/confirm/{id_booking}', [BookingController::class, 'confirm'])->name('admin.bookingconfirm'); Route::put('/confirm/{id_booking}', [BookingController::class, 'confirm'])->name('admin.bookingconfirm');
Route::put('/cancel/{id_booking}', [BookingController::class, 'cancel'])->name('admin.bookingcancel'); Route::put('/cancel/{id_booking}', [BookingController::class, 'cancel'])->name('admin.bookingcancel');
Route::put('/admin/booking/perpanjangan/{id}/approve', [BookingController::class, 'approvePerpanjangan'])->name('admin.approvePerpanjangan'); Route::put('/admin/booking/perpanjangan/{id}/approve', [BookingController::class, 'approvePerpanjangan'])->name('admin.approvePerpanjangan');
Route::get('/admin/booking/selesai/{id_booking}', [BookingController::class, 'markAsCompleted'])->name('admin.bookingselesai');
}); });
// Expense // Expense