push tgl 9
This commit is contained in:
parent
6bbbe40c86
commit
1daae8d4a4
|
@ -8,6 +8,7 @@
|
||||||
use App\Models\Paket;
|
use App\Models\Paket;
|
||||||
use App\Models\Sewa;
|
use App\Models\Sewa;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
class DashboardController extends Controller
|
class DashboardController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -17,14 +18,22 @@ public function index()
|
||||||
$stats = [
|
$stats = [
|
||||||
'users' => User::where('role', 'customer')->count(),
|
'users' => User::where('role', 'customer')->count(),
|
||||||
'packages' => Paket::count(),
|
'packages' => Paket::count(),
|
||||||
'rentals' => Sewa::count(),
|
'rentals' => Sewa::whereIn('status', ['disetujui', 'selesai'])->count(),
|
||||||
'revenue' => Sewa::where('status', 'selesai')->sum('total_harga')
|
'revenue' => Sewa::where('status', 'selesai')->sum('total_harga')
|
||||||
];
|
];
|
||||||
|
|
||||||
// Mengambil aktivitas terbaru
|
// Mengambil aktivitas terbaru
|
||||||
$activities = $this->getRecentActivities();
|
$activities = $this->getRecentActivities();
|
||||||
|
|
||||||
return view('admin.dashboard', compact('stats', 'activities'));
|
// Mengambil pesanan yang dibatalkan terbaru (untuk notifikasi)
|
||||||
|
$recentCancellations = Sewa::with(['user', 'paket'])
|
||||||
|
->where('status', 'dibatalkan')
|
||||||
|
->whereNotNull('detail_status')
|
||||||
|
->latest()
|
||||||
|
->take(5)
|
||||||
|
->get();
|
||||||
|
|
||||||
|
return view('admin.dashboard', compact('stats', 'activities', 'recentCancellations'));
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getRecentActivities()
|
private function getRecentActivities()
|
||||||
|
@ -33,6 +42,7 @@ private function getRecentActivities()
|
||||||
|
|
||||||
// Aktivitas sewa terbaru
|
// Aktivitas sewa terbaru
|
||||||
$recentRentals = Sewa::with(['user', 'paket'])
|
$recentRentals = Sewa::with(['user', 'paket'])
|
||||||
|
->whereIn('status', ['disetujui', 'selesai'])
|
||||||
->latest()
|
->latest()
|
||||||
->take(5)
|
->take(5)
|
||||||
->get();
|
->get();
|
||||||
|
@ -63,6 +73,23 @@ private function getRecentActivities()
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Aktivitas pembatalan
|
||||||
|
$recentCancellations = Sewa::with(['user', 'paket'])
|
||||||
|
->where('status', 'dibatalkan')
|
||||||
|
->latest()
|
||||||
|
->take(3)
|
||||||
|
->get();
|
||||||
|
|
||||||
|
foreach ($recentCancellations as $cancellation) {
|
||||||
|
$activities[] = [
|
||||||
|
'title' => 'Pesanan Dibatalkan',
|
||||||
|
'description' => "{$cancellation->user->name} membatalkan pesanan paket {$cancellation->paket->nama_paket}",
|
||||||
|
'time' => Carbon::parse($cancellation->updated_at)->diffForHumans(),
|
||||||
|
'color' => 'red',
|
||||||
|
'icon' => 'M6 18L18 6M6 6l12 12'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
// Urutkan berdasarkan waktu terbaru
|
// Urutkan berdasarkan waktu terbaru
|
||||||
usort($activities, function($a, $b) {
|
usort($activities, function($a, $b) {
|
||||||
return strtotime($b['time']) - strtotime($a['time']);
|
return strtotime($b['time']) - strtotime($a['time']);
|
||||||
|
@ -70,4 +97,86 @@ private function getRecentActivities()
|
||||||
|
|
||||||
return array_slice($activities, 0, 5);
|
return array_slice($activities, 0, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Menampilkan halaman daftar pesanan yang dibatalkan
|
||||||
|
*/
|
||||||
|
public function cancelledOrders()
|
||||||
|
{
|
||||||
|
if (Auth::user()->tipe_pengguna !== 'admin') {
|
||||||
|
return redirect()->route('dashboard')->with('error', 'Akses ditolak.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$cancelledOrders = Sewa::with(['user', 'paket', 'kota'])
|
||||||
|
->where('status', 'dibatalkan')
|
||||||
|
->orderBy('updated_at', 'desc')
|
||||||
|
->paginate(15);
|
||||||
|
|
||||||
|
return view('admin.cancelled-orders', compact('cancelledOrders'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Menampilkan detail pesanan yang dibatalkan
|
||||||
|
*/
|
||||||
|
public function showCancelledOrder($id)
|
||||||
|
{
|
||||||
|
if (Auth::user()->tipe_pengguna !== 'admin') {
|
||||||
|
return redirect()->route('dashboard')->with('error', 'Akses ditolak.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$sewa = Sewa::with(['user', 'paket', 'kota'])->findOrFail($id);
|
||||||
|
|
||||||
|
if ($sewa->status !== 'dibatalkan') {
|
||||||
|
return redirect()->route('admin.cancelled-orders')->with('error', 'Pesanan ini tidak dibatalkan.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return view('admin.cancelled-order-detail', compact('sewa'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API untuk mendapatkan jumlah pesanan yang dibatalkan (untuk notifikasi)
|
||||||
|
*/
|
||||||
|
public function getCancelledOrdersCount()
|
||||||
|
{
|
||||||
|
if (Auth::user()->tipe_pengguna !== 'admin') {
|
||||||
|
return response()->json(['error' => 'Unauthorized'], 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
$count = Sewa::where('status', 'dibatalkan')
|
||||||
|
->whereNotNull('detail_status')
|
||||||
|
->where('updated_at', '>=', now()->subDays(7)) // Hanya 7 hari terakhir
|
||||||
|
->count();
|
||||||
|
|
||||||
|
return response()->json(['count' => $count]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API untuk mendapatkan notifikasi pembatalan terbaru
|
||||||
|
*/
|
||||||
|
public function getRecentCancellations()
|
||||||
|
{
|
||||||
|
if (Auth::user()->tipe_pengguna !== 'admin') {
|
||||||
|
return response()->json(['error' => 'Unauthorized'], 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
$recentCancellations = Sewa::with(['user', 'paket'])
|
||||||
|
->where('status', 'dibatalkan')
|
||||||
|
->whereNotNull('detail_status')
|
||||||
|
->where('updated_at', '>=', now()->subHours(24)) // Hanya 24 jam terakhir
|
||||||
|
->orderBy('updated_at', 'desc')
|
||||||
|
->take(5)
|
||||||
|
->get()
|
||||||
|
->map(function ($cancellation) {
|
||||||
|
return [
|
||||||
|
'id' => $cancellation->id,
|
||||||
|
'user_name' => $cancellation->user->name ?? 'N/A',
|
||||||
|
'paket_name' => $cancellation->paket->nama ?? 'N/A',
|
||||||
|
'alasan' => $cancellation->detail_status,
|
||||||
|
'cancelled_at' => $cancellation->updated_at->diffForHumans(),
|
||||||
|
'total_harga' => number_format($cancellation->total_harga, 0, ',', '.')
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
return response()->json(['cancellations' => $recentCancellations]);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -8,6 +8,14 @@
|
||||||
|
|
||||||
class VerifikasiController extends Controller
|
class VerifikasiController extends Controller
|
||||||
{
|
{
|
||||||
|
// Konstanta untuk opsi alasan penolakan
|
||||||
|
const ALASAN_PENOLAKAN = [
|
||||||
|
'Bukti pembayaran tidak valid',
|
||||||
|
'Jaminan tidak sesuai',
|
||||||
|
'Data tidak lengkap',
|
||||||
|
'Lainnya'
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Menampilkan daftar pembayaran yang perlu diverifikasi
|
* Menampilkan daftar pembayaran yang perlu diverifikasi
|
||||||
*/
|
*/
|
||||||
|
@ -51,7 +59,7 @@ public function approve($id)
|
||||||
/**
|
/**
|
||||||
* Menolak pembayaran
|
* Menolak pembayaran
|
||||||
*/
|
*/
|
||||||
public function reject($id)
|
public function reject(Request $request, $id)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$sewa = Sewa::findOrFail($id);
|
$sewa = Sewa::findOrFail($id);
|
||||||
|
@ -61,9 +69,32 @@ public function reject($id)
|
||||||
return back()->with('error', 'Status sewa tidak valid untuk ditolak.');
|
return back()->with('error', 'Status sewa tidak valid untuk ditolak.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update status menjadi ditolak
|
// Validasi alasan penolakan
|
||||||
|
$request->validate([
|
||||||
|
'alasan_penolakan' => 'required|string|max:255',
|
||||||
|
'alasan_lainnya' => 'nullable|string|max:255'
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Ambil alasan penolakan
|
||||||
|
$alasan = trim($request->alasan_penolakan);
|
||||||
|
if ($alasan === 'Lainnya') {
|
||||||
|
$alasanLainnya = trim($request->alasan_lainnya ?? '');
|
||||||
|
if (empty($alasanLainnya)) {
|
||||||
|
return back()->with('error', 'Silakan isi alasan lainnya.');
|
||||||
|
}
|
||||||
|
$alasan = $alasanLainnya;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pastikan alasan tidak kosong
|
||||||
|
if (empty($alasan)) {
|
||||||
|
return back()->with('error', 'Alasan penolakan tidak boleh kosong.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update status menjadi ditolak dan simpan alasan ke detail_status
|
||||||
$sewa->update([
|
$sewa->update([
|
||||||
'status' => 'ditolak'
|
'status' => 'ditolak',
|
||||||
|
'detail_status' => $alasan,
|
||||||
|
'catatan' => 'Pembayaran ditolak: ' . $alasan
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return back()->with('success', 'Pembayaran telah ditolak.');
|
return back()->with('success', 'Pembayaran telah ditolak.');
|
||||||
|
@ -71,4 +102,14 @@ public function reject($id)
|
||||||
return back()->with('error', 'Terjadi kesalahan: ' . $e->getMessage());
|
return back()->with('error', 'Terjadi kesalahan: ' . $e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mendapatkan daftar alasan penolakan
|
||||||
|
*/
|
||||||
|
public function getAlasanPenolakan()
|
||||||
|
{
|
||||||
|
return response()->json([
|
||||||
|
'alasan_penolakan' => self::ALASAN_PENOLAKAN
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -18,7 +18,9 @@ public function index()
|
||||||
'active_rentals' => Sewa::where('user_id', $user->id)
|
'active_rentals' => Sewa::where('user_id', $user->id)
|
||||||
->whereIn('status', ['menunggu', 'diproses'])
|
->whereIn('status', ['menunggu', 'diproses'])
|
||||||
->count(),
|
->count(),
|
||||||
'total_rentals' => Sewa::where('user_id', $user->id)->count(),
|
'total_rentals' => Sewa::where('user_id', $user->id)
|
||||||
|
->whereIn('status', ['disetujui', 'selesai'])
|
||||||
|
->count(),
|
||||||
'total_spent' => Sewa::where('user_id', $user->id)
|
'total_spent' => Sewa::where('user_id', $user->id)
|
||||||
->where('status', 'selesai')
|
->where('status', 'selesai')
|
||||||
->sum('total_harga')
|
->sum('total_harga')
|
||||||
|
@ -34,6 +36,7 @@ private function getRecentRentals($userId)
|
||||||
{
|
{
|
||||||
$rentals = Sewa::with('paket')
|
$rentals = Sewa::with('paket')
|
||||||
->where('user_id', $userId)
|
->where('user_id', $userId)
|
||||||
|
->whereIn('status', ['disetujui', 'selesai'])
|
||||||
->latest()
|
->latest()
|
||||||
->take(5)
|
->take(5)
|
||||||
->get();
|
->get();
|
||||||
|
|
|
@ -22,21 +22,26 @@ public function index()
|
||||||
// Cek tipe pengguna yang sedang login
|
// Cek tipe pengguna yang sedang login
|
||||||
$userType = Auth::user()->tipe_pengguna;
|
$userType = Auth::user()->tipe_pengguna;
|
||||||
|
|
||||||
// Data untuk dashboard
|
// Jika user adalah customer, redirect langsung ke halaman sewa
|
||||||
|
if ($userType === 'user') {
|
||||||
|
return redirect()->route('sewa.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data untuk dashboard (hanya untuk admin)
|
||||||
$stats = [
|
$stats = [
|
||||||
'pengguna' => User::where('tipe_pengguna', 'user')->count(),
|
'pengguna' => User::where('tipe_pengguna', 'user')->count(),
|
||||||
'admin' => User::where('tipe_pengguna', 'admin')->count(),
|
'admin' => User::where('tipe_pengguna', 'admin')->count(),
|
||||||
'total_pengguna' => User::count(),
|
'total_pengguna' => User::count(),
|
||||||
'barang' => Barang::count(),
|
'barang' => Barang::count(),
|
||||||
'sewa' => DB::table('sewas')->count()
|
'sewa' => DB::table('sewas')->whereIn('status', ['disetujui', 'selesai'])->count()
|
||||||
];
|
];
|
||||||
|
|
||||||
// Data grafik per tahun
|
// Data grafik per tahun
|
||||||
$yearlyStats = DB::table('sewas')
|
$yearlyStats = DB::table('sewas')
|
||||||
->select(
|
->select(
|
||||||
DB::raw('YEAR(created_at) as tahun'),
|
DB::raw('YEAR(created_at) as tahun'),
|
||||||
DB::raw('COUNT(*) as total_sewa'),
|
DB::raw('COUNT(CASE WHEN status IN ("disetujui", "selesai") THEN 1 END) as total_sewa'),
|
||||||
DB::raw('SUM(total_harga) as total_pemasukan'),
|
DB::raw('SUM(CASE WHEN status IN ("disetujui", "selesai") THEN total_harga ELSE 0 END) as total_pemasukan'),
|
||||||
DB::raw('0 as total_pengeluaran') // Sementara set 0 karena belum ada kolom biaya_operasional
|
DB::raw('0 as total_pengeluaran') // Sementara set 0 karena belum ada kolom biaya_operasional
|
||||||
)
|
)
|
||||||
->groupBy('tahun')
|
->groupBy('tahun')
|
||||||
|
@ -121,63 +126,35 @@ public function index()
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
// Debug data
|
// Data aktivitas (hanya untuk admin)
|
||||||
// dd($chartData, $userChartData);
|
|
||||||
|
|
||||||
// Data aktivitas
|
|
||||||
$aktivitas = [];
|
$aktivitas = [];
|
||||||
|
|
||||||
// Jika user adalah admin, tampilkan semua data
|
// Ambil user terbaru yang mendaftar (baik admin maupun user)
|
||||||
if ($userType === 'admin') {
|
$latestUsers = User::latest()->take(5)->get();
|
||||||
// Ambil user terbaru yang mendaftar (baik admin maupun user)
|
|
||||||
$latestUsers = User::latest()->take(5)->get();
|
|
||||||
|
|
||||||
foreach ($latestUsers as $user) {
|
foreach ($latestUsers as $user) {
|
||||||
$aktivitas[] = [
|
|
||||||
'type' => 'pengguna',
|
|
||||||
'title' => 'Pengguna ' . ucfirst($user->tipe_pengguna),
|
|
||||||
'description' => $user->nama . ' (' . $user->tipe_pengguna . ')',
|
|
||||||
'time' => Carbon::parse($user->created_at)->diffForHumans(),
|
|
||||||
'icon_color' => $user->tipe_pengguna === 'admin' ? 'indigo' : 'blue'
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tambahkan aktivitas sewa terbaru
|
|
||||||
$latestSewa = Sewa::with(['user', 'paket'])->latest()->first();
|
|
||||||
if ($latestSewa) {
|
|
||||||
$aktivitas[] = [
|
|
||||||
'type' => 'sewa',
|
|
||||||
'title' => 'Pemesanan Baru',
|
|
||||||
'description' => $latestSewa->user->nama . ' memesan paket ' . $latestSewa->paket->nama_paket,
|
|
||||||
'time' => Carbon::parse($latestSewa->created_at)->diffForHumans(),
|
|
||||||
'icon_color' => 'green'
|
|
||||||
];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Jika user adalah customer, hanya tampilkan data terbatas
|
|
||||||
$aktivitas[] = [
|
$aktivitas[] = [
|
||||||
'type' => 'info',
|
'type' => 'pengguna',
|
||||||
'title' => 'Selamat Datang',
|
'title' => 'Pengguna ' . ucfirst($user->tipe_pengguna),
|
||||||
'description' => 'Anda login sebagai pengguna biasa. Anda hanya dapat melihat informasi.',
|
'description' => $user->nama . ' (' . $user->tipe_pengguna . ')',
|
||||||
'time' => 'Saat ini',
|
'time' => Carbon::parse($user->created_at)->diffForHumans(),
|
||||||
'icon_color' => 'blue'
|
'icon_color' => $user->tipe_pengguna === 'admin' ? 'indigo' : 'blue'
|
||||||
];
|
];
|
||||||
|
}
|
||||||
|
|
||||||
// Tampilkan riwayat sewa pengguna ini saja
|
// Tambahkan aktivitas sewa terbaru
|
||||||
$userSewa = Sewa::where('user_id', Auth::id())
|
$latestSewa = Sewa::with(['user', 'paket'])
|
||||||
->with('paket')
|
->whereIn('status', ['disetujui', 'selesai'])
|
||||||
->latest()
|
->latest()
|
||||||
->first();
|
->first();
|
||||||
|
if ($latestSewa) {
|
||||||
if ($userSewa) {
|
$aktivitas[] = [
|
||||||
$aktivitas[] = [
|
'type' => 'sewa',
|
||||||
'type' => 'sewa',
|
'title' => 'Pemesanan Baru',
|
||||||
'title' => 'Pesanan Terakhir Anda',
|
'description' => $latestSewa->user->nama . ' memesan paket ' . $latestSewa->paket->nama_paket,
|
||||||
'description' => 'Paket: ' . $userSewa->paket->nama_paket,
|
'time' => Carbon::parse($latestSewa->created_at)->diffForHumans(),
|
||||||
'time' => Carbon::parse($userSewa->created_at)->diffForHumans(),
|
'icon_color' => 'green'
|
||||||
'icon_color' => 'green'
|
];
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return view('dashboard', compact('stats', 'chartData', 'userChartData', 'aktivitas', 'userType'));
|
return view('dashboard', compact('stats', 'chartData', 'userChartData', 'aktivitas', 'userType'));
|
||||||
|
|
|
@ -209,7 +209,7 @@ public function update(Request $request, $id)
|
||||||
}
|
}
|
||||||
|
|
||||||
DB::commit();
|
DB::commit();
|
||||||
return redirect()->route('paket')->with('success', 'Paket berhasil diperbarui!');
|
return redirect()->route('paket.index')->with('success', 'Paket berhasil diperbarui!');
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
DB::rollback();
|
DB::rollback();
|
||||||
|
@ -402,17 +402,17 @@ public function activate($id)
|
||||||
->first();
|
->first();
|
||||||
|
|
||||||
if (!$oldestSewa) {
|
if (!$oldestSewa) {
|
||||||
return redirect()->route('paket')->with('error', 'Tidak ada penyewaan aktif yang dapat diselesaikan.');
|
return redirect()->route('paket.index')->with('error', 'Tidak ada penyewaan aktif yang dapat diselesaikan.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update status sewa menjadi completed hanya untuk sewa terlama
|
// Update status sewa menjadi selesai hanya untuk sewa terlama
|
||||||
$oldestSewa->update(['status' => 'completed']);
|
$oldestSewa->update(['status' => 'selesai']);
|
||||||
|
|
||||||
DB::commit();
|
DB::commit();
|
||||||
return redirect()->route('paket')->with('success', 'Satu unit paket berhasil diaktifkan kembali.');
|
return redirect()->route('paket.index')->with('success', 'Satu unit paket berhasil diaktifkan kembali.');
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
DB::rollback();
|
DB::rollback();
|
||||||
return redirect()->route('paket')->with('error', 'Terjadi kesalahan: ' . $e->getMessage());
|
return redirect()->route('paket.index')->with('error', 'Terjadi kesalahan: ' . $e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -426,20 +426,20 @@ public function activateAll($id)
|
||||||
|
|
||||||
$paket = Paket::findOrFail($id);
|
$paket = Paket::findOrFail($id);
|
||||||
|
|
||||||
// Update status semua sewa yang masih aktif menjadi completed
|
// Update status semua sewa yang masih aktif menjadi selesai
|
||||||
$count = $paket->sewas()
|
$count = $paket->sewas()
|
||||||
->whereIn('status', ['confirmed', 'ongoing'])
|
->whereIn('status', ['confirmed', 'ongoing'])
|
||||||
->update(['status' => 'completed']);
|
->update(['status' => 'selesai']);
|
||||||
|
|
||||||
if ($count === 0) {
|
if ($count === 0) {
|
||||||
return redirect()->route('paket')->with('error', 'Tidak ada penyewaan aktif yang dapat diselesaikan.');
|
return redirect()->route('paket.index')->with('error', 'Tidak ada penyewaan aktif yang dapat diselesaikan.');
|
||||||
}
|
}
|
||||||
|
|
||||||
DB::commit();
|
DB::commit();
|
||||||
return redirect()->route('paket')->with('success', 'Semua unit paket berhasil diaktifkan kembali.');
|
return redirect()->route('paket.index')->with('success', 'Semua unit paket berhasil diaktifkan kembali.');
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
DB::rollback();
|
DB::rollback();
|
||||||
return redirect()->route('paket')->with('error', 'Terjadi kesalahan: ' . $e->getMessage());
|
return redirect()->route('paket.index')->with('error', 'Terjadi kesalahan: ' . $e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,9 @@ class PenggunaController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
|
// Middleware untuk memastikan user sudah login
|
||||||
|
$this->middleware('auth');
|
||||||
|
|
||||||
// Middleware untuk method yang membutuhkan akses admin
|
// Middleware untuk method yang membutuhkan akses admin
|
||||||
$this->middleware('admin')->only(['create', 'store', 'edit', 'update', 'destroy']);
|
$this->middleware('admin')->only(['create', 'store', 'edit', 'update', 'destroy']);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class RiwayatController extends Controller
|
class RiwayatController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -21,6 +23,23 @@ public function index()
|
||||||
return view('riwayat', compact('sewas'));
|
return view('riwayat', compact('sewas'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Menampilkan riwayat untuk admin
|
||||||
|
*/
|
||||||
|
public function adminIndex()
|
||||||
|
{
|
||||||
|
if (Auth::user()->tipe_pengguna !== 'admin') {
|
||||||
|
return redirect()->route('dashboard')->with('error', 'Akses ditolak.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$sewas = Sewa::with(['paket', 'kota', 'user'])
|
||||||
|
->where('status', '!=', 'draft')
|
||||||
|
->orderBy('created_at', 'desc')
|
||||||
|
->get();
|
||||||
|
|
||||||
|
return view('admin.riwayat', compact('sewas'));
|
||||||
|
}
|
||||||
|
|
||||||
public function updateStatus(Request $request, $id)
|
public function updateStatus(Request $request, $id)
|
||||||
{
|
{
|
||||||
if (Auth::user()->tipe_pengguna !== 'admin') {
|
if (Auth::user()->tipe_pengguna !== 'admin') {
|
||||||
|
@ -28,7 +47,7 @@ public function updateStatus(Request $request, $id)
|
||||||
}
|
}
|
||||||
|
|
||||||
$request->validate([
|
$request->validate([
|
||||||
'status' => 'required|in:completed'
|
'status' => 'required|in:selesai'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$sewa = Sewa::findOrFail($id);
|
$sewa = Sewa::findOrFail($id);
|
||||||
|
@ -40,7 +59,7 @@ public function updateStatus(Request $request, $id)
|
||||||
$sewa->status = $request->status;
|
$sewa->status = $request->status;
|
||||||
$sewa->save();
|
$sewa->save();
|
||||||
|
|
||||||
return back()->with('success', 'Status berhasil diperbarui menjadi completed.');
|
return back()->with('success', 'Status berhasil diperbarui menjadi selesai. Stok paket telah diaktifkan kembali.');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function hapus($id)
|
public function hapus($id)
|
||||||
|
@ -52,7 +71,7 @@ public function hapus($id)
|
||||||
->with('error', 'Anda tidak memiliki akses untuk menghapus pesanan ini.');
|
->with('error', 'Anda tidak memiliki akses untuk menghapus pesanan ini.');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!in_array($sewa->status, ['completed', 'dibatalkan'])) {
|
if (!in_array($sewa->status, ['selesai', 'dibatalkan'])) {
|
||||||
return redirect()->route('riwayat')
|
return redirect()->route('riwayat')
|
||||||
->with('error', 'Hanya pesanan yang sudah selesai atau dibatalkan yang dapat dihapus.');
|
->with('error', 'Hanya pesanan yang sudah selesai atau dibatalkan yang dapat dihapus.');
|
||||||
}
|
}
|
||||||
|
@ -70,8 +89,35 @@ public function hapus($id)
|
||||||
->with('success', 'Riwayat pesanan berhasil dihapus.');
|
->with('success', 'Riwayat pesanan berhasil dihapus.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mengaktifkan stok paket dari halaman riwayat
|
||||||
|
*/
|
||||||
|
public function activateStock($id)
|
||||||
|
{
|
||||||
|
if (Auth::user()->tipe_pengguna !== 'admin') {
|
||||||
|
return redirect()->route('dashboard')->with('error', 'Akses ditolak.');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$sewa = Sewa::with('paket')->findOrFail($id);
|
||||||
|
|
||||||
|
// Pastikan status sewa adalah confirmed atau ongoing
|
||||||
|
if (!in_array($sewa->status, ['confirmed', 'ongoing'])) {
|
||||||
|
return back()->with('error', 'Hanya sewa dengan status confirmed atau ongoing yang dapat diaktifkan.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update status sewa menjadi selesai
|
||||||
|
$sewa->update(['status' => 'selesai']);
|
||||||
|
|
||||||
|
return back()->with('success', 'Stok paket berhasil diaktifkan kembali. Status sewa diubah menjadi selesai.');
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return back()->with('error', 'Terjadi kesalahan: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function show($id)
|
public function show($id)
|
||||||
{
|
{
|
||||||
|
try {
|
||||||
$sewa = Sewa::with(['paket', 'kota'])->findOrFail($id);
|
$sewa = Sewa::with(['paket', 'kota'])->findOrFail($id);
|
||||||
|
|
||||||
// Pastikan hanya user yang berhak yang bisa akses
|
// Pastikan hanya user yang berhak yang bisa akses
|
||||||
|
@ -79,18 +125,206 @@ public function show($id)
|
||||||
return response()->json(['error' => 'Unauthorized'], 403);
|
return response()->json(['error' => 'Unauthorized'], 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
$nomor_rekening = Setting::where('key', 'nomor_rekening')->first()->value ?? null;
|
// Cek apakah tabel settings ada dan ambil nomor rekening dengan aman
|
||||||
|
$nomor_rekening = null;
|
||||||
|
try {
|
||||||
|
if (Schema::hasTable('settings')) {
|
||||||
|
$setting = Setting::where('key', 'nomor_rekening')->first();
|
||||||
|
$nomor_rekening = $setting ? $setting->value : null;
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
// Jika ada error saat mengakses tabel settings, set null
|
||||||
|
$nomor_rekening = null;
|
||||||
|
}
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'tanggal_pembayaran' => $sewa->tanggal_pembayaran,
|
'tanggal_pembayaran' => $sewa->tanggal_pembayaran,
|
||||||
'status_pembayaran' => $sewa->status,
|
'status_pembayaran' => $sewa->status,
|
||||||
|
'detail_status' => $sewa->detail_status,
|
||||||
'lokasi' => $sewa->lokasi,
|
'lokasi' => $sewa->lokasi,
|
||||||
'kota' => $sewa->kota,
|
'kota' => $sewa->kota ?? null,
|
||||||
'ongkir' => $sewa->ongkir,
|
'ongkir' => $sewa->ongkir,
|
||||||
'bukti_pembayaran' => $sewa->bukti_pembayaran,
|
'bukti_pembayaran' => $sewa->bukti_pembayaran,
|
||||||
'foto_jaminan' => $sewa->foto_jaminan,
|
'foto_jaminan' => $sewa->foto_jaminan,
|
||||||
'jenis_jaminan' => $sewa->jenis_jaminan,
|
'jenis_jaminan' => $sewa->jenis_jaminan,
|
||||||
'nomor_rekening' => $nomor_rekening,
|
'nomor_rekening' => $nomor_rekening,
|
||||||
|
'paket' => $sewa->paket ?? null,
|
||||||
]);
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return response()->json([
|
||||||
|
'error' => 'Terjadi kesalahan: ' . $e->getMessage()
|
||||||
|
], 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Membatalkan pesanan
|
||||||
|
*/
|
||||||
|
public function cancel(Request $request, $id)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$sewa = Sewa::findOrFail($id);
|
||||||
|
|
||||||
|
// Pastikan hanya user yang berhak yang bisa membatalkan
|
||||||
|
if ($sewa->user_id != Auth::id()) {
|
||||||
|
if ($request->ajax()) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Anda tidak memiliki akses untuk membatalkan pesanan ini.'
|
||||||
|
], 403);
|
||||||
|
}
|
||||||
|
return redirect()->route('riwayat')
|
||||||
|
->with('error', 'Anda tidak memiliki akses untuk membatalkan pesanan ini.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cek apakah status memungkinkan untuk dibatalkan
|
||||||
|
if (in_array($sewa->status, ['selesai', 'dibatalkan', 'ongoing'])) {
|
||||||
|
if ($request->ajax()) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Pesanan dengan status ini tidak dapat dibatalkan.'
|
||||||
|
], 400);
|
||||||
|
}
|
||||||
|
return redirect()->route('riwayat')
|
||||||
|
->with('error', 'Pesanan dengan status ini tidak dapat dibatalkan.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ambil alasan pembatalan dari request
|
||||||
|
$alasanPembatalan = $request->input('alasan_pembatalan', 'Tidak ada alasan yang diberikan');
|
||||||
|
|
||||||
|
// Update status menjadi dibatalkan dan simpan alasan
|
||||||
|
$sewa->status = 'dibatalkan';
|
||||||
|
$sewa->detail_status = $alasanPembatalan;
|
||||||
|
$sewa->save();
|
||||||
|
|
||||||
|
// Log aktivitas pembatalan untuk dashboard admin
|
||||||
|
Log::info('Pesanan dibatalkan dengan alasan', [
|
||||||
|
'sewa_id' => $sewa->id,
|
||||||
|
'user_id' => $sewa->user_id,
|
||||||
|
'user_name' => Auth::user()->name,
|
||||||
|
'paket_name' => $sewa->paket->nama ?? 'N/A',
|
||||||
|
'alasan_pembatalan' => $alasanPembatalan,
|
||||||
|
'cancelled_at' => now()
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($request->ajax()) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'Pesanan berhasil dibatalkan. Alasan pembatalan telah dikirim ke admin.',
|
||||||
|
'data' => [
|
||||||
|
'sewa_id' => $sewa->id,
|
||||||
|
'status' => $sewa->status,
|
||||||
|
'alasan' => $alasanPembatalan
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('riwayat')
|
||||||
|
->with('success', 'Pesanan berhasil dibatalkan. Alasan pembatalan telah dikirim ke admin.');
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
if ($request->ajax()) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Terjadi kesalahan saat membatalkan pesanan: ' . $e->getMessage()
|
||||||
|
], 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('riwayat')
|
||||||
|
->with('error', 'Terjadi kesalahan saat membatalkan pesanan: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Menampilkan form pembatalan
|
||||||
|
*/
|
||||||
|
public function showCancelForm($id)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$sewa = Sewa::with(['paket', 'kota'])->findOrFail($id);
|
||||||
|
|
||||||
|
// Pastikan hanya user yang berhak yang bisa akses
|
||||||
|
if ($sewa->user_id != Auth::id()) {
|
||||||
|
return redirect()->route('riwayat')
|
||||||
|
->with('error', 'Anda tidak memiliki akses untuk membatalkan pesanan ini.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cek apakah status memungkinkan untuk dibatalkan
|
||||||
|
if (in_array($sewa->status, ['selesai', 'dibatalkan', 'ongoing'])) {
|
||||||
|
return redirect()->route('riwayat')
|
||||||
|
->with('error', 'Pesanan dengan status ini tidak dapat dibatalkan.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return view('riwayat.cancel-form', compact('sewa'));
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return redirect()->route('riwayat')
|
||||||
|
->with('error', 'Terjadi kesalahan: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Memproses pembatalan pesanan
|
||||||
|
*/
|
||||||
|
public function processCancel(Request $request, $id)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$request->validate([
|
||||||
|
'alasan_pembatalan' => 'required|string|max:500'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$sewa = Sewa::findOrFail($id);
|
||||||
|
|
||||||
|
// Pastikan hanya user yang berhak yang bisa membatalkan
|
||||||
|
if ($sewa->user_id != Auth::id()) {
|
||||||
|
return redirect()->route('riwayat')
|
||||||
|
->with('error', 'Anda tidak memiliki akses untuk membatalkan pesanan ini.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cek apakah status memungkinkan untuk dibatalkan
|
||||||
|
if (in_array($sewa->status, ['selesai', 'dibatalkan', 'ongoing'])) {
|
||||||
|
return redirect()->route('riwayat')
|
||||||
|
->with('error', 'Pesanan dengan status ini tidak dapat dibatalkan.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update status menjadi dibatalkan dan simpan alasan
|
||||||
|
$sewa->status = 'dibatalkan';
|
||||||
|
$sewa->detail_status = $request->alasan_pembatalan;
|
||||||
|
$sewa->save();
|
||||||
|
|
||||||
|
// Log aktivitas pembatalan untuk dashboard admin
|
||||||
|
Log::info('Pesanan dibatalkan dengan alasan', [
|
||||||
|
'sewa_id' => $sewa->id,
|
||||||
|
'user_id' => $sewa->user_id,
|
||||||
|
'user_name' => Auth::user()->name,
|
||||||
|
'paket_name' => $sewa->paket->nama ?? 'N/A',
|
||||||
|
'alasan_pembatalan' => $request->alasan_pembatalan,
|
||||||
|
'cancelled_at' => now()
|
||||||
|
]);
|
||||||
|
|
||||||
|
return redirect()->route('riwayat')
|
||||||
|
->with('success', 'Pesanan berhasil dibatalkan.');
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return redirect()->route('riwayat')
|
||||||
|
->with('error', 'Terjadi kesalahan saat membatalkan pesanan: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Menampilkan form update pembayaran
|
||||||
|
*/
|
||||||
|
public function showUpdatePaymentForm($id)
|
||||||
|
{
|
||||||
|
if (Auth::user()->tipe_pengguna !== 'admin') {
|
||||||
|
return redirect()->route('dashboard')->with('error', 'Akses ditolak.');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$sewa = Sewa::with(['paket', 'kota', 'user'])->findOrFail($id);
|
||||||
|
return view('admin.update-payment-form', compact('sewa'));
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return back()->with('error', 'Terjadi kesalahan: ' . $e->getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,11 +56,7 @@ public function create($id)
|
||||||
$paket = Paket::with('ongkirKota')->findOrFail($id);
|
$paket = Paket::with('ongkirKota')->findOrFail($id);
|
||||||
|
|
||||||
// Cek apakah paket tersedia
|
// Cek apakah paket tersedia
|
||||||
$activeSewa = $paket->sewas()
|
if (!$paket->is_available) {
|
||||||
->whereIn('status', ['confirmed', 'ongoing'])
|
|
||||||
->count();
|
|
||||||
|
|
||||||
if ($activeSewa >= $paket->stok) {
|
|
||||||
return redirect()->route('sewa.index')
|
return redirect()->route('sewa.index')
|
||||||
->with('error', 'Maaf, paket ini sedang tidak tersedia.');
|
->with('error', 'Maaf, paket ini sedang tidak tersedia.');
|
||||||
}
|
}
|
||||||
|
@ -89,12 +85,16 @@ public function store(Request $request)
|
||||||
try {
|
try {
|
||||||
$paket = Paket::findOrFail($request->paket_id);
|
$paket = Paket::findOrFail($request->paket_id);
|
||||||
|
|
||||||
// Cek ketersediaan paket
|
// Cek ketersediaan paket untuk tanggal yang dipilih
|
||||||
$activeSewa = $paket->sewas()
|
$activeSewa = $paket->sewas()
|
||||||
->whereIn('status', ['confirmed', 'ongoing'])
|
->whereIn('status', ['confirmed', 'ongoing'])
|
||||||
->where(function($query) use ($request) {
|
->where(function($query) use ($request) {
|
||||||
$query->whereBetween('tanggal_mulai', [$request->tanggal_mulai, $request->tanggal_selesai])
|
$query->whereBetween('tanggal_mulai', [$request->tanggal_mulai, $request->tanggal_selesai])
|
||||||
->orWhereBetween('tanggal_selesai', [$request->tanggal_mulai, $request->tanggal_selesai]);
|
->orWhereBetween('tanggal_selesai', [$request->tanggal_mulai, $request->tanggal_selesai])
|
||||||
|
->orWhere(function($q) use ($request) {
|
||||||
|
$q->where('tanggal_mulai', '<=', $request->tanggal_mulai)
|
||||||
|
->where('tanggal_selesai', '>=', $request->tanggal_selesai);
|
||||||
|
});
|
||||||
})
|
})
|
||||||
->count();
|
->count();
|
||||||
|
|
||||||
|
@ -309,4 +309,34 @@ public function detail($id)
|
||||||
], 500);
|
], 500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function detailJson($id)
|
||||||
|
{
|
||||||
|
$sewa = Sewa::with(['paket.barangs', 'user', 'kota'])->findOrFail($id);
|
||||||
|
return response()->json([
|
||||||
|
'id' => $sewa->id,
|
||||||
|
'paket' => [
|
||||||
|
'nama_paket' => $sewa->paket->nama_paket,
|
||||||
|
'jenis_paket' => $sewa->paket->jenis_paket,
|
||||||
|
'harga' => $sewa->paket->harga,
|
||||||
|
],
|
||||||
|
'user' => [
|
||||||
|
'nama' => $sewa->user->nama,
|
||||||
|
'email' => $sewa->user->email,
|
||||||
|
],
|
||||||
|
'tanggal_mulai' => $sewa->tanggal_mulai,
|
||||||
|
'tanggal_selesai' => $sewa->tanggal_selesai,
|
||||||
|
'status' => $sewa->status,
|
||||||
|
'total_harga' => $sewa->total_harga,
|
||||||
|
'lokasi' => $sewa->lokasi,
|
||||||
|
'kota' => $sewa->kota ? $sewa->kota->nama_kota : null,
|
||||||
|
'catatan' => $sewa->catatan,
|
||||||
|
'barangs' => $sewa->paket->barangs->map(function($barang) {
|
||||||
|
return [
|
||||||
|
'nama_barang' => $barang->nama_barang,
|
||||||
|
'jumlah' => $barang->pivot->jumlah
|
||||||
|
];
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -10,6 +10,9 @@ class UserController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
|
// Middleware untuk memastikan user sudah login
|
||||||
|
$this->middleware('auth');
|
||||||
|
|
||||||
// Middleware hanya untuk admin yang mengakses destroy
|
// Middleware hanya untuk admin yang mengakses destroy
|
||||||
$this->middleware('admin')->only(['destroy']);
|
$this->middleware('admin')->only(['destroy']);
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,4 +123,46 @@ public function sewas()
|
||||||
{
|
{
|
||||||
return $this->hasMany(Sewa::class);
|
return $this->hasMany(Sewa::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Menghitung jumlah sewa yang sedang aktif (confirmed/ongoing)
|
||||||
|
*/
|
||||||
|
public function getActiveSewaCountAttribute()
|
||||||
|
{
|
||||||
|
return $this->sewas()
|
||||||
|
->whereIn('status', ['confirmed', 'ongoing'])
|
||||||
|
->count();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Menghitung stok yang tersedia
|
||||||
|
*/
|
||||||
|
public function getStokTersediaAttribute()
|
||||||
|
{
|
||||||
|
return max(0, $this->stok - $this->active_sewa_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cek apakah paket tersedia untuk disewa
|
||||||
|
*/
|
||||||
|
public function getIsAvailableAttribute()
|
||||||
|
{
|
||||||
|
return $this->status === 'aktif' && $this->stok_tersedia > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mendapatkan status ketersediaan yang diformat
|
||||||
|
*/
|
||||||
|
public function getStatusKetersediaanAttribute()
|
||||||
|
{
|
||||||
|
if ($this->status !== 'aktif') {
|
||||||
|
return 'Tidak Aktif';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->stok_tersedia <= 0) {
|
||||||
|
return 'Sedang Disewa Semua';
|
||||||
|
}
|
||||||
|
|
||||||
|
return "Tersedia ({$this->stok_tersedia} unit)";
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -21,6 +21,7 @@ class Sewa extends Model
|
||||||
'catatan',
|
'catatan',
|
||||||
'total_harga',
|
'total_harga',
|
||||||
'status',
|
'status',
|
||||||
|
'detail_status',
|
||||||
'bukti_pembayaran',
|
'bukti_pembayaran',
|
||||||
'tanggal_pembayaran',
|
'tanggal_pembayaran',
|
||||||
'jenis_jaminan',
|
'jenis_jaminan',
|
||||||
|
@ -92,7 +93,7 @@ public function scopeStatus($query, $status)
|
||||||
// Scope untuk sewa yang aktif
|
// Scope untuk sewa yang aktif
|
||||||
public function scopeAktif($query)
|
public function scopeAktif($query)
|
||||||
{
|
{
|
||||||
return $query->whereIn('status', ['disetujui'])
|
return $query->whereIn('status', ['confirmed'])
|
||||||
->where('tanggal_selesai', '>=', now());
|
->where('tanggal_selesai', '>=', now());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?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::table('sewas', function (Blueprint $table) {
|
||||||
|
$table->string('detail_status')->nullable()->after('status')->comment('Detail status untuk alasan penolakan atau informasi tambahan');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('sewas', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('detail_status');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
|
@ -91,12 +91,12 @@
|
||||||
|
|
||||||
<!-- Ongkir per Kota -->
|
<!-- Ongkir per Kota -->
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<label class="block text-gray-700 font-medium mb-2">Ongkir per Kota</label>
|
<label class="block text-gray-700 font-medium mb-2">Ongkir per Kabupaten</label>
|
||||||
<div id="ongkir-container">
|
<div id="ongkir-container">
|
||||||
<div class="ongkir-form mb-2 p-4 border rounded-lg bg-gray-50">
|
<div class="ongkir-form mb-2 p-4 border rounded-lg bg-gray-50">
|
||||||
<div class="grid grid-cols-2 gap-4">
|
<div class="grid grid-cols-2 gap-4">
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-600">Nama Kota</label>
|
<label class="block text-sm font-medium text-gray-600">Nama Kabupaten</label>
|
||||||
<input type="text" name="ongkir[0][nama_kota]" class="w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500">
|
<input type="text" name="ongkir[0][nama_kota]" class="w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
@ -110,7 +110,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" id="tambah-ongkir" class="mt-2 text-sm bg-green-500 hover:bg-green-600 text-white px-3 py-1 rounded">
|
<button type="button" id="tambah-ongkir" class="mt-2 text-sm bg-green-500 hover:bg-green-600 text-white px-3 py-1 rounded">
|
||||||
<i class="fas fa-plus mr-1"></i> Tambah Kota
|
<i class="fas fa-plus mr-1"></i> Tambah Kabupaten
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,167 @@
|
||||||
|
@extends('layouts.admin')
|
||||||
|
|
||||||
|
@section('title', 'Detail Pesanan Dibatalkan - INUFA')
|
||||||
|
|
||||||
|
@section('header', 'Detail Pesanan Dibatalkan')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="bg-white rounded-lg shadow-md p-6">
|
||||||
|
<div class="flex justify-between items-center mb-6">
|
||||||
|
<h2 class="text-xl font-semibold text-gray-800">Detail Pesanan #{{ $sewa->id }}</h2>
|
||||||
|
<div class="flex space-x-2">
|
||||||
|
<a href="{{ route('admin.cancelled-orders') }}" class="bg-gray-500 hover:bg-gray-600 text-white px-4 py-2 rounded-md text-sm">
|
||||||
|
Kembali ke Daftar
|
||||||
|
</a>
|
||||||
|
<a href="{{ route('admin.dashboard') }}" class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-md text-sm">
|
||||||
|
Dashboard
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if(session('success'))
|
||||||
|
<div class="bg-green-100 border-l-4 border-green-500 text-green-700 p-4 mb-4 rounded">
|
||||||
|
{{ session('success') }}
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if(session('error'))
|
||||||
|
<div class="bg-red-100 border-l-4 border-red-500 text-red-700 p-4 mb-4 rounded">
|
||||||
|
{{ session('error') }}
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<!-- Status Badge -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<span class="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-red-100 text-red-800">
|
||||||
|
<svg class="w-4 h-4 mr-1" fill="currentColor" viewBox="0 0 20 20">
|
||||||
|
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd" />
|
||||||
|
</svg>
|
||||||
|
Dibatalkan oleh Customer
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||||
|
<!-- Informasi Customer -->
|
||||||
|
<div class="bg-gray-50 p-6 rounded-lg">
|
||||||
|
<h3 class="text-lg font-semibold text-gray-800 mb-4">Informasi Customer</h3>
|
||||||
|
<div class="space-y-3">
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-600">Nama</label>
|
||||||
|
<p class="text-sm text-gray-900">{{ $sewa->user->name ?? 'N/A' }}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-600">Email</label>
|
||||||
|
<p class="text-sm text-gray-900">{{ $sewa->user->email ?? 'N/A' }}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-600">No. Telepon</label>
|
||||||
|
<p class="text-sm text-gray-900">{{ $sewa->user->no_telp ?? 'N/A' }}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-600">Alamat</label>
|
||||||
|
<p class="text-sm text-gray-900">{{ $sewa->user->alamat ?? 'N/A' }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Informasi Pesanan -->
|
||||||
|
<div class="bg-gray-50 p-6 rounded-lg">
|
||||||
|
<h3 class="text-lg font-semibold text-gray-800 mb-4">Informasi Pesanan</h3>
|
||||||
|
<div class="space-y-3">
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-600">ID Pesanan</label>
|
||||||
|
<p class="text-sm text-gray-900">#{{ $sewa->id }}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-600">Paket</label>
|
||||||
|
<p class="text-sm text-gray-900">{{ $sewa->paket->nama ?? 'N/A' }}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-600">Total Harga</label>
|
||||||
|
<p class="text-sm text-gray-900">Rp {{ number_format($sewa->total_harga, 0, ',', '.') }}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-600">Tanggal Pesanan</label>
|
||||||
|
<p class="text-sm text-gray-900">{{ $sewa->created_at->format('d/m/Y H:i') }}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-600">Tanggal Dibatalkan</label>
|
||||||
|
<p class="text-sm text-gray-900">{{ $sewa->updated_at->format('d/m/Y H:i') }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Alasan Pembatalan -->
|
||||||
|
<div class="mt-6 bg-red-50 border border-red-200 p-6 rounded-lg">
|
||||||
|
<h3 class="text-lg font-semibold text-red-800 mb-4">
|
||||||
|
<svg class="w-5 h-5 inline mr-2" fill="currentColor" viewBox="0 0 20 20">
|
||||||
|
<path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd" />
|
||||||
|
</svg>
|
||||||
|
Alasan Pembatalan
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
@if($sewa->detail_status)
|
||||||
|
<div class="bg-white p-4 rounded border border-red-200">
|
||||||
|
<p class="text-gray-800 leading-relaxed">{{ $sewa->detail_status }}</p>
|
||||||
|
</div>
|
||||||
|
@else
|
||||||
|
<div class="bg-white p-4 rounded border border-red-200">
|
||||||
|
<p class="text-gray-500 italic">Customer tidak memberikan alasan pembatalan.</p>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Detail Tambahan -->
|
||||||
|
@if($sewa->lokasi || $sewa->kota)
|
||||||
|
<div class="mt-6 bg-gray-50 p-6 rounded-lg">
|
||||||
|
<h3 class="text-lg font-semibold text-gray-800 mb-4">Detail Lokasi</h3>
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
|
@if($sewa->lokasi)
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-600">Lokasi</label>
|
||||||
|
<p class="text-sm text-gray-900">{{ $sewa->lokasi }}</p>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
@if($sewa->kota)
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-600">Kota</label>
|
||||||
|
<p class="text-sm text-gray-900">{{ $sewa->kota->nama ?? 'N/A' }}</p>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
@if($sewa->ongkir)
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-600">Ongkir</label>
|
||||||
|
<p class="text-sm text-gray-900">Rp {{ number_format($sewa->ongkir, 0, ',', '.') }}</p>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<!-- File Uploads -->
|
||||||
|
@if($sewa->bukti_pembayaran || $sewa->foto_jaminan)
|
||||||
|
<div class="mt-6 bg-gray-50 p-6 rounded-lg">
|
||||||
|
<h3 class="text-lg font-semibold text-gray-800 mb-4">File yang Diupload</h3>
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
|
@if($sewa->bukti_pembayaran)
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-600 mb-2">Bukti Pembayaran</label>
|
||||||
|
<img src="{{ asset('storage/' . $sewa->bukti_pembayaran) }}"
|
||||||
|
alt="Bukti Pembayaran"
|
||||||
|
class="w-full h-32 object-cover rounded border">
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
@if($sewa->foto_jaminan)
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-600 mb-2">Foto Jaminan</label>
|
||||||
|
<img src="{{ asset('storage/' . $sewa->foto_jaminan) }}"
|
||||||
|
alt="Foto Jaminan"
|
||||||
|
class="w-full h-32 object-cover rounded border">
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
@endsection
|
|
@ -0,0 +1,97 @@
|
||||||
|
@extends('layouts.admin')
|
||||||
|
|
||||||
|
@section('title', 'Pesanan Dibatalkan - INUFA')
|
||||||
|
|
||||||
|
@section('header', 'Pesanan Dibatalkan')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="bg-white rounded-lg shadow-md p-6">
|
||||||
|
<div class="flex justify-between items-center mb-6">
|
||||||
|
<h2 class="text-xl font-semibold text-gray-800">Daftar Pesanan Dibatalkan</h2>
|
||||||
|
<a href="{{ route('admin.dashboard') }}" class="bg-gray-500 hover:bg-gray-600 text-white px-4 py-2 rounded-md text-sm">
|
||||||
|
Kembali ke Dashboard
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if(session('success'))
|
||||||
|
<div class="bg-green-100 border-l-4 border-green-500 text-green-700 p-4 mb-4 rounded">
|
||||||
|
{{ session('success') }}
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if(session('error'))
|
||||||
|
<div class="bg-red-100 border-l-4 border-red-500 text-red-700 p-4 mb-4 rounded">
|
||||||
|
{{ session('error') }}
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if($cancelledOrders->count() > 0)
|
||||||
|
<div class="overflow-x-auto">
|
||||||
|
<table class="min-w-full bg-white">
|
||||||
|
<thead class="bg-gray-50">
|
||||||
|
<tr>
|
||||||
|
<th class="py-3 px-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">ID Pesanan</th>
|
||||||
|
<th class="py-3 px-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Customer</th>
|
||||||
|
<th class="py-3 px-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Paket</th>
|
||||||
|
<th class="py-3 px-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Total Harga</th>
|
||||||
|
<th class="py-3 px-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Tanggal Dibatalkan</th>
|
||||||
|
<th class="py-3 px-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Alasan</th>
|
||||||
|
<th class="py-3 px-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Aksi</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody class="bg-white divide-y divide-gray-200">
|
||||||
|
@foreach($cancelledOrders as $order)
|
||||||
|
<tr class="hover:bg-gray-50">
|
||||||
|
<td class="py-4 px-4 whitespace-nowrap text-sm font-medium text-gray-900">
|
||||||
|
#{{ $order->id }}
|
||||||
|
</td>
|
||||||
|
<td class="py-4 px-4 whitespace-nowrap text-sm text-gray-900">
|
||||||
|
{{ $order->user->name ?? 'N/A' }}
|
||||||
|
<br>
|
||||||
|
<span class="text-xs text-gray-500">{{ $order->user->email ?? 'N/A' }}</span>
|
||||||
|
</td>
|
||||||
|
<td class="py-4 px-4 whitespace-nowrap text-sm text-gray-900">
|
||||||
|
{{ $order->paket->nama ?? 'N/A' }}
|
||||||
|
</td>
|
||||||
|
<td class="py-4 px-4 whitespace-nowrap text-sm text-gray-900">
|
||||||
|
Rp {{ number_format($order->total_harga, 0, ',', '.') }}
|
||||||
|
</td>
|
||||||
|
<td class="py-4 px-4 whitespace-nowrap text-sm text-gray-900">
|
||||||
|
{{ $order->updated_at->format('d/m/Y H:i') }}
|
||||||
|
<br>
|
||||||
|
<span class="text-xs text-gray-500">{{ $order->updated_at->diffForHumans() }}</span>
|
||||||
|
</td>
|
||||||
|
<td class="py-4 px-4 text-sm text-gray-900">
|
||||||
|
@if($order->detail_status)
|
||||||
|
<span class="text-red-600 font-medium">Ada alasan</span>
|
||||||
|
@else
|
||||||
|
<span class="text-gray-500">Tidak ada alasan</span>
|
||||||
|
@endif
|
||||||
|
</td>
|
||||||
|
<td class="py-4 px-4 whitespace-nowrap text-sm font-medium">
|
||||||
|
<a href="{{ route('admin.cancelled-orders.show', $order->id) }}"
|
||||||
|
class="text-blue-600 hover:text-blue-900 bg-blue-100 hover:bg-blue-200 px-3 py-1 rounded-md text-xs">
|
||||||
|
Lihat Detail
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Pagination -->
|
||||||
|
<div class="mt-6">
|
||||||
|
{{ $cancelledOrders->links() }}
|
||||||
|
</div>
|
||||||
|
@else
|
||||||
|
<div class="text-center py-12">
|
||||||
|
<svg class="mx-auto h-12 w-12 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
||||||
|
</svg>
|
||||||
|
<h3 class="mt-2 text-sm font-medium text-gray-900">Tidak ada pesanan yang dibatalkan</h3>
|
||||||
|
<p class="mt-1 text-sm text-gray-500">Belum ada customer yang membatalkan pesanan mereka.</p>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
@endsection
|
|
@ -107,6 +107,36 @@
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
|
<!-- Notifikasi Pesanan Dibatalkan -->
|
||||||
|
@if(isset($recentCancellations) && count($recentCancellations) > 0)
|
||||||
|
<div class="bg-red-50 border-l-4 border-red-400 p-4 mb-6">
|
||||||
|
<div class="flex">
|
||||||
|
<div class="flex-shrink-0">
|
||||||
|
<svg class="h-5 w-5 text-red-400" viewBox="0 0 20 20" fill="currentColor">
|
||||||
|
<path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div class="ml-3">
|
||||||
|
<h3 class="text-sm font-medium text-red-800">
|
||||||
|
Pesanan Dibatalkan Terbaru
|
||||||
|
</h3>
|
||||||
|
<div class="mt-2 text-sm text-red-700">
|
||||||
|
<p>Ada {{ count($recentCancellations) }} pesanan yang baru dibatalkan oleh customer.
|
||||||
|
<a href="{{ route('admin.cancelled-orders') }}" class="font-medium underline hover:text-red-600">Lihat Detail</a></p>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3">
|
||||||
|
@foreach($recentCancellations->take(3) as $cancellation)
|
||||||
|
<div class="text-xs text-red-600 mb-1">
|
||||||
|
• {{ $cancellation->user->name ?? 'User' }} membatalkan pesanan #{{ $cancellation->id }}
|
||||||
|
({{ $cancellation->paket->nama ?? 'Paket' }}) - {{ $cancellation->updated_at->diffForHumans() }}
|
||||||
|
</div>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
<div class="bg-white rounded-lg shadow-md p-6 mb-6 max-w-lg">
|
<div class="bg-white rounded-lg shadow-md p-6 mb-6 max-w-lg">
|
||||||
<h2 class="text-lg font-semibold mb-4">Pengaturan Nomor Rekening</h2>
|
<h2 class="text-lg font-semibold mb-4">Pengaturan Nomor Rekening</h2>
|
||||||
<form action="{{ route('admin.save-rekening') }}" method="POST">
|
<form action="{{ route('admin.save-rekening') }}" method="POST">
|
||||||
|
|
|
@ -14,8 +14,8 @@
|
||||||
<div class="kota-form mb-6 p-4 border rounded-lg bg-gray-50">
|
<div class="kota-form mb-6 p-4 border rounded-lg bg-gray-50">
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-gray-700 font-medium mb-2">Nama Kota <span class="text-red-500">*</span></label>
|
<label class="block text-gray-700 font-medium mb-2">Nama Kabupaten <span class="text-red-500">*</span></label>
|
||||||
<input type="text" name="kotas[0][nama_kota]" class="w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" required>
|
<input type="text" name="kotas[0][nama_Kabupaten]" class="w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" required>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-gray-700 font-medium mb-2">Biaya Ongkir (Rp) <span class="text-red-500">*</span></label>
|
<label class="block text-gray-700 font-medium mb-2">Biaya Ongkir (Rp) <span class="text-red-500">*</span></label>
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
<div class="space-y-6">
|
<div class="space-y-6">
|
||||||
<div>
|
<div>
|
||||||
<label for="nama_kota" class="block text-gray-700 font-medium mb-2">Nama Kota <span class="text-red-500">*</span></label>
|
<label for="nama_kota" class="block text-gray-700 font-medium mb-2">Nama Kabupaten <span class="text-red-500">*</span></label>
|
||||||
<input type="text" id="nama_kota" name="nama_kota" value="{{ old('nama_kota', $kota->nama_kota) }}"
|
<input type="text" id="nama_kota" name="nama_kota" value="{{ old('nama_kota', $kota->nama_kota) }}"
|
||||||
class="w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" required>
|
class="w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" required>
|
||||||
@error('nama_kota')
|
@error('nama_kota')
|
||||||
|
|
|
@ -61,14 +61,14 @@
|
||||||
</td>
|
</td>
|
||||||
<td class="py-3 px-4 text-sm text-gray-800">
|
<td class="py-3 px-4 text-sm text-gray-800">
|
||||||
<span class="px-2 py-1 text-xs font-semibold rounded-full
|
<span class="px-2 py-1 text-xs font-semibold rounded-full
|
||||||
@if($sewa->status === 'completed') bg-green-100 text-green-800
|
@if($sewa->status === 'selesai') bg-green-100 text-green-800
|
||||||
@elseif($sewa->status === 'confirmed') bg-blue-100 text-blue-800
|
@elseif($sewa->status === 'confirmed') bg-blue-100 text-blue-800
|
||||||
@else bg-gray-100 text-gray-800 @endif">
|
@else bg-gray-100 text-gray-800 @endif">
|
||||||
{{ ucfirst($sewa->status) }}
|
{{ ucfirst($sewa->status) }}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="py-3 px-4 text-center text-sm">
|
<td class="py-3 px-4 text-center text-sm">
|
||||||
@if($sewa->status !== 'completed' && $sewa->status !== 'dibatalkan')
|
@if($sewa->status !== 'selesai' && $sewa->status !== 'dibatalkan')
|
||||||
<form action="{{ route('admin.riwayat.update-status', $sewa->id) }}" method="POST" class="inline">
|
<form action="{{ route('admin.riwayat.update-status', $sewa->id) }}" method="POST" class="inline">
|
||||||
@csrf
|
@csrf
|
||||||
@method('PUT')
|
@method('PUT')
|
||||||
|
|
|
@ -33,17 +33,25 @@
|
||||||
</td>
|
</td>
|
||||||
<td>Rp {{ number_format($sewa->total_harga, 0, ',', '.') }}</td>
|
<td>Rp {{ number_format($sewa->total_harga, 0, ',', '.') }}</td>
|
||||||
<td>
|
<td>
|
||||||
<!-- Tombol tandai completed (hanya admin & status confirmed) -->
|
<!-- Tombol tandai selesai (hanya admin & status confirmed) -->
|
||||||
@if(Auth::user()->tipe_pengguna === 'admin' && $sewa->status === 'confirmed')
|
@if(Auth::user()->tipe_pengguna === 'admin' && $sewa->status === 'confirmed')
|
||||||
<form action="{{ route('riwayat.updateStatus', $sewa->id) }}" method="POST" style="display:inline;">
|
<form action="{{ route('riwayat.updateStatus', $sewa->id) }}" method="POST" style="display:inline;">
|
||||||
@csrf
|
@csrf
|
||||||
<input type="hidden" name="status" value="completed">
|
<input type="hidden" name="status" value="selesai">
|
||||||
<button type="submit" class="btn btn-success btn-sm" onclick="return confirm('Tandai sebagai LUNAS / completed?')">Tandai Lunas</button>
|
<button type="submit" class="btn btn-success btn-sm" onclick="return confirm('Tandai sebagai SELESAI? Ini akan mengaktifkan kembali stok paket.')">Tandai Selesai</button>
|
||||||
|
</form>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<!-- Tombol aktifkan stok (hanya admin & status ongoing) -->
|
||||||
|
@if(Auth::user()->tipe_pengguna === 'admin' && $sewa->status === 'ongoing')
|
||||||
|
<form action="{{ route('admin.riwayat.activate-stock', $sewa->id) }}" method="POST" style="display:inline;">
|
||||||
|
@csrf
|
||||||
|
<button type="submit" class="btn btn-warning btn-sm" onclick="return confirm('Aktifkan kembali stok paket? Status sewa akan diubah menjadi selesai.')">Aktifkan Stok</button>
|
||||||
</form>
|
</form>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<!-- Tombol hapus (jika status sudah selesai atau dibatalkan) -->
|
<!-- Tombol hapus (jika status sudah selesai atau dibatalkan) -->
|
||||||
@if($sewa->user_id == Auth::id() && in_array($sewa->status, ['completed', 'dibatalkan']))
|
@if($sewa->user_id == Auth::id() && in_array($sewa->status, ['selesai', 'dibatalkan']))
|
||||||
<form action="{{ url('/riwayat/hapus/'.$sewa->id) }}" method="POST" style="display:inline;">
|
<form action="{{ url('/riwayat/hapus/'.$sewa->id) }}" method="POST" style="display:inline;">
|
||||||
@csrf
|
@csrf
|
||||||
@method('DELETE')
|
@method('DELETE')
|
||||||
|
|
|
@ -131,10 +131,11 @@ class="bg-green-500 text-white px-3 py-1 rounded hover:bg-green-600">
|
||||||
Setujui
|
Setujui
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
<form action="{{ route('admin.verifikasi.reject', $sewa->id) }}" method="POST" class="inline">
|
<form action="{{ route('admin.verifikasi.reject', $sewa->id) }}" method="POST" class="inline reject-form">
|
||||||
@csrf
|
@csrf
|
||||||
<button type="submit"
|
<button type="button"
|
||||||
class="bg-red-500 text-white px-3 py-1 rounded hover:bg-red-600">
|
class="bg-red-500 text-white px-3 py-1 rounded hover:bg-red-600 open-reject-modal"
|
||||||
|
data-sewa-id="{{ $sewa->id }}">
|
||||||
Tolak
|
Tolak
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
@ -162,4 +163,119 @@ class="inline-flex items-center justify-center w-full px-3 py-1 bg-blue-500 text
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Modal Penolakan -->
|
||||||
|
<div id="rejectModal" class="fixed inset-0 flex items-center justify-center z-50 hidden bg-black bg-opacity-40">
|
||||||
|
<div class="bg-white rounded-lg shadow-lg p-6 w-full max-w-md">
|
||||||
|
<h3 class="text-lg font-bold mb-4">Pilih Alasan Penolakan</h3>
|
||||||
|
<form id="rejectReasonForm" method="POST">
|
||||||
|
@csrf
|
||||||
|
<input type="hidden" name="sewa_id" id="modalSewaId">
|
||||||
|
<div class="mb-4">
|
||||||
|
<select name="alasan_penolakan" id="alasan_penolakan" class="w-full border rounded px-3 py-2">
|
||||||
|
<option value="">-- Pilih Alasan --</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="mb-4" id="alasanLainnyaDiv" style="display:none;">
|
||||||
|
<input type="text"
|
||||||
|
name="alasan_lainnya"
|
||||||
|
id="alasan_lainnya"
|
||||||
|
class="w-full border rounded px-3 py-2"
|
||||||
|
placeholder="Tulis alasan lain..."
|
||||||
|
maxlength="255">
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-end space-x-2">
|
||||||
|
<button type="button" id="closeRejectModal" class="px-4 py-2 bg-gray-300 rounded hover:bg-gray-400">Batal</button>
|
||||||
|
<button type="submit" class="px-4 py-2 bg-red-500 text-white rounded hover:bg-red-600">Tolak</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Opsi alasan penolakan fallback jika API tidak tersedia
|
||||||
|
const FALLBACK_ALASAN = [
|
||||||
|
'Bukti pembayaran tidak valid',
|
||||||
|
'Jaminan tidak sesuai',
|
||||||
|
'Data tidak lengkap',
|
||||||
|
'Lainnya'
|
||||||
|
];
|
||||||
|
|
||||||
|
// Load alasan penolakan dari server
|
||||||
|
async function loadAlasanPenolakan() {
|
||||||
|
try {
|
||||||
|
const response = await fetch('/admin/verifikasi/alasan-penolakan');
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('API tidak tersedia');
|
||||||
|
}
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
const select = document.getElementById('alasan_penolakan');
|
||||||
|
select.innerHTML = '<option value="">-- Pilih Alasan --</option>';
|
||||||
|
|
||||||
|
data.alasan_penolakan.forEach(alasan => {
|
||||||
|
const option = document.createElement('option');
|
||||||
|
option.value = alasan;
|
||||||
|
option.textContent = alasan;
|
||||||
|
select.appendChild(option);
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading alasan penolakan:', error);
|
||||||
|
// Gunakan fallback jika API tidak tersedia
|
||||||
|
const select = document.getElementById('alasan_penolakan');
|
||||||
|
select.innerHTML = '<option value="">-- Pilih Alasan --</option>';
|
||||||
|
|
||||||
|
FALLBACK_ALASAN.forEach(alasan => {
|
||||||
|
const option = document.createElement('option');
|
||||||
|
option.value = alasan;
|
||||||
|
option.textContent = alasan;
|
||||||
|
select.appendChild(option);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load alasan penolakan saat halaman dimuat
|
||||||
|
document.addEventListener('DOMContentLoaded', loadAlasanPenolakan);
|
||||||
|
|
||||||
|
document.querySelectorAll('.open-reject-modal').forEach(btn => {
|
||||||
|
btn.addEventListener('click', function() {
|
||||||
|
document.getElementById('rejectModal').classList.remove('hidden');
|
||||||
|
document.getElementById('modalSewaId').value = this.getAttribute('data-sewa-id');
|
||||||
|
// Set form action
|
||||||
|
const sewaId = this.getAttribute('data-sewa-id');
|
||||||
|
document.getElementById('rejectReasonForm').action = `/admin/verifikasi/${sewaId}/reject`;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('closeRejectModal').onclick = function() {
|
||||||
|
document.getElementById('rejectModal').classList.add('hidden');
|
||||||
|
};
|
||||||
|
|
||||||
|
document.getElementById('alasan_penolakan').onchange = function() {
|
||||||
|
if (this.value === 'Lainnya') {
|
||||||
|
document.getElementById('alasanLainnyaDiv').style.display = 'block';
|
||||||
|
} else {
|
||||||
|
document.getElementById('alasanLainnyaDiv').style.display = 'none';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
document.getElementById('rejectReasonForm').onsubmit = function(e) {
|
||||||
|
const alasan = document.getElementById('alasan_penolakan').value;
|
||||||
|
const alasanLainnya = document.getElementById('alasan_lainnya').value;
|
||||||
|
|
||||||
|
if (!alasan) {
|
||||||
|
alert('Silakan pilih alasan penolakan!');
|
||||||
|
e.preventDefault();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alasan === 'Lainnya' && !alasanLainnya.trim()) {
|
||||||
|
alert('Silakan isi alasan lainnya!');
|
||||||
|
e.preventDefault();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
@endsection
|
@endsection
|
|
@ -90,56 +90,36 @@
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Pendapatan Stats -->
|
|
||||||
<!-- <div class="bg-gradient-to-br from-green-50 to-green-100 rounded-xl shadow-lg p-6 transform hover:scale-105 transition-all duration-300">
|
|
||||||
<div class="flex items-center">
|
|
||||||
<div class="p-3 rounded-full bg-green-500 text-white mr-4 shadow-md">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p class="text-green-600 text-sm font-medium">Pendapatan</p>
|
|
||||||
<p class="text-3xl font-bold text-green-800">
|
|
||||||
{{ isset($chartData['datasets'][0]['data']) ? 'Rp ' . number_format(end($chartData['datasets'][0]['data']), 0, ',', '.') : 'Rp 0' }}
|
|
||||||
</p>
|
|
||||||
<p class="text-sm text-green-600 mt-1">Tahun {{ date('Y') }}</p>
|
|
||||||
</div>
|
|
||||||
</div> -->
|
|
||||||
<!-- </div> -->
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@if(auth()->user()->tipe_pengguna == 'admin')
|
<!-- Grafik Statistik -->
|
||||||
<!-- Grafik Statistik -->
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-8">
|
||||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-8">
|
<!-- Grafik Pemasukan & Pengeluaran -->
|
||||||
<!-- Grafik Pemasukan & Pengeluaran -->
|
<div class="bg-white rounded-xl shadow-lg p-6 hover:shadow-xl transition-shadow duration-300">
|
||||||
<div class="bg-white rounded-xl shadow-lg p-6 hover:shadow-xl transition-shadow duration-300">
|
<div class="flex items-center justify-between mb-6">
|
||||||
<div class="flex items-center justify-between mb-6">
|
<h3 class="text-xl font-bold text-gray-800">Statistik Keuangan & Sewa</h3>
|
||||||
<h3 class="text-xl font-bold text-gray-800">Statistik Keuangan & Sewa</h3>
|
<div class="flex space-x-2">
|
||||||
<div class="flex space-x-2">
|
<span class="px-3 py-1 bg-green-100 text-green-600 rounded-full text-sm font-medium">Pemasukan</span>
|
||||||
<span class="px-3 py-1 bg-green-100 text-green-600 rounded-full text-sm font-medium">Pemasukan</span>
|
<span class="px-3 py-1 bg-red-100 text-red-600 rounded-full text-sm font-medium">Pengeluaran</span>
|
||||||
<span class="px-3 py-1 bg-red-100 text-red-600 rounded-full text-sm font-medium">Pengeluaran</span>
|
<span class="px-3 py-1 bg-blue-100 text-blue-600 rounded-full text-sm font-medium">Total Sewa</span>
|
||||||
<span class="px-3 py-1 bg-blue-100 text-blue-600 rounded-full text-sm font-medium">Total Sewa</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="relative h-80">
|
|
||||||
<canvas id="financeChart"></canvas>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="relative h-80">
|
||||||
<!-- Grafik Pertumbuhan Pengguna -->
|
<canvas id="financeChart"></canvas>
|
||||||
<div class="bg-white rounded-xl shadow-lg p-6 hover:shadow-xl transition-shadow duration-300">
|
|
||||||
<div class="flex items-center justify-between mb-6">
|
|
||||||
<h3 class="text-xl font-bold text-gray-800">Pertumbuhan Pengguna</h3>
|
|
||||||
<span class="px-3 py-1 bg-purple-100 text-purple-600 rounded-full text-sm font-medium">Total Pengguna</span>
|
|
||||||
</div>
|
|
||||||
<div class="relative h-80">
|
|
||||||
<canvas id="userGrowthChart"></canvas>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Grafik Pertumbuhan Pengguna -->
|
||||||
|
<div class="bg-white rounded-xl shadow-lg p-6 hover:shadow-xl transition-shadow duration-300">
|
||||||
|
<div class="flex items-center justify-between mb-6">
|
||||||
|
<h3 class="text-xl font-bold text-gray-800">Pertumbuhan Pengguna</h3>
|
||||||
|
<span class="px-3 py-1 bg-purple-100 text-purple-600 rounded-full text-sm font-medium">Total Pengguna</span>
|
||||||
|
</div>
|
||||||
|
<div class="relative h-80">
|
||||||
|
<canvas id="userGrowthChart"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Ringkasan Statistik -->
|
<!-- Ringkasan Statistik -->
|
||||||
<div class="bg-white rounded-xl shadow-lg p-6 hover:shadow-xl transition-shadow duration-300">
|
<div class="bg-white rounded-xl shadow-lg p-6 hover:shadow-xl transition-shadow duration-300">
|
||||||
|
@ -165,7 +145,6 @@
|
||||||
Rp {{ isset($chartData['datasets'][0]['data']) ? number_format(end($chartData['datasets'][0]['data']), 0, ',', '.') : '0' }}
|
Rp {{ isset($chartData['datasets'][0]['data']) ? number_format(end($chartData['datasets'][0]['data']), 0, ',', '.') : '0' }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
|
||||||
|
|
||||||
<!-- Total Sewa -->
|
<!-- Total Sewa -->
|
||||||
<div class="p-6 bg-gradient-to-br from-blue-50 to-blue-100 rounded-xl border border-blue-200">
|
<div class="p-6 bg-gradient-to-br from-blue-50 to-blue-100 rounded-xl border border-blue-200">
|
||||||
|
|
|
@ -19,28 +19,84 @@
|
||||||
<!-- Admin Menu -->
|
<!-- Admin Menu -->
|
||||||
<nav class="mt-4">
|
<nav class="mt-4">
|
||||||
<a href="{{ route('admin.dashboard') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('admin.dashboard') ? 'bg-blue-800 text-white' : '' }}">
|
<a href="{{ route('admin.dashboard') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('admin.dashboard') ? 'bg-blue-800 text-white' : '' }}">
|
||||||
Dashboard
|
<div class="flex items-center">
|
||||||
|
<svg class="w-5 h-5 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2H5a2 2 0 00-2-2z" />
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 5a2 2 0 012-2h4a2 2 0 012 2v2H8V5z" />
|
||||||
|
</svg>
|
||||||
|
Dashboard
|
||||||
|
</div>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('pengguna') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('pengguna*') ? 'bg-blue-800 text-white' : '' }}">
|
<a href="{{ route('pengguna') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('pengguna*') ? 'bg-blue-800 text-white' : '' }}">
|
||||||
Manajemen User
|
<div class="flex items-center">
|
||||||
|
<svg class="w-5 h-5 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z" />
|
||||||
|
</svg>
|
||||||
|
Manajemen User
|
||||||
|
</div>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('paket.index') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('paket*') ? 'bg-blue-800 text-white' : '' }}">
|
<a href="{{ route('paket.index') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('paket*') ? 'bg-blue-800 text-white' : '' }}">
|
||||||
Manajemen Paket
|
<div class="flex items-center">
|
||||||
|
<svg class="w-5 h-5 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 8h14M5 8a2 2 0 110-4h14a2 2 0 110 4M5 8v10a2 2 0 002 2h10a2 2 0 002-2V8m-9 4h4" />
|
||||||
|
</svg>
|
||||||
|
Manajemen Paket
|
||||||
|
</div>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('input-stock') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('input-stock*') ? 'bg-blue-800 text-white' : '' }}">
|
<a href="{{ route('input-stock') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('input-stock*') ? 'bg-blue-800 text-white' : '' }}">
|
||||||
Manajemen Stock
|
<div class="flex items-center">
|
||||||
|
<svg class="w-5 h-5 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4" />
|
||||||
|
</svg>
|
||||||
|
Manajemen Stock
|
||||||
|
</div>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('sewa.index') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('sewa.*') ? 'bg-blue-800 text-white' : '' }}">
|
<a href="{{ route('sewa.index') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('sewa.*') ? 'bg-blue-800 text-white' : '' }}">
|
||||||
Manajemen Sewa
|
<div class="flex items-center">
|
||||||
|
<svg class="w-5 h-5 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
|
||||||
|
</svg>
|
||||||
|
Manajemen Sewa
|
||||||
|
</div>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('riwayat') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('riwayat') ? 'bg-blue-800 text-white' : '' }}">
|
<a href="{{ route('riwayat') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('riwayat') ? 'bg-blue-800 text-white' : '' }}">
|
||||||
Laporan
|
<div class="flex items-center">
|
||||||
|
<svg class="w-5 h-5 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
||||||
|
</svg>
|
||||||
|
Laporan
|
||||||
|
</div>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('admin.verifikasi.index') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('admin.verifikasi.*') ? 'bg-blue-800 text-white' : '' }}">
|
<a href="{{ route('admin.verifikasi.index') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('admin.verifikasi.*') ? 'bg-blue-800 text-white' : '' }}">
|
||||||
Verifikasi Pembayaran
|
<div class="flex items-center">
|
||||||
|
<svg class="w-5 h-5 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
|
</svg>
|
||||||
|
Verifikasi Pembayaran
|
||||||
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
<!-- Menu Pesanan Dibatalkan dengan styling khusus -->
|
||||||
|
<div class="border-t border-gray-200 my-2"></div>
|
||||||
|
<a href="{{ route('admin.cancelled-orders') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-red-50 hover:text-red-700 {{ request()->routeIs('admin.cancelled-orders*') ? 'bg-red-100 text-red-700 border-r-4 border-red-500' : '' }}">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<svg class="w-5 h-5 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||||
|
</svg>
|
||||||
|
<span>Pesanan Dibatalkan</span>
|
||||||
|
</div>
|
||||||
|
<span id="cancelled-orders-badge" class="hidden bg-red-500 text-white text-xs rounded-full px-2 py-1 font-bold">0</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
<a href="{{ route('contact.index') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('contact.*') ? 'bg-blue-800 text-white' : '' }}">
|
<a href="{{ route('contact.index') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('contact.*') ? 'bg-blue-800 text-white' : '' }}">
|
||||||
Kelola Kontak
|
<div class="flex items-center">
|
||||||
|
<svg class="w-5 h-5 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 4.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
|
||||||
|
</svg>
|
||||||
|
Kelola Kontak
|
||||||
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
@ -53,6 +109,15 @@
|
||||||
<h1 class="text-xl font-bold text-gray-800">@yield('header', 'Admin Dashboard')</h1>
|
<h1 class="text-xl font-bold text-gray-800">@yield('header', 'Admin Dashboard')</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center space-x-4">
|
<div class="flex items-center space-x-4">
|
||||||
|
<!-- Notifikasi Pembatalan di Header -->
|
||||||
|
<a href="{{ route('admin.cancelled-orders') }}" class="relative flex items-center space-x-2 px-3 py-2 bg-red-50 hover:bg-red-100 rounded-lg transition-colors">
|
||||||
|
<svg class="w-5 h-5 text-red-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||||
|
</svg>
|
||||||
|
<span class="text-red-700 font-medium">Pesanan Dibatalkan</span>
|
||||||
|
<span id="header-cancelled-badge" class="hidden absolute -top-1 -right-1 bg-red-500 text-white text-xs rounded-full px-2 py-1 font-bold">0</span>
|
||||||
|
</a>
|
||||||
|
|
||||||
<a href="{{ route('profile.index') }}" class="font-semibold text-gray-600 flex items-center space-x-2">
|
<a href="{{ route('profile.index') }}" class="font-semibold text-gray-600 flex items-center space-x-2">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||||
<path fill-rule="evenodd" d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z" clip-rule="evenodd" />
|
<path fill-rule="evenodd" d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z" clip-rule="evenodd" />
|
||||||
|
@ -97,5 +162,96 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@stack('scripts')
|
@stack('scripts')
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Notifikasi real-time untuk pesanan yang dibatalkan
|
||||||
|
function updateCancelledOrdersBadge() {
|
||||||
|
fetch('{{ route("admin.cancelled-orders.count") }}')
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
const badge = document.getElementById('cancelled-orders-badge');
|
||||||
|
if (data.count > 0) {
|
||||||
|
badge.textContent = data.count;
|
||||||
|
badge.classList.remove('hidden');
|
||||||
|
} else {
|
||||||
|
badge.classList.add('hidden');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error fetching cancelled orders count:', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update badge setiap 30 detik
|
||||||
|
setInterval(updateCancelledOrdersBadge, 30000);
|
||||||
|
|
||||||
|
// Update badge saat halaman dimuat
|
||||||
|
document.addEventListener('DOMContentLoaded', updateCancelledOrdersBadge);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Notifikasi toast untuk pembatalan pesanan
|
||||||
|
let lastCancellationCount = 0;
|
||||||
|
|
||||||
|
function checkNewCancellations() {
|
||||||
|
fetch('{{ route("admin.recent-cancellations") }}')
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.cancellations && data.cancellations.length > 0) {
|
||||||
|
const latestCancellation = data.cancellations[0];
|
||||||
|
|
||||||
|
// Tampilkan toast notifikasi
|
||||||
|
showToast(
|
||||||
|
'Pesanan Dibatalkan',
|
||||||
|
`${latestCancellation.user_name} membatalkan pesanan #${latestCancellation.id} (${latestCancellation.paket_name})`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error checking cancellations:', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function showToast(title, message) {
|
||||||
|
document.getElementById('toast-title').textContent = title;
|
||||||
|
document.getElementById('toast-message').textContent = message;
|
||||||
|
document.getElementById('toast').classList.remove('hidden');
|
||||||
|
|
||||||
|
// Auto hide setelah 5 detik
|
||||||
|
setTimeout(hideToast, 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideToast() {
|
||||||
|
document.getElementById('toast').classList.add('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check pembatalan baru setiap 60 detik
|
||||||
|
setInterval(checkNewCancellations, 60000);
|
||||||
|
|
||||||
|
// Check saat halaman dimuat
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
setTimeout(checkNewCancellations, 5000); // Check setelah 5 detik
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Toast Notification -->
|
||||||
|
<div id="toast" class="fixed top-4 right-4 z-50 hidden">
|
||||||
|
<div class="bg-red-500 text-white px-6 py-4 rounded-lg shadow-lg max-w-sm">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<svg class="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 20 20">
|
||||||
|
<path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd" />
|
||||||
|
</svg>
|
||||||
|
<div>
|
||||||
|
<h4 class="font-semibold" id="toast-title">Pesanan Dibatalkan</h4>
|
||||||
|
<p class="text-sm" id="toast-message">Ada pesanan baru yang dibatalkan oleh customer.</p>
|
||||||
|
</div>
|
||||||
|
<button onclick="hideToast()" class="ml-4 text-white hover:text-gray-200">
|
||||||
|
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20">
|
||||||
|
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
|
@ -7,27 +7,41 @@
|
||||||
|
|
||||||
<!-- Sidebar Menu -->
|
<!-- Sidebar Menu -->
|
||||||
<nav class="mt-4">
|
<nav class="mt-4">
|
||||||
<a href="{{ route('dashboard') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('dashboard') ? 'bg-blue-800 text-white' : '' }}">
|
<!-- <a href="{{ route('dashboard') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('dashboard') ? 'bg-blue-800 text-white' : '' }}">
|
||||||
|
Dashboard
|
||||||
|
</a> -->
|
||||||
|
@if(auth()->check() && auth()->user()->tipe_pengguna === 'admin')
|
||||||
|
<a href="{{ route('dashboard') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('dashboard') ? 'bg-blue-800 text-white' : '' }}">
|
||||||
Dashboard
|
Dashboard
|
||||||
</a>
|
</a>
|
||||||
@if(auth()->user()->tipe_pengguna === 'admin')
|
|
||||||
|
|
||||||
<a href="{{ route('pengguna') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('pengguna*') ? 'bg-blue-800 text-white' : '' }}">
|
<a href="{{ route('pengguna') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('pengguna*') ? 'bg-blue-800 text-white' : '' }}">
|
||||||
pengguna
|
pengguna
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('input-stock') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('input-stock*') ? 'bg-blue-800 text-white' : '' }}">
|
<a href="{{ route('input-stock') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('input-stock*') ? 'bg-blue-800 text-white' : '' }}">
|
||||||
Input Stock
|
Input Stock
|
||||||
</a>
|
</a>
|
||||||
@endif
|
<a href="{{ route('paket.index') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('paket*') ? 'bg-blue-800 text-white' : '' }}">
|
||||||
<a href="{{ route('paket.index') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('paket*') ? 'bg-blue-800 text-white' : '' }}">
|
|
||||||
Paket
|
Paket
|
||||||
</a>
|
</a>
|
||||||
@if(auth()->user()->tipe_pengguna === 'user')
|
<!-- Tambahkan menu Pesanan Dibatalkan -->
|
||||||
|
<!-- <a href="{{ route('admin.cancelled-orders') }}" class="block py-3 px-4 text-red-700 font-semibold mb-1 hover:bg-red-50 hover:text-red-700 {{ request()->routeIs('admin.cancelled-orders*') ? 'bg-red-100 text-red-700 border-r-4 border-red-500' : '' }}">
|
||||||
|
<span class="flex items-center">
|
||||||
|
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||||
|
</svg>
|
||||||
|
Pesanan Dibatalkan
|
||||||
|
</span>
|
||||||
|
</a> -->
|
||||||
|
@endif
|
||||||
|
<!-- <a href="{{ route('paket.index') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('paket*') ? 'bg-blue-800 text-white' : '' }}">
|
||||||
|
Paket
|
||||||
|
</a> -->
|
||||||
|
@if(auth()->check() && auth()->user()->tipe_pengguna === 'user')
|
||||||
<a href="{{ route('sewa.index') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('sewa.*') ? 'bg-blue-800 text-white' : '' }}">
|
<a href="{{ route('sewa.index') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('sewa.*') ? 'bg-blue-800 text-white' : '' }}">
|
||||||
Sewa
|
Sewa
|
||||||
</a>
|
</a>
|
||||||
@endif
|
@endif
|
||||||
@if(auth()->user()->tipe_pengguna === 'admin')
|
@if(auth()->check() && auth()->user()->tipe_pengguna === 'admin')
|
||||||
<a href="/admin/verifikasi" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->is('admin/verifikasi*') ? 'bg-blue-800 text-white' : '' }}">
|
<a href="/admin/verifikasi" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->is('admin/verifikasi*') ? 'bg-blue-800 text-white' : '' }}">
|
||||||
Verifikasi
|
Verifikasi
|
||||||
</a>
|
</a>
|
||||||
|
@ -35,16 +49,16 @@
|
||||||
Laporan Transaksi
|
Laporan Transaksi
|
||||||
</a>
|
</a>
|
||||||
@endif
|
@endif
|
||||||
@if(auth()->user()->tipe_pengguna === 'user')
|
@if(auth()->check() && auth()->user()->tipe_pengguna === 'user')
|
||||||
<a href="{{ route('riwayat') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('riwayat') ? 'bg-blue-800 text-white' : '' }}">
|
<a href="{{ route('riwayat') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('riwayat') ? 'bg-blue-800 text-white' : '' }}">
|
||||||
Riwayat
|
Riwayat
|
||||||
</a>
|
</a>
|
||||||
@endif
|
@endif
|
||||||
@if(auth()->user()->tipe_pengguna === 'admin')
|
@if(auth()->check() && auth()->user()->tipe_pengguna === 'admin')
|
||||||
<a href="{{ route('contact.index') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('contact.index') ? 'bg-blue-800 text-white' : '' }}">
|
<a href="{{ route('contact.index') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('contact.index') ? 'bg-blue-800 text-white' : '' }}">
|
||||||
Hubungi Kami
|
Hubungi Kami
|
||||||
</a>
|
</a>
|
||||||
@else
|
@elseif(auth()->check())
|
||||||
<a href="{{ route('contact.show') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('contact.*') ? 'bg-blue-800 text-white' : '' }}">
|
<a href="{{ route('contact.show') }}" class="block py-3 px-4 text-gray-800 font-semibold mb-1 hover:bg-gray-100 {{ request()->routeIs('contact.*') ? 'bg-blue-800 text-white' : '' }}">
|
||||||
Hubungi Kami
|
Hubungi Kami
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -36,16 +36,12 @@ class="w-full h-full object-cover">
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@php
|
@if($paket->stok_tersedia <= 0)
|
||||||
$activeSewa = $paket->sewas()->whereIn('status', ['confirmed', 'ongoing'])->count();
|
|
||||||
@endphp
|
|
||||||
|
|
||||||
@if($activeSewa > 0)
|
|
||||||
<div class="absolute inset-0 bg-black bg-opacity-50 flex items-center justify-center">
|
<div class="absolute inset-0 bg-black bg-opacity-50 flex items-center justify-center">
|
||||||
<div class="text-white text-center p-4">
|
<div class="text-white text-center p-4">
|
||||||
<i class="fas fa-clock text-3xl mb-2"></i>
|
<i class="fas fa-clock text-3xl mb-2"></i>
|
||||||
<p class="font-bold">Sedang Disewa</p>
|
<p class="font-bold">Sedang Disewa</p>
|
||||||
<p class="text-sm">{{ $activeSewa }} dari {{ $paket->stok }} unit disewa</p>
|
<p class="text-sm">{{ $paket->active_sewa_count }} dari {{ $paket->stok }} unit disewa</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
@ -70,28 +66,20 @@ class="w-full h-full object-cover">
|
||||||
<span class="text-gray-600">Stok:</span>
|
<span class="text-gray-600">Stok:</span>
|
||||||
<span class="font-semibold">
|
<span class="font-semibold">
|
||||||
{{ $paket->stok }}
|
{{ $paket->stok }}
|
||||||
@if($activeSewa > 0)
|
@if($paket->active_sewa_count > 0)
|
||||||
<span class="text-orange-500 text-sm ml-1">({{ $paket->stok - $activeSewa }} tersedia)</span>
|
<span class="text-orange-500 text-sm ml-1">({{ $paket->stok_tersedia }} tersedia)</span>
|
||||||
@endif
|
@endif
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-between">
|
<div class="flex justify-between">
|
||||||
<span class="text-gray-600">Status:</span>
|
<span class="text-gray-600">Status:</span>
|
||||||
<span class="font-semibold
|
<span class="font-semibold
|
||||||
@if($paket->status == 'aktif' && ($paket->stok - $activeSewa) > 0)
|
@if($paket->is_available)
|
||||||
text-green-600
|
text-green-600
|
||||||
@else
|
@else
|
||||||
text-red-600
|
text-red-600
|
||||||
@endif">
|
@endif">
|
||||||
@if($paket->status == 'aktif')
|
{{ $paket->status_ketersediaan }}
|
||||||
@if(($paket->stok - $activeSewa) > 0)
|
|
||||||
Aktif ({{ $paket->stok - $activeSewa }} unit tersedia)
|
|
||||||
@else
|
|
||||||
Sedang Disewa Semua
|
|
||||||
@endif
|
|
||||||
@else
|
|
||||||
{{ ucfirst($paket->status) }}
|
|
||||||
@endif
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -118,7 +106,7 @@ class="w-full h-full object-cover">
|
||||||
<!-- Action Buttons - Only for Admin -->
|
<!-- Action Buttons - Only for Admin -->
|
||||||
@if(auth()->user()->tipe_pengguna === 'admin')
|
@if(auth()->user()->tipe_pengguna === 'admin')
|
||||||
<div class="flex flex-col space-y-2 mt-4">
|
<div class="flex flex-col space-y-2 mt-4">
|
||||||
@if($activeSewa > 0)
|
@if($paket->active_sewa_count > 0)
|
||||||
<div class="flex space-x-2">
|
<div class="flex space-x-2">
|
||||||
<form action="{{ route('paket.activate', $paket->id) }}" method="POST" class="flex-1">
|
<form action="{{ route('paket.activate', $paket->id) }}" method="POST" class="flex-1">
|
||||||
@csrf
|
@csrf
|
||||||
|
|
|
@ -42,9 +42,6 @@
|
||||||
<th class="py-3 px-4 text-left w-48 border-r">Email</th>
|
<th class="py-3 px-4 text-left w-48 border-r">Email</th>
|
||||||
<th class="py-3 px-4 text-left w-36 border-r">No.Telp</th>
|
<th class="py-3 px-4 text-left w-36 border-r">No.Telp</th>
|
||||||
<th class="py-3 px-4 text-left border-r">Alamat</th>
|
<th class="py-3 px-4 text-left border-r">Alamat</th>
|
||||||
@if(auth()->user()->tipe_pengguna === 'admin')
|
|
||||||
<th class="py-3 px-4 text-center w-24">Aksi</th>
|
|
||||||
@endif
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
@ -56,21 +53,10 @@
|
||||||
<td class="py-3 px-4 border-r">{{ $user->email }}</td>
|
<td class="py-3 px-4 border-r">{{ $user->email }}</td>
|
||||||
<td class="py-3 px-4 border-r">{{ $user->no_telp }}</td>
|
<td class="py-3 px-4 border-r">{{ $user->no_telp }}</td>
|
||||||
<td class="py-3 px-4 border-r">{{ $user->alamat }}</td>
|
<td class="py-3 px-4 border-r">{{ $user->alamat }}</td>
|
||||||
@if(auth()->user()->tipe_pengguna === 'admin')
|
|
||||||
<td class="py-3 px-4 text-center">
|
|
||||||
<form action="{{ route('pengguna.destroy', $user->id) }}" method="POST">
|
|
||||||
@csrf
|
|
||||||
@method('DELETE')
|
|
||||||
<button type="submit" class="bg-red-500 text-white px-4 py-1 rounded-sm font-medium text-sm">
|
|
||||||
Hapus
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</td>
|
|
||||||
@endif
|
|
||||||
</tr>
|
</tr>
|
||||||
@empty
|
@empty
|
||||||
<tr class="border-t">
|
<tr class="border-t">
|
||||||
<td colspan="{{ auth()->user()->tipe_pengguna === 'admin' ? 7 : 6 }}" class="py-3 px-4 text-center">Tidak ada data admin</td>
|
<td colspan="6" class="py-3 px-4 text-center">Tidak ada data admin</td>
|
||||||
</tr>
|
</tr>
|
||||||
@endforelse
|
@endforelse
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
|
@ -51,11 +51,21 @@
|
||||||
<span class="px-2 py-1 rounded-full text-xs font-semibold
|
<span class="px-2 py-1 rounded-full text-xs font-semibold
|
||||||
@if($sewa->status == 'pending') bg-yellow-100 text-yellow-800
|
@if($sewa->status == 'pending') bg-yellow-100 text-yellow-800
|
||||||
@elseif($sewa->status == 'confirmed') bg-blue-100 text-blue-800
|
@elseif($sewa->status == 'confirmed') bg-blue-100 text-blue-800
|
||||||
@elseif($sewa->status == 'completed') bg-green-100 text-green-800
|
@elseif($sewa->status == 'selesai') bg-green-100 text-green-800
|
||||||
@elseif($sewa->status == 'dibatalkan') bg-red-100 text-red-800
|
@elseif($sewa->status == 'dibatalkan') bg-red-100 text-red-800
|
||||||
|
@elseif($sewa->status == 'ditolak') bg-red-100 text-red-800
|
||||||
@endif">
|
@endif">
|
||||||
{{ ucfirst($sewa->status) }}
|
{{ ucfirst($sewa->status) }}
|
||||||
</span>
|
</span>
|
||||||
|
@if($sewa->status == 'ditolak' && $sewa->detail_status)
|
||||||
|
<div class="mt-1">
|
||||||
|
<button type="button"
|
||||||
|
onclick="showAlasanPenolakan('{{ $sewa->detail_status }}')"
|
||||||
|
class="text-xs text-blue-600 underline">
|
||||||
|
Lihat Alasan Penolakan
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
</td>
|
</td>
|
||||||
<td class="py-3 px-4">
|
<td class="py-3 px-4">
|
||||||
<div class="space-y-2">
|
<div class="space-y-2">
|
||||||
|
@ -66,20 +76,15 @@ class="w-full bg-blue-600 text-white px-3 py-1 rounded hover:bg-blue-700">
|
||||||
Detail
|
Detail
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
@if(!in_array($sewa->status, ['completed', 'dibatalkan', 'ongoing']))
|
@if(!in_array($sewa->status, ['selesai', 'dibatalkan', 'ongoing']))
|
||||||
<form action="{{ route('riwayat.batal', $sewa->id) }}" method="POST">
|
<button type="button"
|
||||||
@csrf
|
onclick="showCancelForm('{{ $sewa->id }}', '{{ $sewa->paket->nama_paket }}', '{{ $sewa->status }}')"
|
||||||
@method('PUT')
|
|
||||||
<button type="submit"
|
|
||||||
onclick="return confirm('Apakah Anda yakin ingin membatalkan pesanan ini?' +
|
|
||||||
(('{{ $sewa->status }}' === 'confirmed') ? ' Pembatalan setelah disetujui mungkin dikenakan biaya pembatalan.' : ''))"
|
|
||||||
class="w-full bg-red-500 text-white px-3 py-1 rounded hover:bg-red-600">
|
class="w-full bg-red-500 text-white px-3 py-1 rounded hover:bg-red-600">
|
||||||
Batalkan Pesanan
|
Batalkan Pesanan
|
||||||
</button>
|
</button>
|
||||||
</form>
|
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@if(in_array($sewa->status, ['dibatalkan', 'completed']))
|
@if(in_array($sewa->status, ['dibatalkan', 'selesai']))
|
||||||
<form action="{{ route('riwayat.hapus', $sewa->id) }}" method="POST">
|
<form action="{{ route('riwayat.hapus', $sewa->id) }}" method="POST">
|
||||||
@csrf
|
@csrf
|
||||||
@method('DELETE')
|
@method('DELETE')
|
||||||
|
@ -117,6 +122,113 @@ class="w-full bg-gray-500 text-white px-3 py-1 rounded hover:bg-gray-600">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Modal Alasan Penolakan -->
|
||||||
|
<div id="alasanPenolakanModal" class="fixed inset-0 bg-black bg-opacity-50 hidden items-center justify-center z-50">
|
||||||
|
<div class="bg-white rounded-lg shadow-xl max-w-md w-full mx-4">
|
||||||
|
<div class="p-6">
|
||||||
|
<div class="flex justify-between items-start mb-4">
|
||||||
|
<h3 class="text-lg font-bold text-gray-800">Alasan Penolakan</h3>
|
||||||
|
<button onclick="closeAlasanPenolakan()" class="text-gray-400 hover:text-gray-600">
|
||||||
|
<svg class="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="bg-red-50 border-l-4 border-red-500 p-4 rounded">
|
||||||
|
<p id="alasanPenolakanText" class="text-red-700"></p>
|
||||||
|
</div>
|
||||||
|
<div class="mt-4 flex justify-end">
|
||||||
|
<button onclick="closeAlasanPenolakan()"
|
||||||
|
class="px-4 py-2 bg-gray-300 text-gray-700 rounded hover:bg-gray-400">
|
||||||
|
Tutup
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Modal Form Pembatalan -->
|
||||||
|
<div id="cancelFormModal" class="fixed inset-0 bg-black bg-opacity-50 hidden items-center justify-center z-50">
|
||||||
|
<div class="bg-white rounded-lg shadow-xl max-w-md w-full mx-4">
|
||||||
|
<div class="p-6">
|
||||||
|
<div class="flex justify-between items-start mb-4">
|
||||||
|
<h3 class="text-lg font-bold text-gray-800">Form Pembatalan Pesanan</h3>
|
||||||
|
<button onclick="closeCancelForm()" class="text-gray-400 hover:text-gray-600">
|
||||||
|
<svg class="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-4">
|
||||||
|
<h4 class="font-semibold text-gray-700 mb-2">Detail Pesanan</h4>
|
||||||
|
<div class="bg-gray-50 p-3 rounded text-sm">
|
||||||
|
<p><strong>ID Pesanan:</strong> <span id="cancelOrderId"></span></p>
|
||||||
|
<p><strong>Paket:</strong> <span id="cancelOrderPackage"></span></p>
|
||||||
|
<p><strong>Status:</strong> <span id="cancelOrderStatus"></span></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form id="cancelOrderForm" method="POST">
|
||||||
|
@csrf
|
||||||
|
@method('PUT')
|
||||||
|
|
||||||
|
<div class="mb-4">
|
||||||
|
<label for="alasan_pembatalan" class="block text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Alasan Pembatalan <span class="text-red-500">*</span>
|
||||||
|
</label>
|
||||||
|
<select id="alasan_pembatalan" name="alasan_pembatalan"
|
||||||
|
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-red-500 focus:border-transparent"
|
||||||
|
required>
|
||||||
|
<option value="">-- Pilih Alasan --</option>
|
||||||
|
<option value="Perubahan rencana">Perubahan rencana</option>
|
||||||
|
<option value="Kendala keuangan">Kendala keuangan</option>
|
||||||
|
<option value="Tidak sesuai ekspektasi">Tidak sesuai ekspektasi</option>
|
||||||
|
<option value="Masalah teknis">Masalah teknis</option>
|
||||||
|
<option value="Lainnya">Lainnya</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-4" id="alasanLainnyaDiv" style="display:none;">
|
||||||
|
<label for="alasan_lainnya" class="block text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Jelaskan alasan lainnya
|
||||||
|
</label>
|
||||||
|
<textarea id="alasan_lainnya" name="alasan_lainnya" rows="3"
|
||||||
|
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-red-500 focus:border-transparent"
|
||||||
|
placeholder="Silakan jelaskan alasan pembatalan Anda..."></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-yellow-50 border border-yellow-200 rounded-lg p-4 mb-4">
|
||||||
|
<div class="flex">
|
||||||
|
<div class="flex-shrink-0">
|
||||||
|
<svg class="h-5 w-5 text-yellow-400" viewBox="0 0 20 20" fill="currentColor">
|
||||||
|
<path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div class="ml-3">
|
||||||
|
<h3 class="text-sm font-medium text-yellow-800">Peringatan</h3>
|
||||||
|
<div class="mt-2 text-sm text-yellow-700">
|
||||||
|
<p>Dengan membatalkan pesanan ini, Anda tidak akan dapat mengembalikannya. Alasan pembatalan akan dikirim ke admin untuk evaluasi.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex justify-end space-x-3">
|
||||||
|
<button type="button" onclick="closeCancelForm()"
|
||||||
|
class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2">
|
||||||
|
Batal
|
||||||
|
</button>
|
||||||
|
<button type="submit"
|
||||||
|
class="px-4 py-2 bg-red-600 text-white rounded-md hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2">
|
||||||
|
Batalkan Pesanan
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
@else
|
@else
|
||||||
<div class="text-center py-8">
|
<div class="text-center py-8">
|
||||||
<p class="text-gray-500">Belum ada riwayat pemesanan</p>
|
<p class="text-gray-500">Belum ada riwayat pemesanan</p>
|
||||||
|
@ -164,6 +276,7 @@ class="w-full bg-gray-500 text-white px-3 py-1 rounded hover:bg-gray-600">
|
||||||
<div class="bg-gray-50 p-4 rounded-lg">
|
<div class="bg-gray-50 p-4 rounded-lg">
|
||||||
<p class="text-sm">Tanggal Pembayaran: ${data.tanggal_pembayaran || '-'}</p>
|
<p class="text-sm">Tanggal Pembayaran: ${data.tanggal_pembayaran || '-'}</p>
|
||||||
<p class="text-sm">Status: ${data.status_pembayaran}</p>
|
<p class="text-sm">Status: ${data.status_pembayaran}</p>
|
||||||
|
${data.detail_status ? `<p class="text-sm text-red-600">Alasan Penolakan: ${data.detail_status}</p>` : ''}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -233,6 +346,119 @@ function closeDetail() {
|
||||||
closeDetail();
|
closeDetail();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function showAlasanPenolakan(alasan) {
|
||||||
|
const alasanPenolakanText = document.getElementById('alasanPenolakanText');
|
||||||
|
alasanPenolakanText.textContent = alasan;
|
||||||
|
document.getElementById('alasanPenolakanModal').classList.remove('hidden');
|
||||||
|
document.getElementById('alasanPenolakanModal').classList.add('flex');
|
||||||
|
document.body.style.overflow = 'hidden';
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeAlasanPenolakan() {
|
||||||
|
document.getElementById('alasanPenolakanModal').classList.add('hidden');
|
||||||
|
document.getElementById('alasanPenolakanModal').classList.remove('flex');
|
||||||
|
document.body.style.overflow = 'auto';
|
||||||
|
}
|
||||||
|
|
||||||
|
function showCancelForm(sewaId, paketNama, status) {
|
||||||
|
document.getElementById('cancelOrderId').textContent = sewaId;
|
||||||
|
document.getElementById('cancelOrderPackage').textContent = paketNama;
|
||||||
|
document.getElementById('cancelOrderStatus').textContent = status;
|
||||||
|
document.getElementById('cancelFormModal').classList.remove('hidden');
|
||||||
|
document.getElementById('cancelFormModal').classList.add('flex');
|
||||||
|
document.body.style.overflow = 'hidden';
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeCancelForm() {
|
||||||
|
document.getElementById('cancelFormModal').classList.add('hidden');
|
||||||
|
document.getElementById('cancelFormModal').classList.remove('flex');
|
||||||
|
document.body.style.overflow = 'auto';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle alasan pembatalan dropdown
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const alasanSelect = document.getElementById('alasan_pembatalan');
|
||||||
|
const alasanLainnyaDiv = document.getElementById('alasanLainnyaDiv');
|
||||||
|
const alasanLainnyaTextarea = document.getElementById('alasan_lainnya');
|
||||||
|
|
||||||
|
if (alasanSelect) {
|
||||||
|
alasanSelect.addEventListener('change', function() {
|
||||||
|
if (this.value === 'Lainnya') {
|
||||||
|
alasanLainnyaDiv.style.display = 'block';
|
||||||
|
alasanLainnyaTextarea.required = true;
|
||||||
|
} else {
|
||||||
|
alasanLainnyaDiv.style.display = 'none';
|
||||||
|
alasanLainnyaTextarea.required = false;
|
||||||
|
alasanLainnyaTextarea.value = '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle form submission
|
||||||
|
const cancelForm = document.getElementById('cancelOrderForm');
|
||||||
|
if (cancelForm) {
|
||||||
|
cancelForm.addEventListener('submit', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const alasanPembatalan = document.getElementById('alasan_pembatalan').value;
|
||||||
|
const alasanLainnya = document.getElementById('alasan_lainnya').value;
|
||||||
|
const sewaId = document.getElementById('cancelOrderId').textContent;
|
||||||
|
|
||||||
|
if (!alasanPembatalan) {
|
||||||
|
alert('Silakan pilih alasan pembatalan!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alasanPembatalan === 'Lainnya' && !alasanLainnya.trim()) {
|
||||||
|
alert('Silakan isi alasan lainnya!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gabungkan alasan
|
||||||
|
const finalAlasan = alasanPembatalan === 'Lainnya' ? alasanLainnya : alasanPembatalan;
|
||||||
|
|
||||||
|
// Konfirmasi pembatalan
|
||||||
|
if (!confirm('Apakah Anda yakin ingin membatalkan pesanan ini? Alasan pembatalan akan dikirim ke admin.')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kirim data ke server
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('_token', '{{ csrf_token() }}');
|
||||||
|
formData.append('_method', 'PUT');
|
||||||
|
formData.append('alasan_pembatalan', finalAlasan);
|
||||||
|
|
||||||
|
fetch(`/riwayat/${sewaId}/batal`, {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData,
|
||||||
|
headers: {
|
||||||
|
'X-Requested-With': 'XMLHttpRequest'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.success) {
|
||||||
|
alert('Pesanan berhasil dibatalkan! Alasan pembatalan telah dikirim ke admin.');
|
||||||
|
window.location.reload();
|
||||||
|
} else {
|
||||||
|
alert('Terjadi kesalahan: ' + (data.message || 'Gagal membatalkan pesanan'));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error:', error);
|
||||||
|
alert('Terjadi kesalahan saat membatalkan pesanan. Silakan coba lagi.');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Menutup modal saat mengklik area di luar modal
|
||||||
|
document.getElementById('cancelFormModal').addEventListener('click', function(e) {
|
||||||
|
if (e.target === this) {
|
||||||
|
closeCancelForm();
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
@endpush
|
@endpush
|
||||||
@endsection
|
@endsection
|
|
@ -0,0 +1,87 @@
|
||||||
|
@extends('layouts.app')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="container mx-auto px-4 py-8">
|
||||||
|
<div class="max-w-2xl mx-auto">
|
||||||
|
<div class="bg-white rounded-lg shadow-md p-6">
|
||||||
|
<h2 class="text-2xl font-bold mb-6 text-gray-800">Form Pembatalan Pesanan</h2>
|
||||||
|
|
||||||
|
<div class="mb-6">
|
||||||
|
<h3 class="text-lg font-semibold mb-3 text-gray-700">Detail Pesanan</h3>
|
||||||
|
<div class="bg-gray-50 p-4 rounded-lg">
|
||||||
|
<div class="grid grid-cols-2 gap-4">
|
||||||
|
<div>
|
||||||
|
<p class="text-sm text-gray-600">ID Pesanan:</p>
|
||||||
|
<p class="font-medium">{{ $sewa->id }}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="text-sm text-gray-600">Status:</p>
|
||||||
|
<p class="font-medium">{{ ucfirst($sewa->status) }}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="text-sm text-gray-600">Paket:</p>
|
||||||
|
<p class="font-medium">{{ $sewa->paket->nama ?? 'N/A' }}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="text-sm text-gray-600">Tanggal Sewa:</p>
|
||||||
|
<p class="font-medium">{{ $sewa->created_at->format('d/m/Y H:i') }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form action="{{ route('riwayat.process-cancel', $sewa->id) }}" method="POST">
|
||||||
|
@csrf
|
||||||
|
@method('PUT')
|
||||||
|
|
||||||
|
<div class="mb-6">
|
||||||
|
<label for="alasan_pembatalan" class="block text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Alasan Pembatalan <span class="text-red-500">*</span>
|
||||||
|
</label>
|
||||||
|
<textarea
|
||||||
|
id="alasan_pembatalan"
|
||||||
|
name="alasan_pembatalan"
|
||||||
|
rows="4"
|
||||||
|
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent @error('alasan_pembatalan') border-red-500 @enderror"
|
||||||
|
placeholder="Silakan jelaskan alasan pembatalan pesanan Anda..."
|
||||||
|
required
|
||||||
|
>{{ old('alasan_pembatalan') }}</textarea>
|
||||||
|
@error('alasan_pembatalan')
|
||||||
|
<p class="text-red-500 text-sm mt-1">{{ $message }}</p>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-yellow-50 border border-yellow-200 rounded-lg p-4 mb-6">
|
||||||
|
<div class="flex">
|
||||||
|
<div class="flex-shrink-0">
|
||||||
|
<svg class="h-5 w-5 text-yellow-400" viewBox="0 0 20 20" fill="currentColor">
|
||||||
|
<path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div class="ml-3">
|
||||||
|
<h3 class="text-sm font-medium text-yellow-800">
|
||||||
|
Peringatan
|
||||||
|
</h3>
|
||||||
|
<div class="mt-2 text-sm text-yellow-700">
|
||||||
|
<p>Dengan membatalkan pesanan ini, Anda tidak akan dapat mengembalikannya. Pastikan Anda yakin dengan keputusan ini.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex justify-end space-x-4">
|
||||||
|
<a href="{{ route('riwayat') }}"
|
||||||
|
class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2">
|
||||||
|
Kembali
|
||||||
|
</a>
|
||||||
|
<button type="submit"
|
||||||
|
class="px-4 py-2 bg-red-600 text-white rounded-md hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2"
|
||||||
|
onclick="return confirm('Apakah Anda yakin ingin membatalkan pesanan ini?')">
|
||||||
|
Batalkan Pesanan
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
|
@ -27,19 +27,12 @@ class="w-full h-full object-cover">
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@php
|
@if($paket->stok_tersedia <= 0)
|
||||||
$activeSewa = $paket->sewas()
|
|
||||||
->whereIn('status', ['confirmed', 'ongoing'])
|
|
||||||
->count();
|
|
||||||
$tersedia = $paket->stok - $activeSewa;
|
|
||||||
@endphp
|
|
||||||
|
|
||||||
@if($tersedia <= 0)
|
|
||||||
<div class="absolute inset-0 bg-black bg-opacity-50 flex items-center justify-center">
|
<div class="absolute inset-0 bg-black bg-opacity-50 flex items-center justify-center">
|
||||||
<div class="text-white text-center p-4">
|
<div class="text-white text-center p-4">
|
||||||
<i class="fas fa-clock text-3xl mb-2"></i>
|
<i class="fas fa-clock text-3xl mb-2"></i>
|
||||||
<p class="font-bold">Sedang Disewa</p>
|
<p class="font-bold">Sedang Disewa</p>
|
||||||
<p class="text-sm">{{ $activeSewa }} dari {{ $paket->stok }} unit disewa</p>
|
<p class="text-sm">{{ $paket->active_sewa_count }} dari {{ $paket->stok }} unit disewa</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
@ -64,24 +57,20 @@ class="w-full h-full object-cover">
|
||||||
<span class="text-gray-600">Stok:</span>
|
<span class="text-gray-600">Stok:</span>
|
||||||
<span class="font-semibold">
|
<span class="font-semibold">
|
||||||
{{ $paket->stok }}
|
{{ $paket->stok }}
|
||||||
@if($activeSewa > 0)
|
@if($paket->active_sewa_count > 0)
|
||||||
<span class="text-orange-500 text-sm ml-1">({{ $tersedia }} tersedia)</span>
|
<span class="text-orange-500 text-sm ml-1">({{ $paket->stok_tersedia }} tersedia)</span>
|
||||||
@endif
|
@endif
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-between">
|
<div class="flex justify-between">
|
||||||
<span class="text-gray-600">Status:</span>
|
<span class="text-gray-600">Status:</span>
|
||||||
<span class="font-semibold
|
<span class="font-semibold
|
||||||
@if($tersedia > 0)
|
@if($paket->is_available)
|
||||||
text-green-600
|
text-green-600
|
||||||
@else
|
@else
|
||||||
text-red-600
|
text-red-600
|
||||||
@endif">
|
@endif">
|
||||||
@if($tersedia > 0)
|
{{ $paket->status_ketersediaan }}
|
||||||
Tersedia ({{ $tersedia }} unit)
|
|
||||||
@else
|
|
||||||
Sedang Disewa Semua
|
|
||||||
@endif
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -114,7 +103,7 @@ class="w-full bg-gray-100 hover:bg-gray-200 text-gray-800 font-semibold py-2 px-
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
@auth
|
@auth
|
||||||
@if($tersedia <= 0)
|
@if($paket->stok_tersedia <= 0)
|
||||||
<button disabled
|
<button disabled
|
||||||
class="w-full bg-gray-400 text-white py-2 px-4 rounded cursor-not-allowed">
|
class="w-full bg-gray-400 text-white py-2 px-4 rounded cursor-not-allowed">
|
||||||
<i class="fas fa-ban mr-2"></i>Tidak Tersedia
|
<i class="fas fa-ban mr-2"></i>Tidak Tersedia
|
||||||
|
|
|
@ -78,11 +78,11 @@ class="w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:r
|
||||||
|
|
||||||
<!-- Kota Tujuan -->
|
<!-- Kota Tujuan -->
|
||||||
<div>
|
<div>
|
||||||
<label for="kota_id" class="block text-sm font-medium text-gray-700 mb-2">Kota Tujuan</label>
|
<label for="kota_id" class="block text-sm font-medium text-gray-700 mb-2">Kabupaten Tujuan</label>
|
||||||
<select id="kota_id" name="kota_id"
|
<select id="kota_id" name="kota_id"
|
||||||
class="w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring focus:ring-blue-200"
|
class="w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring focus:ring-blue-200"
|
||||||
required>
|
required>
|
||||||
<option value="">Pilih Kota</option>
|
<option value="">Pilih Kabupaten</option>
|
||||||
@foreach($paket->ongkirKota as $kota)
|
@foreach($paket->ongkirKota as $kota)
|
||||||
<option value="{{ $kota->id }}" data-ongkir="{{ $kota->biaya_ongkir }}">
|
<option value="{{ $kota->id }}" data-ongkir="{{ $kota->biaya_ongkir }}">
|
||||||
{{ $kota->nama_kota }} - Rp {{ number_format($kota->biaya_ongkir, 0, ',', '.') }}
|
{{ $kota->nama_kota }} - Rp {{ number_format($kota->biaya_ongkir, 0, ',', '.') }}
|
||||||
|
|
|
@ -70,6 +70,9 @@
|
||||||
@endif">
|
@endif">
|
||||||
{{ ucfirst($sewa->status) }}
|
{{ ucfirst($sewa->status) }}
|
||||||
</span>
|
</span>
|
||||||
|
@if($sewa->status === 'ditolak' && $sewa->catatan)
|
||||||
|
<button type="button" class="ml-2 text-xs text-blue-600 underline lihat-penolakan-btn" data-alasan="{{ $sewa->catatan }}">Lihat Penolakan</button>
|
||||||
|
@endif
|
||||||
</td>
|
</td>
|
||||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||||
Rp {{ number_format($sewa->total_harga, 0, ',', '.') }}
|
Rp {{ number_format($sewa->total_harga, 0, ',', '.') }}
|
||||||
|
@ -79,6 +82,10 @@
|
||||||
class="bg-blue-500 hover:bg-blue-600 text-white px-3 py-1 rounded-md text-sm">
|
class="bg-blue-500 hover:bg-blue-600 text-white px-3 py-1 rounded-md text-sm">
|
||||||
Detail
|
Detail
|
||||||
</button>
|
</button>
|
||||||
|
@if($sewa->status === 'ditolak' && $sewa->catatan)
|
||||||
|
<button type="button" class="mt-2 block text-xs text-blue-600 underline lihat-penolakan-btn" data-alasan="{{ $sewa->catatan }}">Lihat Penolakan</button>
|
||||||
|
@endif
|
||||||
|
<button class="bg-red-500 hover:bg-red-600 text-white px-3 py-1 rounded-md text-sm mt-2">Batalkan Pesanan</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@empty
|
@empty
|
||||||
|
@ -112,57 +119,57 @@ class="bg-blue-500 hover:bg-blue-600 text-white px-3 py-1 rounded-md text-sm">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@push('scripts')
|
<!-- Modal Alasan Penolakan -->
|
||||||
<script>
|
<div id="modalPenolakan" class="fixed inset-0 flex items-center justify-center z-50 hidden bg-black bg-opacity-40">
|
||||||
function showDetail(sewaId) {
|
<div class="bg-white rounded-lg shadow-lg p-6 w-full max-w-md">
|
||||||
fetch(`/sewa/${sewaId}/detail`)
|
<h3 class="text-lg font-bold mb-4">Alasan Penolakan</h3>
|
||||||
.then(response => response.json())
|
<div id="alasanPenolakanText" class="mb-4 text-gray-700"></div>
|
||||||
.then(data => {
|
<div class="flex justify-end">
|
||||||
const modal = document.getElementById('detailModal');
|
<button type="button" id="closeModalPenolakan" class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">Tutup</button>
|
||||||
const content = document.getElementById('modalContent');
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
content.innerHTML = `
|
<script>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
function showDetail(id) {
|
||||||
<div class="space-y-3">
|
fetch(`/sewa/${id}/json`)
|
||||||
<div>
|
.then(response => {
|
||||||
<h4 class="text-sm font-medium text-gray-500">Informasi Penyewa</h4>
|
if (!response.ok) throw new Error('Gagal mengambil data');
|
||||||
<p class="text-gray-900">${data.user.nama}</p>
|
return response.json();
|
||||||
<p class="text-gray-600">${data.user.email}</p>
|
})
|
||||||
<p class="text-gray-600">${data.user.no_hp || '-'}</p>
|
.then(sewa => {
|
||||||
</div>
|
let barangList = '';
|
||||||
<div>
|
if (sewa.barangs && sewa.barangs.length > 0) {
|
||||||
<h4 class="text-sm font-medium text-gray-500">Paket Disewa</h4>
|
barangList = '<ul>';
|
||||||
<p class="text-gray-900">${data.paket.nama_paket}</p>
|
sewa.barangs.forEach(barang => {
|
||||||
<p class="text-gray-600">${data.paket.jenis_paket}</p>
|
barangList += `<li>${barang.nama_barang} (${barang.jumlah} unit)</li>`;
|
||||||
</div>
|
});
|
||||||
</div>
|
barangList += '</ul>';
|
||||||
<div class="space-y-3">
|
} else {
|
||||||
<div>
|
barangList = '<p>Tidak ada barang dalam paket</p>';
|
||||||
<h4 class="text-sm font-medium text-gray-500">Detail Sewa</h4>
|
}
|
||||||
<p class="text-gray-600">Mulai: ${data.tanggal_mulai}</p>
|
document.getElementById('modalContent').innerHTML = `
|
||||||
<p class="text-gray-600">Selesai: ${data.tanggal_selesai}</p>
|
<div class="space-y-2">
|
||||||
<p class="text-gray-600">Status: ${data.status}</p>
|
<p><b>Nama Paket:</b> ${sewa.paket.nama_paket}</p>
|
||||||
</div>
|
<p><b>Jenis Paket:</b> ${sewa.paket.jenis_paket}</p>
|
||||||
<div>
|
<p><b>Harga per Hari:</b> Rp ${parseInt(sewa.paket.harga).toLocaleString('id-ID')}</p>
|
||||||
<h4 class="text-sm font-medium text-gray-500">Pembayaran</h4>
|
<p><b>Penyewa:</b> ${sewa.user.nama} (${sewa.user.email})</p>
|
||||||
<p class="text-gray-900">Total: Rp ${data.total_harga}</p>
|
<p><b>Tanggal Sewa:</b> ${sewa.tanggal_mulai} - ${sewa.tanggal_selesai}</p>
|
||||||
<p class="text-gray-600">Dibayar: Rp ${data.nominal_pembayaran || 0}</p>
|
<p><b>Status:</b> ${sewa.status}</p>
|
||||||
</div>
|
<p><b>Total Harga:</b> Rp ${parseInt(sewa.total_harga).toLocaleString('id-ID')}</p>
|
||||||
</div>
|
<p><b>Kota:</b> ${sewa.kota || '-'}</p>
|
||||||
<div class="col-span-2">
|
<p><b>Alamat:</b> ${sewa.lokasi || '-'}</p>
|
||||||
<h4 class="text-sm font-medium text-gray-500">Lokasi Pengiriman</h4>
|
${sewa.catatan ? `<p><b>Catatan:</b> ${sewa.catatan}</p>` : ''}
|
||||||
<p class="text-gray-900">${data.lokasi}</p>
|
<b>Daftar Barang:</b>
|
||||||
<p class="text-gray-600">Kota: ${data.kota ? data.kota.nama_kota : '-'}</p>
|
${barangList}
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
const modal = document.getElementById('detailModal');
|
||||||
modal.classList.remove('hidden');
|
modal.classList.remove('hidden');
|
||||||
modal.classList.add('flex');
|
modal.classList.add('flex');
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(() => {
|
||||||
console.error('Error:', error);
|
alert('Gagal memuat detail sewa');
|
||||||
alert('Terjadi kesalahan saat memuat detail');
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,6 +185,16 @@ function closeModal() {
|
||||||
closeModal();
|
closeModal();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
document.querySelectorAll('.lihat-penolakan-btn').forEach(btn => {
|
||||||
|
btn.addEventListener('click', function() {
|
||||||
|
document.getElementById('alasanPenolakanText').innerText = this.getAttribute('data-alasan');
|
||||||
|
document.getElementById('modalPenolakan').classList.remove('hidden');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('closeModalPenolakan').onclick = function() {
|
||||||
|
document.getElementById('modalPenolakan').classList.add('hidden');
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
@endpush
|
|
||||||
@endsection
|
@endsection
|
|
@ -62,13 +62,16 @@
|
||||||
bg-green-100 text-green-800
|
bg-green-100 text-green-800
|
||||||
@elseif($sewa->status === 'ongoing')
|
@elseif($sewa->status === 'ongoing')
|
||||||
bg-blue-100 text-blue-800
|
bg-blue-100 text-blue-800
|
||||||
@elseif($sewa->status === 'completed')
|
@elseif($sewa->status === 'selesai')
|
||||||
bg-purple-100 text-purple-800
|
bg-purple-100 text-purple-800
|
||||||
@else
|
@else
|
||||||
bg-red-100 text-red-800
|
bg-red-100 text-red-800
|
||||||
@endif">
|
@endif">
|
||||||
{{ ucfirst($sewa->status) }}
|
{{ ucfirst($sewa->status) }}
|
||||||
</span>
|
</span>
|
||||||
|
@if($sewa->status === 'ditolak' && $sewa->catatan)
|
||||||
|
<button type="button" class="ml-2 text-xs text-blue-600 underline lihat-penolakan-btn" data-alasan="{{ $sewa->catatan }}">Lihat Penolakan</button>
|
||||||
|
@endif
|
||||||
</td>
|
</td>
|
||||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||||
Rp {{ number_format($sewa->total_harga, 0, ',', '.') }}
|
Rp {{ number_format($sewa->total_harga, 0, ',', '.') }}
|
||||||
|
@ -92,4 +95,26 @@ class="text-blue-600 hover:text-blue-900">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Modal Alasan Penolakan -->
|
||||||
|
<div id="modalPenolakan" class="fixed inset-0 flex items-center justify-center z-50 hidden bg-black bg-opacity-40">
|
||||||
|
<div class="bg-white rounded-lg shadow-lg p-6 w-full max-w-md">
|
||||||
|
<h3 class="text-lg font-bold mb-4">Alasan Penolakan</h3>
|
||||||
|
<div id="alasanPenolakanText" class="mb-4 text-gray-700"></div>
|
||||||
|
<div class="flex justify-end">
|
||||||
|
<button type="button" id="closeModalPenolakan" class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">Tutup</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
document.querySelectorAll('.lihat-penolakan-btn').forEach(btn => {
|
||||||
|
btn.addEventListener('click', function() {
|
||||||
|
document.getElementById('alasanPenolakanText').innerText = this.getAttribute('data-alasan');
|
||||||
|
document.getElementById('modalPenolakan').classList.remove('hidden');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
document.getElementById('closeModalPenolakan').onclick = function() {
|
||||||
|
document.getElementById('modalPenolakan').classList.add('hidden');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
@endsection
|
@endsection
|
|
@ -117,7 +117,7 @@
|
||||||
<div class="bg-blue-50 border-l-4 border-blue-500 text-blue-700 p-4 mb-4">
|
<div class="bg-blue-50 border-l-4 border-blue-500 text-blue-700 p-4 mb-4">
|
||||||
<p class="font-medium">Informasi Pembayaran:</p>
|
<p class="font-medium">Informasi Pembayaran:</p>
|
||||||
<p>tolong masukkan nominal pembayaran sebesar
|
<p>tolong masukkan nominal pembayaran sebesar
|
||||||
DP50% dari total harga yang sudah diberikan
|
DP30% sampai 100% dari total harga yang sudah diberikan
|
||||||
segera lakukan pembayaran ke rekening dibawah ini
|
segera lakukan pembayaran ke rekening dibawah ini
|
||||||
agar proses penyewaan ditangani lebih cepat
|
agar proses penyewaan ditangani lebih cepat
|
||||||
jika ada masalah mohon hubungi admin di bagian hubungi kami
|
jika ada masalah mohon hubungi admin di bagian hubungi kami
|
||||||
|
@ -130,18 +130,22 @@
|
||||||
<!-- Nominal Pembayaran -->
|
<!-- Nominal Pembayaran -->
|
||||||
<div>
|
<div>
|
||||||
<label for="nominal_pembayaran" class="block text-sm font-medium text-gray-700 mb-1">
|
<label for="nominal_pembayaran" class="block text-sm font-medium text-gray-700 mb-1">
|
||||||
Nominal Pembayaran (DP 50% = Rp {{ number_format($sewa->total_harga * 0.5, 0, ',', '.') }})
|
Nominal Pembayaran (Pilih persentase pembayaran)
|
||||||
</label>
|
</label>
|
||||||
<div class="relative rounded-md shadow-sm">
|
<div class="relative rounded-md shadow-sm">
|
||||||
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||||
<span class="text-gray-500 sm:text-sm">Rp</span>
|
<span class="text-gray-500 sm:text-sm">Rp</span>
|
||||||
</div>
|
</div>
|
||||||
<input type="number" name="nominal_pembayaran" id="nominal_pembayaran"
|
<select name="nominal_pembayaran" id="nominal_pembayaran"
|
||||||
class="block w-full pl-10 pr-3 py-2 border border-gray-300 rounded-md focus:ring-blue-500 focus:border-blue-500"
|
class="block w-full pl-10 pr-3 py-2 border border-gray-300 rounded-md focus:ring-blue-500 focus:border-blue-500"
|
||||||
placeholder="Masukkan nominal pembayaran sesuai keinginan"
|
|
||||||
min="1"
|
|
||||||
max="{{ $sewa->total_harga }}"
|
|
||||||
required>
|
required>
|
||||||
|
<option value="">Pilih nominal pembayaran</option>
|
||||||
|
@for ($i = 30; $i <= 100; $i += 10)
|
||||||
|
<option value="{{ intval($sewa->total_harga * ($i/100)) }}">
|
||||||
|
{{ $i }}% = Rp {{ number_format($sewa->total_harga * ($i/100), 0, ',', '.') }}
|
||||||
|
</option>
|
||||||
|
@endfor
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
@error('nominal_pembayaran')
|
@error('nominal_pembayaran')
|
||||||
<p class="text-red-500 text-sm mt-1">{{ $message }}</p>
|
<p class="text-red-500 text-sm mt-1">{{ $message }}</p>
|
||||||
|
|
|
@ -81,6 +81,10 @@
|
||||||
Route::post('/pengguna', [PenggunaController::class, 'store'])->name('pengguna.store');
|
Route::post('/pengguna', [PenggunaController::class, 'store'])->name('pengguna.store');
|
||||||
Route::delete('/pengguna/{id}', [PenggunaController::class, 'destroy'])->name('pengguna.destroy');
|
Route::delete('/pengguna/{id}', [PenggunaController::class, 'destroy'])->name('pengguna.destroy');
|
||||||
|
|
||||||
|
// Users (data pengguna biasa)
|
||||||
|
Route::get('/users', [UserController::class, 'index'])->name('users');
|
||||||
|
Route::delete('/users/{id}', [UserController::class, 'destroy'])->name('users.destroy');
|
||||||
|
|
||||||
// Admin
|
// Admin
|
||||||
Route::get('/admin', [AdminController::class, 'index'])->name('admin');
|
Route::get('/admin', [AdminController::class, 'index'])->name('admin');
|
||||||
Route::get('/admin/tambah', [AdminController::class, 'create'])->name('admin.create');
|
Route::get('/admin/tambah', [AdminController::class, 'create'])->name('admin.create');
|
||||||
|
@ -156,11 +160,21 @@
|
||||||
Route::delete('/riwayat/hapus/{id}', [\App\Http\Controllers\RiwayatController::class, 'hapus']);
|
Route::delete('/riwayat/hapus/{id}', [\App\Http\Controllers\RiwayatController::class, 'hapus']);
|
||||||
Route::get('/riwayat', [\App\Http\Controllers\RiwayatController::class, 'index'])->name('riwayat');
|
Route::get('/riwayat', [\App\Http\Controllers\RiwayatController::class, 'index'])->name('riwayat');
|
||||||
|
|
||||||
|
// Route untuk mengaktifkan stok dari riwayat
|
||||||
|
Route::post('/riwayat/{id}/activate-stock', [\App\Http\Controllers\RiwayatController::class, 'activateStock'])->name('riwayat.activate-stock');
|
||||||
|
|
||||||
|
// Route untuk pesanan yang dibatalkan
|
||||||
|
Route::get('/cancelled-orders', [App\Http\Controllers\Admin\DashboardController::class, 'cancelledOrders'])->name('cancelled-orders');
|
||||||
|
Route::get('/cancelled-orders/{id}', [App\Http\Controllers\Admin\DashboardController::class, 'showCancelledOrder'])->name('cancelled-orders.show');
|
||||||
|
Route::get('/cancelled-orders-count', [App\Http\Controllers\Admin\DashboardController::class, 'getCancelledOrdersCount'])->name('cancelled-orders.count');
|
||||||
|
Route::get('/recent-cancellations', [App\Http\Controllers\Admin\DashboardController::class, 'getRecentCancellations'])->name('recent-cancellations');
|
||||||
|
|
||||||
|
|
||||||
// Verifikasi Pembayaran
|
// Verifikasi Pembayaran
|
||||||
Route::get('/verifikasi', [App\Http\Controllers\Admin\VerifikasiController::class, 'index'])->name('verifikasi.index');
|
Route::get('/verifikasi', [App\Http\Controllers\Admin\VerifikasiController::class, 'index'])->name('verifikasi.index');
|
||||||
Route::post('/verifikasi/{id}/approve', [App\Http\Controllers\Admin\VerifikasiController::class, 'approve'])->name('verifikasi.approve');
|
Route::post('/verifikasi/{id}/approve', [App\Http\Controllers\Admin\VerifikasiController::class, 'approve'])->name('verifikasi.approve');
|
||||||
Route::post('/verifikasi/{id}/reject', [App\Http\Controllers\Admin\VerifikasiController::class, 'reject'])->name('verifikasi.reject');
|
Route::post('/verifikasi/{id}/reject', [App\Http\Controllers\Admin\VerifikasiController::class, 'reject'])->name('verifikasi.reject');
|
||||||
|
Route::get('/verifikasi/alasan-penolakan', [App\Http\Controllers\Admin\VerifikasiController::class, 'getAlasanPenolakan'])->name('verifikasi.alasan-penolakan');
|
||||||
|
|
||||||
// Laporan Transaksi
|
// Laporan Transaksi
|
||||||
Route::get('/reports/transactions', [App\Http\Controllers\Admin\ReportController::class, 'transactions'])->name('reports.transactions');
|
Route::get('/reports/transactions', [App\Http\Controllers\Admin\ReportController::class, 'transactions'])->name('reports.transactions');
|
||||||
|
@ -217,8 +231,4 @@
|
||||||
|
|
||||||
Route::get('/paket/{id}/detail', [PaketController::class, 'detail'])->name('paket.detail');
|
Route::get('/paket/{id}/detail', [PaketController::class, 'detail'])->name('paket.detail');
|
||||||
|
|
||||||
// Route untuk data pengguna biasa
|
|
||||||
Route::get('/users', [UserController::class, 'index'])->name('users');
|
|
||||||
Route::delete('/users/{id}', [UserController::class, 'destroy'])->name('users.destroy');
|
|
||||||
|
|
||||||
Route::put('/admin/riwayat/{id}/update-status', [App\Http\Controllers\Admin\ReportController::class, 'updateStatus'])->name('admin.riwayat.update-status');
|
Route::put('/admin/riwayat/{id}/update-status', [App\Http\Controllers\Admin\ReportController::class, 'updateStatus'])->name('admin.riwayat.update-status');
|
||||||
|
|
Loading…
Reference in New Issue