parent
b68eca055b
commit
b5acd49443
|
|
@ -82,6 +82,7 @@ public function showVerifyOtpForm(Request $request)
|
||||||
// ─────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────
|
||||||
// STEP 2 — Proses: verifikasi OTP
|
// STEP 2 — Proses: verifikasi OTP
|
||||||
// ─────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────
|
||||||
|
// STEP 2 — Proses: verifikasi OTP
|
||||||
public function verifyOtp(Request $request)
|
public function verifyOtp(Request $request)
|
||||||
{
|
{
|
||||||
$request->validate([
|
$request->validate([
|
||||||
|
|
@ -104,13 +105,17 @@ public function verifyOtp(Request $request)
|
||||||
return back()->with('error', 'Kode OTP tidak ditemukan. Silakan kirim ulang.');
|
return back()->with('error', 'Kode OTP tidak ditemukan. Silakan kirim ulang.');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Carbon::now()->diffInMinutes(Carbon::parse($record->created_at)) > 10) {
|
// ✅ CEK EXPIRED — hapus record & paksa user kirim ulang
|
||||||
|
if (Carbon::now()->diffInSeconds(Carbon::parse($record->created_at)) >= 180) {
|
||||||
DB::table('password_reset_tokens')->where('email', $email)->delete();
|
DB::table('password_reset_tokens')->where('email', $email)->delete();
|
||||||
return back()->with('error', 'Kode OTP sudah kadaluarsa. Silakan kirim ulang kode.');
|
return back()->with('otp_expired', true) // flag khusus untuk view
|
||||||
|
->with('error', 'Kode OTP sudah kadaluarsa (3 menit). Silakan kirim ulang kode.');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Hash::check($request->otp, $record->token)) {
|
if (!Hash::check($request->otp, $record->token)) {
|
||||||
return back()->with('error', 'Kode OTP salah. Periksa kembali kode yang Anda masukkan.');
|
return back()
|
||||||
|
->with('error', 'Kode OTP salah. Waktu berkurang 30 detik.')
|
||||||
|
->with('otp_wrong', true); // ← flag untuk kurangi timer di frontend
|
||||||
}
|
}
|
||||||
|
|
||||||
$verifiedToken = Str::random(60);
|
$verifiedToken = Str::random(60);
|
||||||
|
|
@ -123,7 +128,6 @@ public function verifyOtp(Request $request)
|
||||||
return redirect()->route('admin.password.reset-form')
|
return redirect()->route('admin.password.reset-form')
|
||||||
->with('success', 'Kode berhasil diverifikasi! Silakan buat password baru.');
|
->with('success', 'Kode berhasil diverifikasi! Silakan buat password baru.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────
|
||||||
// STEP 2 — Kirim ulang OTP
|
// STEP 2 — Kirim ulang OTP
|
||||||
// ─────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────
|
||||||
|
|
@ -182,6 +186,9 @@ public function showResetForm(Request $request)
|
||||||
// ─────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────
|
||||||
// STEP 3 — Proses: simpan password baru
|
// STEP 3 — Proses: simpan password baru
|
||||||
// ─────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────
|
||||||
|
// ─────────────────────────────────────────────────────────
|
||||||
|
// STEP 3 — Proses: simpan password baru
|
||||||
|
// ─────────────────────────────────────────────────────────
|
||||||
public function resetPassword(Request $request)
|
public function resetPassword(Request $request)
|
||||||
{
|
{
|
||||||
$request->validate([
|
$request->validate([
|
||||||
|
|
@ -209,6 +216,15 @@ public function resetPassword(Request $request)
|
||||||
->with('error', 'Token tidak valid. Silakan ulangi dari awal.');
|
->with('error', 'Token tidak valid. Silakan ulangi dari awal.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ✅ CEK PASSWORD LAMA — tolak jika sama dengan password sekarang
|
||||||
|
$admin = User::where('email', $email)->where('is_admin', true)->first();
|
||||||
|
|
||||||
|
if ($admin && Hash::check($request->password, $admin->password)) {
|
||||||
|
return back()->withErrors([
|
||||||
|
'password' => 'Password baru tidak boleh sama dengan password yang sedang digunakan.',
|
||||||
|
])->withInput();
|
||||||
|
}
|
||||||
|
|
||||||
User::where('email', $email)
|
User::where('email', $email)
|
||||||
->where('is_admin', true)
|
->where('is_admin', true)
|
||||||
->update(['password' => Hash::make($request->password)]);
|
->update(['password' => Hash::make($request->password)]);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
|
||||||
|
class FonnteService
|
||||||
|
{
|
||||||
|
public function sendOTP($nomor, $otp)
|
||||||
|
{
|
||||||
|
// Format nomor: 08xxx → 628xxx
|
||||||
|
$nomor = '62' . ltrim($nomor, '0');
|
||||||
|
|
||||||
|
$response = Http::withHeaders([
|
||||||
|
'Authorization' => env('FONNTE_TOKEN'),
|
||||||
|
])->post('https://api.fonnte.com/send', [
|
||||||
|
'target' => $nomor,
|
||||||
|
'message' => "Kode OTP reset password Anda: *$otp*\n\nBerlaku selama 10 menit. Jangan berikan kode ini kepada siapapun.",
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $response->json();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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()
|
||||||
|
{
|
||||||
|
Schema::table('users', function (Blueprint $table) {
|
||||||
|
$table->string('no_hp')->nullable()->after('email');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('users', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('no_hp');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -3,181 +3,544 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Pengajuan Pembatalan - Admin</title>
|
<title>Pengajuan Pembatalan - Bibit Cabai Admin</title>
|
||||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||||
|
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
body { font-family: 'Segoe UI', sans-serif; background: #f8f9fa; }
|
|
||||||
.admin-container { display: flex; min-height: 100vh; }
|
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--sidebar-width: 260px;
|
||||||
|
--green-dark: #15803d;
|
||||||
|
--green-main: #16a34a;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
|
background: #f1f5f2;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== SIDEBAR ===== */
|
||||||
.sidebar {
|
.sidebar {
|
||||||
width: 280px; background: linear-gradient(180deg, #28a745, #20c997);
|
width: var(--sidebar-width);
|
||||||
color: white; min-height: 100vh; position: fixed; top: 0; left: 0; z-index: 1000;
|
background: linear-gradient(180deg, var(--green-dark) 0%, #14532d 100%);
|
||||||
|
color: white;
|
||||||
|
min-height: 100vh;
|
||||||
|
position: fixed;
|
||||||
|
top: 0; left: 0;
|
||||||
|
z-index: 1050;
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
.sidebar-header { padding: 25px 20px; text-align: center; border-bottom: 1px solid rgba(255,255,255,0.1); }
|
|
||||||
.sidebar-header h3 { font-size: 1.8rem; font-weight: bold; margin-bottom: 5px; }
|
.sidebar-header {
|
||||||
.sidebar-header p { opacity: 0.8; font-size: 0.9rem; }
|
padding: 24px 20px 20px;
|
||||||
.sidebar-menu { padding: 20px 0; }
|
text-align: center;
|
||||||
|
border-bottom: 1px solid rgba(255,255,255,0.12);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-header .brand-icon { font-size: 2rem; margin-bottom: 6px; display: block; }
|
||||||
|
.sidebar-header h3 { font-size: 1.35rem; font-weight: 700; margin-bottom: 2px; }
|
||||||
|
.sidebar-header .subtitle { opacity: 0.65; font-size: 0.78rem; margin-bottom: 6px; }
|
||||||
|
.sidebar-header .admin-name {
|
||||||
|
display: inline-block;
|
||||||
|
background: rgba(255,255,255,0.15);
|
||||||
|
padding: 3px 12px;
|
||||||
|
border-radius: 20px;
|
||||||
|
font-size: 0.78rem;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-menu { padding: 12px 0; flex: 1; }
|
||||||
|
|
||||||
|
.menu-section-label {
|
||||||
|
font-size: 0.68rem;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
opacity: 0.45;
|
||||||
|
padding: 12px 20px 6px;
|
||||||
|
}
|
||||||
|
|
||||||
.menu-item {
|
.menu-item {
|
||||||
display: block; padding: 15px 25px; color: white;
|
display: flex;
|
||||||
text-decoration: none; transition: all 0.3s; border-left: 4px solid transparent;
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 12px 20px;
|
||||||
|
color: rgba(255,255,255,0.82);
|
||||||
|
text-decoration: none;
|
||||||
|
transition: all 0.2s;
|
||||||
|
border-left: 3px solid transparent;
|
||||||
|
font-size: 0.9rem;
|
||||||
}
|
}
|
||||||
.menu-item:hover, .menu-item.active {
|
|
||||||
background: rgba(255,255,255,0.2); color: white;
|
.menu-item i { width: 18px; font-size: 0.95rem; flex-shrink: 0; text-align: center; }
|
||||||
border-left-color: #fff; transform: translateX(5px);
|
|
||||||
|
.menu-item:hover {
|
||||||
|
background: rgba(255,255,255,0.1);
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
border-left-color: rgba(255,255,255,0.5);
|
||||||
}
|
}
|
||||||
.menu-item i { width: 20px; margin-right: 10px; }
|
|
||||||
|
|
||||||
.main-content { margin-left: 280px; flex: 1; }
|
.menu-item.active {
|
||||||
.admin-header {
|
background: rgba(255,255,255,0.15);
|
||||||
background: white; padding: 20px 30px;
|
color: white;
|
||||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1); border-bottom: 1px solid #dee2e6;
|
border-left-color: #fff;
|
||||||
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
.content-area { padding: 30px; }
|
|
||||||
|
|
||||||
.badge-status { padding: 4px 10px; border-radius: 12px; font-size: 0.75rem; font-weight: 600; }
|
.sidebar-footer {
|
||||||
.badge-pending { background: #fff3cd; color: #856404; }
|
padding: 16px 20px;
|
||||||
.badge-approved { background: #d4edda; color: #155724; }
|
border-top: 1px solid rgba(255,255,255,0.12);
|
||||||
.badge-rejected { background: #f8d7da; color: #721c24; }
|
flex-shrink: 0;
|
||||||
|
|
||||||
.card { border: none; border-radius: 12px; box-shadow: 0 4px 6px rgba(0,0,0,0.05); }
|
|
||||||
.card-header { background: white; border-bottom: 2px solid #f8f9fa; border-radius: 12px 12px 0 0 !important; }
|
|
||||||
|
|
||||||
.back-button {
|
|
||||||
position: fixed; top: 20px; right: 20px; z-index: 1100;
|
|
||||||
background: linear-gradient(45deg, #dc3545, #c82333);
|
|
||||||
color: white; border: none; padding: 12px 20px;
|
|
||||||
border-radius: 25px; font-weight: 600; text-decoration: none; transition: all 0.3s;
|
|
||||||
}
|
}
|
||||||
.back-button:hover { color: white; transform: translateY(-2px); }
|
|
||||||
|
|
||||||
.table th { background: #f8f9fa; font-weight: 600; color: #495057; font-size: 0.85rem; }
|
.btn-logout {
|
||||||
.table td { vertical-align: middle; }
|
width: 100%;
|
||||||
|
background: rgba(255,255,255,0.12);
|
||||||
|
color: white;
|
||||||
|
border: 1.5px solid rgba(255,255,255,0.3);
|
||||||
|
padding: 9px 16px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.action-btn { padding: 5px 12px; border-radius: 6px; font-size: 0.8rem; font-weight: 600; border: none; cursor: pointer; }
|
.btn-logout:hover {
|
||||||
.action-btn.btn-success { background-color: #28a745 !important; color: white !important; opacity: 1 !important; }
|
background: rgba(255,255,255,0.22);
|
||||||
.action-btn.btn-danger { background-color: #dc3545 !important; color: white !important; opacity: 1 !important; }
|
border-color: rgba(255,255,255,0.5);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-overlay {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
background: rgba(0,0,0,0.45);
|
||||||
|
z-index: 1040;
|
||||||
|
backdrop-filter: blur(2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-overlay.show { display: block; }
|
||||||
|
|
||||||
|
/* ===== MAIN CONTENT ===== */
|
||||||
|
.main-content {
|
||||||
|
margin-left: var(--sidebar-width);
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== TOPBAR ===== */
|
||||||
|
.topbar {
|
||||||
|
background: white;
|
||||||
|
height: 64px;
|
||||||
|
padding: 0 24px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
box-shadow: 0 1px 0 #e5e7eb;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topbar-left { display: flex; align-items: center; gap: 14px; }
|
||||||
|
|
||||||
|
.hamburger-btn {
|
||||||
|
display: none;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: #374151;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
padding: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 6px;
|
||||||
|
transition: background 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger-btn:hover { background: #f3f4f6; }
|
||||||
|
|
||||||
|
.topbar-breadcrumb { font-size: 0.8rem; color: #6b7280; margin-bottom: 2px; }
|
||||||
|
.topbar-breadcrumb a { color: var(--green-main); text-decoration: none; }
|
||||||
|
.topbar-title h2 { font-size: 1.1rem; font-weight: 700; color: #111827; margin: 0; }
|
||||||
|
.topbar-title p { font-size: 0.75rem; color: #6b7280; margin: 0; }
|
||||||
|
|
||||||
|
.btn-back-website {
|
||||||
|
background: linear-gradient(135deg, #dc2626, #b91c1c);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 9px 18px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.825rem;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 7px;
|
||||||
|
transition: all 0.2s;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-back-website:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 4px 12px rgba(220,38,38,0.35);
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== CONTENT AREA ===== */
|
||||||
|
.content-area { padding: 20px 24px 24px; flex: 1; }
|
||||||
|
|
||||||
|
/* ===== STATS GRID ===== */
|
||||||
|
.stats-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 16px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card {
|
||||||
|
background: white;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 18px 16px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.06), 0 4px 10px rgba(0,0,0,0.04);
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
border-left: 4px solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card.warning { border-left-color: #d97706; }
|
||||||
|
.stat-card.success { border-left-color: var(--green-main); }
|
||||||
|
.stat-card.danger { border-left-color: #dc2626; }
|
||||||
|
|
||||||
|
.stat-label {
|
||||||
|
font-size: 0.72rem;
|
||||||
|
font-weight: 700;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card.warning .stat-label { color: #d97706; }
|
||||||
|
.stat-card.success .stat-label { color: var(--green-main); }
|
||||||
|
.stat-card.danger .stat-label { color: #dc2626; }
|
||||||
|
|
||||||
|
.stat-value { font-size: 1.5rem; font-weight: 800; color: #111827; }
|
||||||
|
.stat-icon { font-size: 1.75rem; color: #e5e7eb; }
|
||||||
|
|
||||||
|
/* ===== TABLE CARD ===== */
|
||||||
|
.table-card {
|
||||||
|
background: white;
|
||||||
|
border-radius: 14px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.06), 0 4px 10px rgba(0,0,0,0.04);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-card-header {
|
||||||
|
padding: 18px 20px;
|
||||||
|
border-bottom: 1px solid #f3f4f6;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #111827;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== TABLE ===== */
|
||||||
|
.data-table { width: 100%; border-collapse: collapse; }
|
||||||
|
|
||||||
|
.data-table th, .data-table td {
|
||||||
|
padding: 11px 14px;
|
||||||
|
text-align: left;
|
||||||
|
border-bottom: 1px solid #f3f4f6;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table th {
|
||||||
|
background: #f9fafb;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #6b7280;
|
||||||
|
font-size: 0.78rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table tbody tr:hover { background: #f9fafb; }
|
||||||
|
|
||||||
|
/* ===== BADGES ===== */
|
||||||
|
.badge-status {
|
||||||
|
padding: 4px 10px;
|
||||||
|
border-radius: 12px;
|
||||||
|
font-size: 0.72rem;
|
||||||
|
font-weight: 600;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-pending { background: #fef3c7; color: #92400e; }
|
||||||
|
.badge-approved { background: #dcfce7; color: #166534; }
|
||||||
|
.badge-rejected { background: #fee2e2; color: #991b1b; }
|
||||||
|
|
||||||
|
/* ===== ACTION BUTTONS ===== */
|
||||||
|
.btn-action {
|
||||||
|
padding: 6px 12px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-approve { background: #16a34a; color: white; }
|
||||||
|
.btn-reject { background: #dc2626; color: white; }
|
||||||
|
.btn-label-approved { background: #dcfce7; color: #166534; cursor: default; }
|
||||||
|
.btn-label-rejected { background: #fee2e2; color: #991b1b; cursor: default; }
|
||||||
|
|
||||||
|
.btn-action:hover:not([style*="cursor:default"]) {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 2px 6px rgba(0,0,0,0.15);
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== TABLE FOOTER ===== */
|
||||||
|
.table-footer {
|
||||||
|
padding: 14px 20px;
|
||||||
|
border-top: 1px solid #f3f4f6;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== MOBILE CARDS ===== */
|
||||||
|
.mobile-card-list { display: none; }
|
||||||
|
|
||||||
|
.cancel-card {
|
||||||
|
background: white;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 16px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.06), 0 4px 10px rgba(0,0,0,0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cancel-card-top {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cancel-card-invoice { font-weight: 700; font-size: 0.9rem; color: #111827; }
|
||||||
|
.cancel-card-amount { font-size: 0.78rem; color: #9ca3af; margin-top: 2px; }
|
||||||
|
|
||||||
|
.cancel-card-meta {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cancel-card-meta-item .label { color: #9ca3af; font-size: 0.72rem; text-transform: uppercase; font-weight: 600; margin-bottom: 2px; }
|
||||||
|
.cancel-card-meta-item .value { color: #374151; }
|
||||||
|
|
||||||
|
.cancel-card-reason {
|
||||||
|
background: #f9fafb;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 10px 12px;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: #374151;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cancel-card-reason .reason-label { font-weight: 700; color: #6b7280; font-size: 0.72rem; text-transform: uppercase; margin-bottom: 4px; }
|
||||||
|
|
||||||
|
.cancel-card-actions { display: flex; gap: 8px; }
|
||||||
|
.cancel-card-actions .btn-action { flex: 1; justify-content: center; }
|
||||||
|
|
||||||
|
/* ===== FADE IN ===== */
|
||||||
|
.fade-in { animation: fadeIn 0.3s ease; }
|
||||||
|
|
||||||
|
@keyframes fadeIn {
|
||||||
|
from { opacity: 0; transform: translateY(8px); }
|
||||||
|
to { opacity: 1; transform: translateY(0); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== RESPONSIVE ===== */
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.sidebar { transform: translateX(-100%); }
|
||||||
|
.sidebar.open { transform: translateX(0); box-shadow: 4px 0 24px rgba(0,0,0,0.2); }
|
||||||
|
.main-content { margin-left: 0; }
|
||||||
|
.hamburger-btn { display: flex; align-items: center; justify-content: center; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
.desktop-table-wrap { display: none; }
|
||||||
|
.mobile-card-list { display: block; }
|
||||||
|
.stats-grid { grid-template-columns: 1fr 1fr; }
|
||||||
|
.stats-grid .stat-card:last-child { grid-column: span 2; }
|
||||||
|
.content-area { padding: 14px 14px 20px; }
|
||||||
|
.topbar { padding: 0 14px; }
|
||||||
|
.btn-back-website span { display: none; }
|
||||||
|
.btn-back-website { padding: 9px 12px; }
|
||||||
|
.table-footer { flex-direction: column; align-items: flex-start; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 400px) {
|
||||||
|
.stats-grid { grid-template-columns: 1fr; }
|
||||||
|
.stats-grid .stat-card:last-child { grid-column: span 1; }
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<a href="{{ route('home') }}" class="back-button">
|
<div class="sidebar-overlay" id="sidebarOverlay" onclick="closeSidebar()"></div>
|
||||||
<i class="fas fa-arrow-left me-2"></i>Kembali ke Website
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div class="admin-container">
|
<!-- Sidebar -->
|
||||||
{{-- Sidebar --}}
|
<nav class="sidebar" id="sidebar">
|
||||||
<nav class="sidebar">
|
|
||||||
<div class="sidebar-header">
|
<div class="sidebar-header">
|
||||||
<h3>🌱 Bibit Cabai</h3>
|
<span class="brand-icon">🌱</span>
|
||||||
<p>Admin Dashboard</p>
|
<h3>Bibit Cabai</h3>
|
||||||
<small class="text-light">{{ Auth::user()->name ?? 'Admin' }}</small>
|
<p class="subtitle">Admin Dashboard</p>
|
||||||
|
<span class="admin-name">{{ Auth::user()->name ?? 'Admin User' }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="sidebar-menu">
|
<div class="sidebar-menu">
|
||||||
|
<div class="menu-section-label">Menu Utama</div>
|
||||||
|
|
||||||
<a href="{{ route('admin.dashboard') }}" class="menu-item">
|
<a href="{{ route('admin.dashboard') }}" class="menu-item">
|
||||||
<i class="fas fa-tachometer-alt"></i>Dashboard
|
<i class="fas fa-tachometer-alt"></i><span>Dashboard</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('admin.products.index') }}" class="menu-item">
|
<a href="{{ route('admin.products.index') }}" class="menu-item">
|
||||||
<i class="fas fa-seedling"></i>Kelola Produk
|
<i class="fas fa-seedling"></i><span>Kelola Produk</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('admin.orders') }}" class="menu-item">
|
<a href="{{ route('admin.orders') }}" class="menu-item">
|
||||||
<i class="fas fa-shopping-cart"></i>Pesanan
|
<i class="fas fa-shopping-cart"></i><span>Pesanan</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('admin.cancellations') }}" class="menu-item active">
|
<a href="{{ route('admin.cancellations') }}" class="menu-item active">
|
||||||
<i class="fas fa-times-circle"></i>Pengajuan Batal
|
<i class="fas fa-times-circle"></i><span>Pengajuan Batal</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('admin.users') }}" class="menu-item">
|
<a href="{{ route('admin.users') }}" class="menu-item">
|
||||||
<i class="fas fa-users"></i>Pengguna
|
<i class="fas fa-users"></i><span>Pengguna</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('admin.laporan') }}" class="menu-item">
|
<a href="{{ route('admin.laporan') }}" class="menu-item">
|
||||||
<i class="fas fa-chart-line"></i>Laporan
|
<i class="fas fa-chart-line"></i><span>Laporan</span>
|
||||||
</a>
|
</a>
|
||||||
<!-- <a href="{{ route('admin.settings') }}" class="menu-item">
|
</div>
|
||||||
<i class="fas fa-cog"></i>Pengaturan
|
|
||||||
</a> -->
|
<div class="sidebar-footer">
|
||||||
<div class="mt-4 px-3">
|
|
||||||
<form method="POST" action="{{ route('admin.logout') }}">
|
<form method="POST" action="{{ route('admin.logout') }}">
|
||||||
@csrf
|
@csrf
|
||||||
<button type="submit" class="btn btn-outline-light btn-sm w-100">
|
<button type="submit" class="btn-logout">
|
||||||
<i class="fas fa-sign-out-alt me-2"></i>Logout
|
<i class="fas fa-sign-out-alt"></i><span>Logout</span>
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
{{-- Main Content --}}
|
<!-- Main Content -->
|
||||||
<div class="main-content">
|
<div class="main-content">
|
||||||
<div class="admin-header">
|
|
||||||
<nav aria-label="breadcrumb">
|
|
||||||
<ol class="breadcrumb mb-1">
|
|
||||||
<li class="breadcrumb-item"><a href="{{ route('admin.dashboard') }}">Dashboard</a></li>
|
|
||||||
<li class="breadcrumb-item active">Pengajuan Pembatalan</li>
|
|
||||||
</ol>
|
|
||||||
</nav>
|
|
||||||
<h2>Pengajuan Pembatalan Pesanan</h2>
|
|
||||||
<p class="mb-0">Kelola semua permintaan pembatalan dari pelanggan.</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="content-area">
|
<!-- Topbar -->
|
||||||
|
<header class="topbar">
|
||||||
|
<div class="topbar-left">
|
||||||
|
<button class="hamburger-btn" onclick="toggleSidebar()" aria-label="Toggle menu">
|
||||||
|
<i class="fas fa-bars"></i>
|
||||||
|
</button>
|
||||||
|
<div class="topbar-title">
|
||||||
|
<div class="topbar-breadcrumb">
|
||||||
|
<a href="{{ route('admin.dashboard') }}"><i class="fas fa-home"></i> Dashboard</a>
|
||||||
|
/ Pengajuan Pembatalan
|
||||||
|
</div>
|
||||||
|
<h2>Pengajuan Pembatalan Pesanan</h2>
|
||||||
|
<p>Kelola semua permintaan pembatalan dari pelanggan.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a href="{{ route('home') }}" class="btn-back-website">
|
||||||
|
<i class="fas fa-arrow-left"></i>
|
||||||
|
<span>Kembali ke Website</span>
|
||||||
|
</a>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<!-- Content -->
|
||||||
|
<div class="content-area fade-in">
|
||||||
|
|
||||||
@if(session('success'))
|
@if(session('success'))
|
||||||
<div class="alert alert-success alert-dismissible fade show">
|
<div class="alert alert-success alert-dismissible fade show mb-4" role="alert">
|
||||||
<i class="fas fa-check-circle me-2"></i>{{ session('success') }}
|
<i class="fas fa-check-circle me-2"></i>{{ session('success') }}
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
{{-- Stats --}}
|
<!-- Stats -->
|
||||||
<div class="row g-3 mb-4">
|
<div class="stats-grid">
|
||||||
<div class="col-md-4">
|
<div class="stat-card warning">
|
||||||
<div class="card p-3 border-start border-warning border-4">
|
|
||||||
<div class="d-flex justify-content-between align-items-center">
|
|
||||||
<div>
|
<div>
|
||||||
<div class="text-warning fw-bold small">MENUNGGU REVIEW</div>
|
<div class="stat-label">Menunggu Review</div>
|
||||||
<div class="fs-3 fw-bold">{{ $cancellations->where('status','pending')->count() }}</div>
|
<div class="stat-value">{{ $cancellations->where('status','pending')->count() }}</div>
|
||||||
</div>
|
</div>
|
||||||
<i class="fas fa-clock fa-2x text-muted"></i>
|
<div class="stat-icon"><i class="fas fa-clock"></i></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="stat-card success">
|
||||||
</div>
|
|
||||||
<div class="col-md-4">
|
|
||||||
<div class="card p-3 border-start border-success border-4">
|
|
||||||
<div class="d-flex justify-content-between align-items-center">
|
|
||||||
<div>
|
<div>
|
||||||
<div class="text-success fw-bold small">DISETUJUI</div>
|
<div class="stat-label">Disetujui</div>
|
||||||
<div class="fs-3 fw-bold">{{ $cancellations->where('status','approved')->count() }}</div>
|
<div class="stat-value">{{ $cancellations->where('status','approved')->count() }}</div>
|
||||||
</div>
|
</div>
|
||||||
<i class="fas fa-check-circle fa-2x text-muted"></i>
|
<div class="stat-icon"><i class="fas fa-check-circle"></i></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="stat-card danger">
|
||||||
</div>
|
|
||||||
<div class="col-md-4">
|
|
||||||
<div class="card p-3 border-start border-danger border-4">
|
|
||||||
<div class="d-flex justify-content-between align-items-center">
|
|
||||||
<div>
|
<div>
|
||||||
<div class="text-danger fw-bold small">DITOLAK</div>
|
<div class="stat-label">Ditolak</div>
|
||||||
<div class="fs-3 fw-bold">{{ $cancellations->where('status','rejected')->count() }}</div>
|
<div class="stat-value">{{ $cancellations->where('status','rejected')->count() }}</div>
|
||||||
</div>
|
|
||||||
<i class="fas fa-times-circle fa-2x text-muted"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="stat-icon"><i class="fas fa-times-circle"></i></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{-- Tabel --}}
|
<!-- Table Card -->
|
||||||
<div class="card">
|
<div class="table-card">
|
||||||
<div class="card-header py-3">
|
<div class="table-card-header">
|
||||||
<h6 class="mb-0 fw-bold text-success">
|
<div class="section-title">
|
||||||
<i class="fas fa-times-circle me-2"></i>
|
<i class="fas fa-times-circle text-success"></i>
|
||||||
Daftar Pengajuan Pembatalan ({{ $cancellations->total() }})
|
Daftar Pengajuan Pembatalan ({{ $cancellations->total() }})
|
||||||
</h6>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body p-0">
|
</div>
|
||||||
<div class="table-responsive">
|
|
||||||
<table class="table table-hover mb-0">
|
<!-- DESKTOP TABLE -->
|
||||||
|
<div class="desktop-table-wrap table-responsive">
|
||||||
|
<table class="data-table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="ps-3">Invoice</th>
|
<th class="ps-3">Invoice</th>
|
||||||
|
|
@ -193,68 +556,62 @@
|
||||||
@forelse($cancellations as $item)
|
@forelse($cancellations as $item)
|
||||||
<tr>
|
<tr>
|
||||||
<td class="ps-3">
|
<td class="ps-3">
|
||||||
<strong class="d-block">{{ $item->transaksi->invoice_number ?? '-' }}</strong>
|
<strong class="d-block" style="color:#111827;">{{ $item->transaksi->invoice_number ?? '-' }}</strong>
|
||||||
<small class="text-muted">
|
<small style="color:#9ca3af;">
|
||||||
Rp{{ number_format($item->transaksi->total_amount ?? 0, 0, ',', '.') }}
|
Rp{{ number_format($item->transaksi->total_amount ?? 0, 0, ',', '.') }}
|
||||||
</small>
|
</small>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<strong>{{ $item->user->name ?? '-' }}</strong><br>
|
<strong style="color:#111827;">{{ $item->user->name ?? '-' }}</strong><br>
|
||||||
<small class="text-muted">{{ $item->user->email ?? '-' }}</small>
|
<small style="color:#9ca3af;">{{ $item->user->email ?? '-' }}</small>
|
||||||
|
</td>
|
||||||
|
<td style="max-width:160px;">
|
||||||
|
<small style="color:#374151;">{{ $item->reason }}</small>
|
||||||
</td>
|
</td>
|
||||||
<td style="max-width:180px;">
|
<td style="max-width:180px;">
|
||||||
<small>{{ $item->reason }}</small>
|
<small style="color:#6b7280;">{{ $item->description ?? '-' }}</small>
|
||||||
</td>
|
|
||||||
<td style="max-width:200px;">
|
|
||||||
<small class="text-muted">{{ $item->description ?? '-' }}</small>
|
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<small>{{ $item->created_at->format('d M Y') }}</small><br>
|
<small style="color:#374151;">{{ $item->created_at->format('d M Y') }}</small><br>
|
||||||
<small class="text-muted">{{ $item->created_at->format('H:i') }}</small>
|
<small style="color:#9ca3af;">{{ $item->created_at->format('H:i') }}</small>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="badge-status badge-{{ $item->status }}">
|
<span class="badge-status badge-{{ $item->status }}">
|
||||||
{{ $item->status === 'pending' ? 'Menunggu' : ($item->status === 'approved' ? 'Disetujui' : 'Ditolak') }}
|
{{ $item->status === 'pending' ? 'Menunggu' : ($item->status === 'approved' ? 'Disetujui' : 'Ditolak') }}
|
||||||
</span>
|
</span>
|
||||||
@if($item->reviewed_at)
|
@if($item->reviewed_at)
|
||||||
<br><small class="text-muted">{{ $item->reviewed_at->format('d M Y') }}</small>
|
<br><small style="color:#9ca3af;">{{ $item->reviewed_at->format('d M Y') }}</small>
|
||||||
@endif
|
@endif
|
||||||
</td>
|
</td>
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
@if($item->status === 'pending')
|
@if($item->status === 'pending')
|
||||||
{{-- Tombol Setujui --}}
|
|
||||||
<form action="{{ route('admin.cancellations.approve', $item->id) }}" method="POST"
|
<form action="{{ route('admin.cancellations.approve', $item->id) }}" method="POST"
|
||||||
class="d-inline"
|
class="d-inline"
|
||||||
onsubmit="return confirm('Setujui pembatalan pesanan {{ $item->transaksi->invoice_number ?? '' }}?')">
|
onsubmit="return confirm('Setujui pembatalan pesanan {{ $item->transaksi->invoice_number ?? '' }}?')">
|
||||||
@csrf
|
@csrf
|
||||||
<textarea name="admin_note" style="display:none"> disetujui</textarea>
|
<textarea name="admin_note" style="display:none"> disetujui</textarea>
|
||||||
<button type="submit" class="action-btn btn-success text-white me-1">
|
<button type="submit" class="btn-action btn-approve me-1">
|
||||||
<i class="fas fa-check me-1"></i>Setujui
|
<i class="fas fa-check"></i>Setujui
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
<button type="button" class="btn-action btn-reject"
|
||||||
{{-- Tombol Tolak --}}
|
|
||||||
<button type="button"
|
|
||||||
class="action-btn btn-danger text-white"
|
|
||||||
onclick="showRejectModal({{ $item->id }}, '{{ $item->transaksi->invoice_number ?? '' }}')">
|
onclick="showRejectModal({{ $item->id }}, '{{ $item->transaksi->invoice_number ?? '' }}')">
|
||||||
<i class="fas fa-times me-1"></i>Tolak
|
<i class="fas fa-times"></i>Tolak
|
||||||
</button>
|
</button>
|
||||||
@else
|
@elseif($item->status === 'approved')
|
||||||
@if($item->status === 'approved')
|
<span class="btn-action btn-label-approved">Disetujui</span>
|
||||||
<span class="action-btn btn-success">Disetujui</span>
|
|
||||||
@elseif($item->status === 'rejected')
|
@elseif($item->status === 'rejected')
|
||||||
<span class="action-btn btn-danger">Ditolak</span>
|
<span class="btn-action btn-label-rejected">Ditolak</span>
|
||||||
@else
|
@else
|
||||||
<span class="text-muted">-</span>
|
<span style="color:#9ca3af;">-</span>
|
||||||
@endif
|
|
||||||
@endif
|
@endif
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@empty
|
@empty
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="7" class="text-center py-5">
|
<td colspan="7" style="text-align:center; padding:50px 20px; color:#9ca3af;">
|
||||||
<i class="fas fa-inbox fa-3x text-muted mb-3 d-block"></i>
|
<i class="fas fa-inbox" style="font-size:2.5rem; display:block; margin-bottom:12px; opacity:0.3;"></i>
|
||||||
<p class="text-muted">Belum ada pengajuan pembatalan</p>
|
Belum ada pengajuan pembatalan
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@endforelse
|
@endforelse
|
||||||
|
|
@ -262,28 +619,94 @@ class="action-btn btn-danger text-white"
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{-- Pagination --}}
|
<!-- MOBILE CARD LIST -->
|
||||||
|
<div class="mobile-card-list" style="padding:16px;">
|
||||||
|
@forelse($cancellations as $item)
|
||||||
|
<div class="cancel-card">
|
||||||
|
<div class="cancel-card-top">
|
||||||
|
<div>
|
||||||
|
<div class="cancel-card-invoice">{{ $item->transaksi->invoice_number ?? '-' }}</div>
|
||||||
|
<div class="cancel-card-amount">Rp{{ number_format($item->transaksi->total_amount ?? 0, 0, ',', '.') }}</div>
|
||||||
|
</div>
|
||||||
|
<span class="badge-status badge-{{ $item->status }}">
|
||||||
|
{{ $item->status === 'pending' ? 'Menunggu' : ($item->status === 'approved' ? 'Disetujui' : 'Ditolak') }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="cancel-card-meta">
|
||||||
|
<div class="cancel-card-meta-item">
|
||||||
|
<div class="label">Pelanggan</div>
|
||||||
|
<div class="value">{{ $item->user->name ?? '-' }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="cancel-card-meta-item">
|
||||||
|
<div class="label">Tanggal</div>
|
||||||
|
<div class="value">{{ $item->created_at->format('d M Y') }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="cancel-card-meta-item" style="grid-column:span 2;">
|
||||||
|
<div class="label">Email</div>
|
||||||
|
<div class="value">{{ $item->user->email ?? '-' }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="cancel-card-reason">
|
||||||
|
<div class="reason-label">Alasan</div>
|
||||||
|
{{ $item->reason }}
|
||||||
|
@if($item->description)
|
||||||
|
<div style="margin-top:6px; color:#6b7280; font-size:0.78rem;">{{ $item->description }}</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if($item->status === 'pending')
|
||||||
|
<div class="cancel-card-actions">
|
||||||
|
<form action="{{ route('admin.cancellations.approve', $item->id) }}" method="POST"
|
||||||
|
style="flex:1;"
|
||||||
|
onsubmit="return confirm('Setujui pembatalan pesanan {{ $item->transaksi->invoice_number ?? '' }}?')">
|
||||||
|
@csrf
|
||||||
|
<textarea name="admin_note" style="display:none"> disetujui</textarea>
|
||||||
|
<button type="submit" class="btn-action btn-approve" style="width:100%; justify-content:center;">
|
||||||
|
<i class="fas fa-check"></i>Setujui
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
<button type="button" class="btn-action btn-reject"
|
||||||
|
style="flex:1; justify-content:center;"
|
||||||
|
onclick="showRejectModal({{ $item->id }}, '{{ $item->transaksi->invoice_number ?? '' }}')">
|
||||||
|
<i class="fas fa-times"></i>Tolak
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
@elseif($item->status === 'approved')
|
||||||
|
<span class="btn-action btn-label-approved" style="width:100%; justify-content:center; display:flex;">Disetujui</span>
|
||||||
|
@elseif($item->status === 'rejected')
|
||||||
|
<span class="btn-action btn-label-rejected" style="width:100%; justify-content:center; display:flex;">Ditolak</span>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
@empty
|
||||||
|
<div style="text-align:center; padding:50px 20px; color:#9ca3af;">
|
||||||
|
<i class="fas fa-inbox" style="font-size:2.5rem; display:block; margin-bottom:12px; opacity:0.3;"></i>
|
||||||
|
Belum ada pengajuan pembatalan
|
||||||
|
</div>
|
||||||
|
@endforelse
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Pagination -->
|
||||||
@if($cancellations->hasPages())
|
@if($cancellations->hasPages())
|
||||||
<div class="d-flex justify-content-between align-items-center p-3 border-top">
|
<div class="table-footer">
|
||||||
<small class="text-muted">
|
<small style="color:#6b7280;">
|
||||||
Menampilkan {{ $cancellations->firstItem() }} - {{ $cancellations->lastItem() }}
|
Menampilkan {{ $cancellations->firstItem() }}–{{ $cancellations->lastItem() }}
|
||||||
dari {{ $cancellations->total() }} pengajuan
|
dari {{ $cancellations->total() }} pengajuan
|
||||||
</small>
|
</small>
|
||||||
{{ $cancellations->links() }}
|
<div>{{ $cancellations->links() }}</div>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
{{-- Modal Tolak --}}
|
<!-- Modal Tolak -->
|
||||||
<div class="modal fade" id="rejectModal" tabindex="-1" aria-hidden="true">
|
<div class="modal fade" id="rejectModal" tabindex="-1" aria-hidden="true">
|
||||||
<div class="modal-dialog modal-dialog-centered" style="max-width:420px;">
|
<div class="modal-dialog modal-dialog-centered" style="max-width:420px;">
|
||||||
<div class="modal-content border-0" style="border-radius:14px; overflow:hidden;">
|
<div class="modal-content border-0" style="border-radius:14px; overflow:hidden;">
|
||||||
<div class="modal-header bg-danger text-white">
|
<div class="modal-header bg-danger text-white border-0">
|
||||||
<h6 class="modal-title fw-bold mb-0">
|
<h6 class="modal-title fw-bold mb-0">
|
||||||
<i class="fas fa-times-circle me-2"></i>Tolak Pengajuan
|
<i class="fas fa-times-circle me-2"></i>Tolak Pengajuan
|
||||||
</h6>
|
</h6>
|
||||||
|
|
@ -292,8 +715,8 @@ class="action-btn btn-danger text-white"
|
||||||
<form id="rejectForm" method="POST">
|
<form id="rejectForm" method="POST">
|
||||||
@csrf
|
@csrf
|
||||||
<div class="modal-body p-4">
|
<div class="modal-body p-4">
|
||||||
<p class="mb-3">Pesanan: <strong id="rejectInvoice"></strong></p>
|
<p class="mb-3" style="font-size:0.9rem;">Pesanan: <strong id="rejectInvoice"></strong></p>
|
||||||
<label class="form-label fw-semibold">
|
<label class="form-label fw-semibold" style="font-size:0.875rem;">
|
||||||
Alasan Penolakan <span class="text-danger">*</span>
|
Alasan Penolakan <span class="text-danger">*</span>
|
||||||
</label>
|
</label>
|
||||||
<textarea name="admin_note" class="form-control" rows="3"
|
<textarea name="admin_note" class="form-control" rows="3"
|
||||||
|
|
@ -314,12 +737,31 @@ class="action-btn btn-danger text-white"
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
|
function toggleSidebar() {
|
||||||
|
const sidebar = document.getElementById('sidebar');
|
||||||
|
const overlay = document.getElementById('sidebarOverlay');
|
||||||
|
sidebar.classList.toggle('open');
|
||||||
|
overlay.classList.toggle('show');
|
||||||
|
document.body.style.overflow = sidebar.classList.contains('open') ? 'hidden' : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeSidebar() {
|
||||||
|
const sidebar = document.getElementById('sidebar');
|
||||||
|
const overlay = document.getElementById('sidebarOverlay');
|
||||||
|
sidebar.classList.remove('open');
|
||||||
|
overlay.classList.remove('show');
|
||||||
|
document.body.style.overflow = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('resize', function() {
|
||||||
|
if (window.innerWidth > 900) closeSidebar();
|
||||||
|
});
|
||||||
|
|
||||||
function showRejectModal(id, invoice) {
|
function showRejectModal(id, invoice) {
|
||||||
document.getElementById('rejectInvoice').textContent = invoice;
|
document.getElementById('rejectInvoice').textContent = invoice;
|
||||||
document.getElementById('rejectForm').action = `/admin/cancellations/${id}/reject`;
|
document.getElementById('rejectForm').action = `/admin/cancellations/${id}/reject`;
|
||||||
new bootstrap.Modal(document.getElementById('rejectModal')).show();
|
new bootstrap.Modal(document.getElementById('rejectModal')).show();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
@ -10,143 +10,551 @@
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: #f8f9fa; }
|
|
||||||
.admin-container { display: flex; min-height: 100vh; }
|
|
||||||
|
|
||||||
/* Sidebar */
|
:root {
|
||||||
.sidebar { width: 280px; background: linear-gradient(180deg, #28a745, #20c997); color: white; min-height: 100vh; position: fixed; top: 0; left: 0; z-index: 1000; transition: all 0.3s ease; }
|
--sidebar-width: 260px;
|
||||||
.sidebar-header { padding: 25px 20px; text-align: center; border-bottom: 1px solid rgba(255,255,255,0.1); }
|
--header-height: 64px;
|
||||||
.sidebar-header h3 { font-size: 1.8rem; font-weight: bold; margin-bottom: 5px; }
|
--green-dark: #15803d;
|
||||||
.sidebar-header p { opacity: 0.8; font-size: 0.9rem; }
|
--green-main: #16a34a;
|
||||||
.sidebar-menu { padding: 20px 0; }
|
--green-light: #22c55e;
|
||||||
.menu-item { display: block; padding: 15px 25px; color: white; text-decoration: none; transition: all 0.3s; border-left: 4px solid transparent; cursor: pointer; }
|
}
|
||||||
.menu-item:hover, .menu-item.active { background: rgba(255,255,255,0.1); color: white; text-decoration: none; border-left-color: #fff; transform: translateX(5px); }
|
|
||||||
.menu-item i { width: 20px; margin-right: 10px; }
|
|
||||||
|
|
||||||
/* Main Content */
|
body {
|
||||||
.main-content { margin-left: 280px; flex: 1; min-height: 100vh; }
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
.admin-header { background: white; padding: 20px 30px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); border-bottom: 1px solid #dee2e6; }
|
background: #f1f5f2;
|
||||||
.content-area { padding: 30px; }
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
/* Stats Cards */
|
/* ===== SIDEBAR ===== */
|
||||||
.stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 25px; margin-bottom: 40px; }
|
.sidebar {
|
||||||
.stat-card { background: white; padding: 25px; border-radius: 12px; box-shadow: 0 4px 6px rgba(0,0,0,0.05); border-left: 5px solid; transition: transform 0.3s ease; }
|
width: var(--sidebar-width);
|
||||||
.stat-card:hover { transform: translateY(-5px); }
|
background: linear-gradient(180deg, var(--green-dark) 0%, #14532d 100%);
|
||||||
.stat-card.products { border-left-color: #28a745; }
|
color: white;
|
||||||
.stat-card.orders { border-left-color: #007bff; }
|
min-height: 100vh;
|
||||||
.stat-card.revenue { border-left-color: #ffc107; }
|
position: fixed;
|
||||||
.stat-card.users { border-left-color: #6f42c1; }
|
top: 0;
|
||||||
.stat-number { font-size: 2.5rem; font-weight: bold; margin-bottom: 8px; }
|
left: 0;
|
||||||
.stat-label { color: #6c757d; font-size: 1rem; font-weight: 500; }
|
z-index: 1050;
|
||||||
.stat-icon { float: right; font-size: 2.5rem; opacity: 0.3; margin-top: -10px; }
|
transition: transform 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
/* Back Button */
|
.sidebar-header {
|
||||||
.back-button { position: fixed; top: 20px; right: 20px; z-index: 1100; background: linear-gradient(45deg, #dc3545, #c82333); color: white; border: none; padding: 12px 20px; border-radius: 25px; font-weight: 600; transition: all 0.3s ease; text-decoration: none; }
|
padding: 24px 20px 20px;
|
||||||
.back-button:hover { background: linear-gradient(45deg, #c82333, #a71e2a); transform: translateY(-2px); color: white; text-decoration: none; }
|
text-align: center;
|
||||||
|
border-bottom: 1px solid rgba(255,255,255,0.12);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Chart Card Header */
|
.sidebar-header .brand-icon {
|
||||||
.chart-card-header {
|
font-size: 2rem;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-header h3 {
|
||||||
|
font-size: 1.35rem;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
letter-spacing: -0.3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-header .subtitle {
|
||||||
|
opacity: 0.65;
|
||||||
|
font-size: 0.78rem;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-header .admin-name {
|
||||||
|
display: inline-block;
|
||||||
|
background: rgba(255,255,255,0.15);
|
||||||
|
padding: 3px 12px;
|
||||||
|
border-radius: 20px;
|
||||||
|
font-size: 0.78rem;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-menu {
|
||||||
|
padding: 12px 0;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-section-label {
|
||||||
|
font-size: 0.68rem;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
opacity: 0.45;
|
||||||
|
padding: 12px 20px 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 12px 20px;
|
||||||
|
color: rgba(255,255,255,0.82);
|
||||||
|
text-decoration: none;
|
||||||
|
transition: all 0.2s;
|
||||||
|
border-left: 3px solid transparent;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-item i {
|
||||||
|
width: 18px;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-item:hover {
|
||||||
|
background: rgba(255,255,255,0.1);
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
border-left-color: rgba(255,255,255,0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-item.active {
|
||||||
|
background: rgba(255,255,255,0.15);
|
||||||
|
color: white;
|
||||||
|
border-left-color: #fff;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-footer {
|
||||||
|
padding: 16px 20px;
|
||||||
|
border-top: 1px solid rgba(255,255,255,0.12);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-logout {
|
||||||
|
width: 100%;
|
||||||
|
background: rgba(255,255,255,0.12);
|
||||||
|
color: white;
|
||||||
|
border: 1.5px solid rgba(255,255,255,0.3);
|
||||||
|
padding: 9px 16px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-logout:hover {
|
||||||
|
background: rgba(255,255,255,0.22);
|
||||||
|
border-color: rgba(255,255,255,0.5);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sidebar Overlay (mobile) */
|
||||||
|
.sidebar-overlay {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
background: rgba(0,0,0,0.45);
|
||||||
|
z-index: 1040;
|
||||||
|
backdrop-filter: blur(2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-overlay.show { display: block; }
|
||||||
|
|
||||||
|
/* ===== MAIN CONTENT ===== */
|
||||||
|
.main-content {
|
||||||
|
margin-left: var(--sidebar-width);
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== TOPBAR ===== */
|
||||||
|
.topbar {
|
||||||
|
background: white;
|
||||||
|
height: var(--header-height);
|
||||||
|
padding: 0 24px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
flex-wrap: wrap;
|
box-shadow: 0 1px 0 #e5e7eb;
|
||||||
gap: 10px;
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topbar-left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger-btn {
|
||||||
|
display: none;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: #374151;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
padding: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 6px;
|
||||||
|
transition: background 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger-btn:hover { background: #f3f4f6; }
|
||||||
|
|
||||||
|
.topbar-title h2 {
|
||||||
|
font-size: 1.15rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #111827;
|
||||||
|
margin: 0;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topbar-title p {
|
||||||
|
font-size: 0.78rem;
|
||||||
|
color: #6b7280;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-back-website {
|
||||||
|
background: linear-gradient(135deg, #dc2626, #b91c1c);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 9px 18px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.825rem;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 7px;
|
||||||
|
transition: all 0.2s;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-back-website:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 4px 12px rgba(220,38,38,0.35);
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== CONTENT AREA ===== */
|
||||||
|
.content-area {
|
||||||
|
padding: 24px;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== STATS GRID ===== */
|
||||||
|
.stats-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
gap: 20px;
|
||||||
|
margin-bottom: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card {
|
||||||
|
background: white;
|
||||||
|
padding: 22px 20px;
|
||||||
|
border-radius: 14px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.06), 0 4px 12px rgba(0,0,0,0.04);
|
||||||
|
border-left: 4px solid;
|
||||||
|
transition: transform 0.25s ease, box-shadow 0.25s ease;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card:hover {
|
||||||
|
transform: translateY(-4px);
|
||||||
|
box-shadow: 0 8px 24px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card.products { border-left-color: #16a34a; }
|
||||||
|
.stat-card.orders { border-left-color: #2563eb; }
|
||||||
|
.stat-card.revenue { border-left-color: #d97706; }
|
||||||
|
.stat-card.users { border-left-color: #7c3aed; }
|
||||||
|
|
||||||
|
.stat-number {
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: 800;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
line-height: 1;
|
||||||
|
letter-spacing: -0.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-label {
|
||||||
|
color: #6b7280;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-icon {
|
||||||
|
position: absolute;
|
||||||
|
top: 18px;
|
||||||
|
right: 18px;
|
||||||
|
font-size: 2rem;
|
||||||
|
opacity: 0.12;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== CHART CARD ===== */
|
||||||
|
.chart-card {
|
||||||
|
background: white;
|
||||||
|
border-radius: 14px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.06), 0 4px 12px rgba(0,0,0,0.04);
|
||||||
|
overflow: hidden;
|
||||||
|
margin-bottom: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-card-header {
|
||||||
|
background: linear-gradient(135deg, var(--green-main), var(--green-light));
|
||||||
|
padding: 16px 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-card-header h5 {
|
||||||
|
color: white;
|
||||||
|
font-size: 0.975rem;
|
||||||
|
font-weight: 700;
|
||||||
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Lihat Detail Button */
|
|
||||||
.btn-lihat-detail {
|
.btn-lihat-detail {
|
||||||
background: rgba(255,255,255,0.2);
|
background: rgba(255,255,255,0.2);
|
||||||
color: white;
|
color: white;
|
||||||
border: 2px solid rgba(255,255,255,0.6);
|
border: 1.5px solid rgba(255,255,255,0.55);
|
||||||
padding: 7px 18px;
|
padding: 6px 16px;
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
font-size: 0.85rem;
|
font-size: 0.8rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.2s;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-lihat-detail:hover {
|
.btn-lihat-detail:hover {
|
||||||
background: white;
|
background: white;
|
||||||
color: #28a745;
|
color: var(--green-main);
|
||||||
border-color: white;
|
border-color: white;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
transform: translateY(-2px);
|
transform: translateY(-1px);
|
||||||
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
box-shadow: 0 4px 10px rgba(0,0,0,0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-card-body {
|
||||||
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Empty State */
|
/* Empty State */
|
||||||
.empty-state { text-align: center; padding: 60px 20px; color: #6c757d; }
|
.empty-state {
|
||||||
.empty-state i { font-size: 4rem; margin-bottom: 20px; opacity: 0.3; }
|
text-align: center;
|
||||||
.empty-state h4 { font-size: 1.5rem; margin-bottom: 10px; }
|
padding: 48px 20px;
|
||||||
.empty-state p { font-size: 1rem; margin-bottom: 20px; }
|
color: #9ca3af;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
.empty-state i { font-size: 3rem; margin-bottom: 16px; opacity: 0.35; display: block; }
|
||||||
.sidebar { width: 100%; position: relative; min-height: auto; }
|
.empty-state h4 { font-size: 1.1rem; color: #6b7280; margin-bottom: 8px; }
|
||||||
.main-content { margin-left: 0; }
|
.empty-state p { font-size: 0.875rem; margin-bottom: 16px; }
|
||||||
.stats-grid { grid-template-columns: 1fr; }
|
|
||||||
|
.btn-buka-laporan {
|
||||||
|
background: var(--green-main);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 9px 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 600;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 7px;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-buka-laporan:hover {
|
||||||
|
background: var(--green-dark);
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== RESPONSIVE ===== */
|
||||||
|
|
||||||
|
/* Large tablets & small desktops */
|
||||||
|
@media (max-width: 1100px) {
|
||||||
|
.stats-grid {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tablets (sidebar collapses) */
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.sidebar {
|
||||||
|
transform: translateX(-100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar.open {
|
||||||
|
transform: translateX(0);
|
||||||
|
box-shadow: 4px 0 24px rgba(0,0,0,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-content {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mobile phones */
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
.stats-grid {
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card {
|
||||||
|
padding: 16px 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-number {
|
||||||
|
font-size: 1.6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-label {
|
||||||
|
font-size: 0.78rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-icon {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-area {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topbar {
|
||||||
|
padding: 0 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-back-website span {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-back-website {
|
||||||
|
padding: 9px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-card-header h5 {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 380px) {
|
||||||
|
.stats-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<a href="{{ route('home') }}" class="back-button">
|
|
||||||
<i class="fas fa-arrow-left me-2"></i>Kembali ke Website
|
<!-- Sidebar Overlay (mobile) -->
|
||||||
|
<div class="sidebar-overlay" id="sidebarOverlay" onclick="closeSidebar()"></div>
|
||||||
|
|
||||||
|
<!-- Sidebar -->
|
||||||
|
<nav class="sidebar" id="sidebar">
|
||||||
|
<div class="sidebar-header">
|
||||||
|
<span class="brand-icon">🌱</span>
|
||||||
|
<h3>Bibit Cabai</h3>
|
||||||
|
<p class="subtitle">Admin Dashboard</p>
|
||||||
|
<span class="admin-name">{{ Auth::user()->name ?? 'Admin User' }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sidebar-menu">
|
||||||
|
<div class="menu-section-label">Menu Utama</div>
|
||||||
|
|
||||||
|
<a href="{{ route('admin.dashboard') }}" class="menu-item {{ request()->routeIs('admin.dashboard') ? 'active' : '' }}">
|
||||||
|
<i class="fas fa-tachometer-alt"></i>
|
||||||
|
<span>Dashboard</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div class="admin-container">
|
|
||||||
<!-- Sidebar -->
|
|
||||||
<nav class="sidebar">
|
|
||||||
<div class="sidebar-header">
|
|
||||||
<h3>🌱 Bibit Cabai</h3>
|
|
||||||
<p>Admin Dashboard</p>
|
|
||||||
<small class="text-light">{{ Auth::user()->name ?? 'Admin User' }}</small>
|
|
||||||
</div>
|
|
||||||
<div class="sidebar-menu">
|
|
||||||
<a href="{{ route('admin.dashboard') }}" class="menu-item {{ request()->routeIs('admin.dashboard') ? 'active' : '' }}">
|
|
||||||
<i class="fas fa-tachometer-alt"></i>Dashboard
|
|
||||||
</a>
|
|
||||||
<a href="{{ route('admin.products.index') }}" class="menu-item {{ request()->routeIs('admin.products.*') ? 'active' : '' }}">
|
<a href="{{ route('admin.products.index') }}" class="menu-item {{ request()->routeIs('admin.products.*') ? 'active' : '' }}">
|
||||||
<i class="fas fa-seedling"></i>Kelola Produk
|
<i class="fas fa-seedling"></i>
|
||||||
|
<span>Kelola Produk</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="{{ route('admin.orders') }}" class="menu-item {{ request()->routeIs('admin.orders') ? 'active' : '' }}">
|
<a href="{{ route('admin.orders') }}" class="menu-item {{ request()->routeIs('admin.orders') ? 'active' : '' }}">
|
||||||
<i class="fas fa-shopping-cart"></i>Pesanan
|
<i class="fas fa-shopping-cart"></i>
|
||||||
|
<span>Pesanan</span>
|
||||||
</a>
|
</a>
|
||||||
{{-- ↓ TAMBAHKAN DI SINI ↓ --}}
|
|
||||||
<a href="{{ route('admin.cancellations') }}" class="menu-item">
|
<a href="{{ route('admin.cancellations') }}" class="menu-item {{ request()->routeIs('admin.cancellations') ? 'active' : '' }}">
|
||||||
<i class="fas fa-times-circle"></i>Pengajuan Batal
|
<i class="fas fa-times-circle"></i>
|
||||||
|
<span>Pengajuan Batal</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="{{ route('admin.users') }}" class="menu-item {{ request()->routeIs('admin.users') ? 'active' : '' }}">
|
<a href="{{ route('admin.users') }}" class="menu-item {{ request()->routeIs('admin.users') ? 'active' : '' }}">
|
||||||
<i class="fas fa-users"></i>Pengguna
|
<i class="fas fa-users"></i>
|
||||||
|
<span>Pengguna</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="{{ route('admin.laporan') }}" class="menu-item {{ request()->routeIs('admin.laporan') ? 'active' : '' }}">
|
<a href="{{ route('admin.laporan') }}" class="menu-item {{ request()->routeIs('admin.laporan') ? 'active' : '' }}">
|
||||||
<i class="fas fa-chart-line"></i>Laporan
|
<i class="fas fa-chart-line"></i>
|
||||||
|
<span>Laporan</span>
|
||||||
</a>
|
</a>
|
||||||
<!-- <a href="{{ route('admin.settings') }}" class="menu-item {{ request()->routeIs('admin.settings') ? 'active' : '' }}">
|
</div>
|
||||||
<i class="fas fa-cog"></i>Pengaturan
|
|
||||||
</a> -->
|
<div class="sidebar-footer">
|
||||||
<div class="mt-4 px-3">
|
|
||||||
<form method="POST" action="{{ route('admin.logout') }}">
|
<form method="POST" action="{{ route('admin.logout') }}">
|
||||||
@csrf
|
@csrf
|
||||||
<button type="submit" class="btn btn-outline-light btn-sm w-100" onclick="return confirm('Apakah Anda yakin ingin logout?')">
|
<button type="submit" class="btn-logout" onclick="return confirm('Apakah Anda yakin ingin logout?')">
|
||||||
<i class="fas fa-sign-out-alt me-2"></i>Logout
|
<i class="fas fa-sign-out-alt"></i>
|
||||||
|
<span>Logout</span>
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<!-- Main Content -->
|
<!-- Main Content -->
|
||||||
<div class="main-content">
|
<div class="main-content" id="mainContent">
|
||||||
<div class="admin-header">
|
|
||||||
<h2>Dashboard</h2>
|
|
||||||
<p class="mb-0">Selamat datang di dashboard admin!</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<!-- Topbar -->
|
||||||
|
<header class="topbar">
|
||||||
|
<div class="topbar-left">
|
||||||
|
<button class="hamburger-btn" id="hamburgerBtn" onclick="toggleSidebar()" aria-label="Toggle menu">
|
||||||
|
<i class="fas fa-bars"></i>
|
||||||
|
</button>
|
||||||
|
<div class="topbar-title">
|
||||||
|
<h2>Dashboard</h2>
|
||||||
|
<p>Selamat datang di dashboard admin!</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a href="{{ route('home') }}" class="btn-back-website">
|
||||||
|
<i class="fas fa-arrow-left"></i>
|
||||||
|
<span>Kembali ke Website</span>
|
||||||
|
</a>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<!-- Content -->
|
||||||
<div class="content-area">
|
<div class="content-area">
|
||||||
|
|
||||||
|
<!-- Stats Grid -->
|
||||||
<div class="stats-grid">
|
<div class="stats-grid">
|
||||||
<div class="stat-card products">
|
<div class="stat-card products">
|
||||||
<div class="stat-number text-success">{{ $stats['total_products'] }}</div>
|
<div class="stat-number text-success">{{ $stats['total_products'] }}</div>
|
||||||
|
|
@ -170,19 +578,15 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<!-- Chart Card -->
|
||||||
<div class="col-12 mb-4">
|
<div class="chart-card">
|
||||||
<div class="card">
|
|
||||||
<div class="card-header bg-success text-white">
|
|
||||||
<div class="chart-card-header">
|
<div class="chart-card-header">
|
||||||
<h5 class="mb-0">📈 Grafik Pendapatan Harian (30 Hari Terakhir)</h5>
|
<h5>📈 Grafik Pendapatan Harian (30 Hari Terakhir)</h5>
|
||||||
{{-- Tombol Lihat Detail → mengarah ke halaman laporan --}}
|
|
||||||
<a href="{{ route('admin.laporan') }}" class="btn-lihat-detail">
|
<a href="{{ route('admin.laporan') }}" class="btn-lihat-detail">
|
||||||
<i class="fas fa-external-link-alt"></i> Lihat Detail
|
<i class="fas fa-external-link-alt"></i> Lihat Detail
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="chart-card-body">
|
||||||
<div class="card-body">
|
|
||||||
@if(count($chartLabels) > 0)
|
@if(count($chartLabels) > 0)
|
||||||
<canvas id="salesChart" height="80"></canvas>
|
<canvas id="salesChart" height="80"></canvas>
|
||||||
@else
|
@else
|
||||||
|
|
@ -190,39 +594,46 @@
|
||||||
<i class="fas fa-chart-line"></i>
|
<i class="fas fa-chart-line"></i>
|
||||||
<h4>Belum Ada Data</h4>
|
<h4>Belum Ada Data</h4>
|
||||||
<p>Grafik pendapatan akan ditampilkan setelah ada transaksi</p>
|
<p>Grafik pendapatan akan ditampilkan setelah ada transaksi</p>
|
||||||
<a href="{{ route('admin.laporan') }}" class="btn btn-success">
|
<a href="{{ route('admin.laporan') }}" class="btn-buka-laporan">
|
||||||
<i class="fas fa-chart-bar me-2"></i>Buka Laporan
|
<i class="fas fa-chart-bar"></i>Buka Laporan
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- <div class="row">
|
</div><!-- /content-area -->
|
||||||
<div class="col-md-6 mb-4">
|
</div><!-- /main-content -->
|
||||||
<div class="card">
|
|
||||||
<div class="card-header bg-info text-white">
|
|
||||||
<h5 class="mb-0">⚡ Aktivitas Terbaru</h5>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="empty-state">
|
|
||||||
<i class="fas fa-clock"></i>
|
|
||||||
<h4>Belum Ada Aktivitas</h4>
|
|
||||||
<p>Aktivitas terbaru akan ditampilkan di sini</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div> -->
|
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
// Sidebar toggle
|
||||||
|
function toggleSidebar() {
|
||||||
|
const sidebar = document.getElementById('sidebar');
|
||||||
|
const overlay = document.getElementById('sidebarOverlay');
|
||||||
|
sidebar.classList.toggle('open');
|
||||||
|
overlay.classList.toggle('show');
|
||||||
|
document.body.style.overflow = sidebar.classList.contains('open') ? 'hidden' : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeSidebar() {
|
||||||
|
const sidebar = document.getElementById('sidebar');
|
||||||
|
const overlay = document.getElementById('sidebarOverlay');
|
||||||
|
sidebar.classList.remove('open');
|
||||||
|
overlay.classList.remove('show');
|
||||||
|
document.body.style.overflow = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close sidebar on resize if desktop
|
||||||
|
window.addEventListener('resize', function() {
|
||||||
|
if (window.innerWidth > 900) {
|
||||||
|
closeSidebar();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Chart
|
||||||
@if(count($chartLabels) > 0)
|
@if(count($chartLabels) > 0)
|
||||||
const ctx = document.getElementById('salesChart').getContext('2d');
|
const ctx = document.getElementById('salesChart').getContext('2d');
|
||||||
new Chart(ctx, {
|
new Chart(ctx, {
|
||||||
|
|
@ -232,11 +643,12 @@
|
||||||
datasets: [{
|
datasets: [{
|
||||||
label: 'Penjualan (Rp)',
|
label: 'Penjualan (Rp)',
|
||||||
data: {!! json_encode($chartData) !!},
|
data: {!! json_encode($chartData) !!},
|
||||||
borderColor: '#28a745',
|
borderColor: '#16a34a',
|
||||||
backgroundColor: 'rgba(40, 167, 69, 0.1)',
|
backgroundColor: 'rgba(22, 163, 74, 0.08)',
|
||||||
borderWidth: 2,
|
borderWidth: 2.5,
|
||||||
pointBackgroundColor: '#28a745',
|
pointBackgroundColor: '#16a34a',
|
||||||
pointRadius: 4,
|
pointRadius: 4,
|
||||||
|
pointHoverRadius: 6,
|
||||||
tension: 0.4,
|
tension: 0.4,
|
||||||
fill: true
|
fill: true
|
||||||
}]
|
}]
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -6,175 +6,330 @@
|
||||||
<title>Orders Management - Bibit Cabai Admin</title>
|
<title>Orders Management - Bibit Cabai Admin</title>
|
||||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||||
|
|
||||||
<!-- Bootstrap CSS -->
|
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
|
||||||
<!-- Font Awesome -->
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--sidebar-width: 260px;
|
||||||
|
--green-dark: #15803d;
|
||||||
|
--green-main: #16a34a;
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
background: #f8f9fa;
|
background: #f1f5f2;
|
||||||
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.admin-container {
|
/* ===== SIDEBAR ===== */
|
||||||
display: flex;
|
|
||||||
min-height: 100vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sidebar */
|
|
||||||
.sidebar {
|
.sidebar {
|
||||||
width: 280px;
|
width: var(--sidebar-width);
|
||||||
background: linear-gradient(180deg, #28a745, #20c997);
|
background: linear-gradient(180deg, var(--green-dark) 0%, #14532d 100%);
|
||||||
color: white;
|
color: white;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
z-index: 1000;
|
z-index: 1050;
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-header {
|
.sidebar-header {
|
||||||
padding: 25px 20px;
|
padding: 24px 20px 20px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border-bottom: 1px solid rgba(255,255,255,0.1);
|
border-bottom: 1px solid rgba(255,255,255,0.12);
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-header h3 {
|
.sidebar-header .brand-icon { font-size: 2rem; margin-bottom: 6px; display: block; }
|
||||||
font-size: 1.8rem;
|
.sidebar-header h3 { font-size: 1.35rem; font-weight: 700; margin-bottom: 2px; }
|
||||||
font-weight: bold;
|
.sidebar-header .subtitle { opacity: 0.65; font-size: 0.78rem; margin-bottom: 6px; }
|
||||||
margin-bottom: 5px;
|
.sidebar-header .admin-name {
|
||||||
|
display: inline-block;
|
||||||
|
background: rgba(255,255,255,0.15);
|
||||||
|
padding: 3px 12px;
|
||||||
|
border-radius: 20px;
|
||||||
|
font-size: 0.78rem;
|
||||||
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-header p { opacity: 0.8; font-size: 0.9rem; }
|
.sidebar-menu { padding: 12px 0; flex: 1; }
|
||||||
|
|
||||||
.sidebar-menu { padding: 20px 0; }
|
.menu-section-label {
|
||||||
|
font-size: 0.68rem;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
opacity: 0.45;
|
||||||
|
padding: 12px 20px 6px;
|
||||||
|
}
|
||||||
|
|
||||||
.menu-item {
|
.menu-item {
|
||||||
display: block;
|
display: flex;
|
||||||
padding: 15px 25px;
|
align-items: center;
|
||||||
color: white;
|
gap: 12px;
|
||||||
|
padding: 12px 20px;
|
||||||
|
color: rgba(255,255,255,0.82);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
transition: all 0.3s;
|
transition: all 0.2s;
|
||||||
border-left: 4px solid transparent;
|
border-left: 3px solid transparent;
|
||||||
|
font-size: 0.9rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-item:hover, .menu-item.active {
|
.menu-item i { width: 18px; font-size: 0.95rem; flex-shrink: 0; text-align: center; }
|
||||||
background: rgba(255,255,255,0.2);
|
|
||||||
|
.menu-item:hover {
|
||||||
|
background: rgba(255,255,255,0.1);
|
||||||
color: white;
|
color: white;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
border-left-color: rgba(255,255,255,0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-item.active {
|
||||||
|
background: rgba(255,255,255,0.15);
|
||||||
|
color: white;
|
||||||
border-left-color: #fff;
|
border-left-color: #fff;
|
||||||
transform: translateX(5px);
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-item i { width: 20px; margin-right: 10px; }
|
.sidebar-footer {
|
||||||
|
padding: 16px 20px;
|
||||||
|
border-top: 1px solid rgba(255,255,255,0.12);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Main Content */
|
.btn-logout {
|
||||||
|
width: 100%;
|
||||||
|
background: rgba(255,255,255,0.12);
|
||||||
|
color: white;
|
||||||
|
border: 1.5px solid rgba(255,255,255,0.3);
|
||||||
|
padding: 9px 16px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-logout:hover {
|
||||||
|
background: rgba(255,255,255,0.22);
|
||||||
|
border-color: rgba(255,255,255,0.5);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-overlay {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
background: rgba(0,0,0,0.45);
|
||||||
|
z-index: 1040;
|
||||||
|
backdrop-filter: blur(2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-overlay.show { display: block; }
|
||||||
|
|
||||||
|
/* ===== MAIN CONTENT ===== */
|
||||||
.main-content {
|
.main-content {
|
||||||
margin-left: 280px;
|
margin-left: var(--sidebar-width);
|
||||||
flex: 1;
|
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.admin-header {
|
/* ===== TOPBAR ===== */
|
||||||
|
.topbar {
|
||||||
background: white;
|
background: white;
|
||||||
padding: 20px 30px;
|
height: 64px;
|
||||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
padding: 0 24px;
|
||||||
border-bottom: 1px solid #dee2e6;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
box-shadow: 0 1px 0 #e5e7eb;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content-area { padding: 30px; }
|
.topbar-left { display: flex; align-items: center; gap: 14px; }
|
||||||
|
|
||||||
.page-header {
|
.hamburger-btn {
|
||||||
background: white;
|
display: none;
|
||||||
padding: 30px;
|
background: none;
|
||||||
border-radius: 12px;
|
border: none;
|
||||||
box-shadow: 0 4px 6px rgba(0,0,0,0.05);
|
color: #374151;
|
||||||
margin-bottom: 30px;
|
font-size: 1.25rem;
|
||||||
|
padding: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 6px;
|
||||||
|
transition: background 0.15s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.breadcrumb { background: transparent; padding: 0; margin-bottom: 10px; }
|
.hamburger-btn:hover { background: #f3f4f6; }
|
||||||
.breadcrumb-item a { color: #28a745; text-decoration: none; }
|
|
||||||
|
|
||||||
/* Stats Cards */
|
.topbar-breadcrumb { font-size: 0.8rem; color: #6b7280; margin-bottom: 2px; }
|
||||||
|
.topbar-breadcrumb a { color: var(--green-main); text-decoration: none; }
|
||||||
|
.topbar-title h2 { font-size: 1.1rem; font-weight: 700; color: #111827; margin: 0; }
|
||||||
|
.topbar-title p { font-size: 0.75rem; color: #6b7280; margin: 0; }
|
||||||
|
|
||||||
|
.btn-back-website {
|
||||||
|
background: linear-gradient(135deg, #dc2626, #b91c1c);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 9px 18px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.825rem;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 7px;
|
||||||
|
transition: all 0.2s;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-back-website:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 4px 12px rgba(220,38,38,0.35);
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== CONTENT AREA ===== */
|
||||||
|
.content-area { padding: 20px 24px 24px; flex: 1; }
|
||||||
|
|
||||||
|
/* ===== STATS GRID ===== */
|
||||||
.stats-grid {
|
.stats-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(4, 1fr);
|
grid-template-columns: repeat(4, 1fr);
|
||||||
gap: 20px;
|
gap: 16px;
|
||||||
margin-bottom: 30px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stat-card {
|
.stat-card {
|
||||||
background: white;
|
background: white;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
padding: 20px;
|
padding: 18px 16px;
|
||||||
box-shadow: 0 4px 6px rgba(0,0,0,0.05);
|
box-shadow: 0 1px 3px rgba(0,0,0,0.06), 0 4px 10px rgba(0,0,0,0.04);
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-left: 4px solid;
|
border-left: 4px solid;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stat-card.primary { border-left-color: #007bff; }
|
.stat-card.primary { border-left-color: #2563eb; }
|
||||||
.stat-card.warning { border-left-color: #ffc107; }
|
.stat-card.warning { border-left-color: #d97706; }
|
||||||
.stat-card.info { border-left-color: #17a2b8; }
|
.stat-card.info { border-left-color: #0891b2; }
|
||||||
.stat-card.success { border-left-color: #28a745; }
|
.stat-card.success { border-left-color: var(--green-main); }
|
||||||
|
|
||||||
.stat-label {
|
.stat-label {
|
||||||
font-size: 0.75rem;
|
font-size: 0.72rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
margin-bottom: 5px;
|
letter-spacing: 0.04em;
|
||||||
|
margin-bottom: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stat-card.primary .stat-label { color: #007bff; }
|
.stat-card.primary .stat-label { color: #2563eb; }
|
||||||
.stat-card.warning .stat-label { color: #ffc107; }
|
.stat-card.warning .stat-label { color: #d97706; }
|
||||||
.stat-card.info .stat-label { color: #17a2b8; }
|
.stat-card.info .stat-label { color: #0891b2; }
|
||||||
.stat-card.success .stat-label { color: #28a745; }
|
.stat-card.success .stat-label { color: var(--green-main); }
|
||||||
|
|
||||||
.stat-value { font-size: 1.5rem; font-weight: 700; color: #333; }
|
.stat-value { font-size: 1.5rem; font-weight: 800; color: #111827; }
|
||||||
.stat-icon { font-size: 2rem; color: #dee2e6; }
|
.stat-icon { font-size: 1.75rem; color: #e5e7eb; }
|
||||||
|
|
||||||
|
/* ===== TABLE CARD ===== */
|
||||||
|
.table-card {
|
||||||
|
background: white;
|
||||||
|
border-radius: 14px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.06), 0 4px 10px rgba(0,0,0,0.04);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-card-header {
|
||||||
|
padding: 18px 20px;
|
||||||
|
border-bottom: 1px solid #f3f4f6;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #111827;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-controls {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
/* Table */
|
/* Table */
|
||||||
.data-table {
|
.data-table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
background: white;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.data-table th, .data-table td {
|
.data-table th, .data-table td {
|
||||||
padding: 12px 15px;
|
padding: 11px 14px;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
border-bottom: 1px solid #dee2e6;
|
border-bottom: 1px solid #f3f4f6;
|
||||||
|
font-size: 0.875rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.data-table th {
|
.data-table th {
|
||||||
background: #f8f9fa;
|
background: #f9fafb;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #495057;
|
color: #6b7280;
|
||||||
font-size: 0.85rem;
|
font-size: 0.78rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.data-table tbody tr:hover { background-color: #f8f9fc; }
|
.data-table tbody tr:hover { background-color: #f9fafb; }
|
||||||
|
|
||||||
/* Badges */
|
/* Badges */
|
||||||
.badge-status {
|
.badge-status {
|
||||||
padding: 4px 10px;
|
padding: 4px 10px;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
font-size: 0.75rem;
|
font-size: 0.72rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.badge-pending { background: #fff3cd; color: #856404; }
|
.badge-pending { background: #fef3c7; color: #92400e; }
|
||||||
.badge-processing { background: #d1ecf1; color: #0c5460; }
|
.badge-processing { background: #dbeafe; color: #1e40af; }
|
||||||
.badge-shipped { background: #cce5ff; color: #004085; }
|
.badge-shipped { background: #e0f2fe; color: #075985; }
|
||||||
.badge-delivered { background: #d4edda; color: #155724; }
|
.badge-delivered { background: #dcfce7; color: #166534; }
|
||||||
.badge-cancelled { background: #f8d7da; color: #721c24; }
|
.badge-cancelled { background: #fee2e2; color: #991b1b; }
|
||||||
.badge-paid { background: #d4edda; color: #155724; }
|
.badge-paid { background: #dcfce7; color: #166534; }
|
||||||
.badge-failed { background: #f8d7da; color: #721c24; }
|
.badge-failed { background: #fee2e2; color: #991b1b; }
|
||||||
|
|
||||||
|
/* Selects with badge style */
|
||||||
|
select.badge-status {
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
appearance: auto;
|
||||||
|
-webkit-appearance: auto;
|
||||||
|
}
|
||||||
|
|
||||||
/* Action Buttons */
|
/* Action Buttons */
|
||||||
.btn-action {
|
.btn-action {
|
||||||
|
|
@ -183,7 +338,7 @@
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.3s;
|
transition: all 0.2s;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -191,59 +346,22 @@
|
||||||
|
|
||||||
.btn-action:hover {
|
.btn-action:hover {
|
||||||
transform: translateY(-1px);
|
transform: translateY(-1px);
|
||||||
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
|
box-shadow: 0 2px 6px rgba(0,0,0,0.15);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-view { background: #17a2b8; color: white; }
|
.btn-view { background: #0891b2; color: white; }
|
||||||
.btn-edit { background: #ffc107; color: #212529; }
|
.btn-edit { background: #d97706; color: white; }
|
||||||
.btn-print { background: #6c757d; color: white; }
|
.btn-print { background: #6b7280; color: white; }
|
||||||
|
|
||||||
/* Section Header */
|
/* Cancelled row */
|
||||||
.section-header {
|
tr.row-cancelled { background-color: #f3f4f6 !important; opacity: 0.75; }
|
||||||
display: flex;
|
tr.row-cancelled td { color: #9ca3af !important; }
|
||||||
justify-content: space-between;
|
tr.row-cancelled strong, tr.row-cancelled .text-success { color: #9ca3af !important; }
|
||||||
align-items: center;
|
tr.row-cancelled select, tr.row-cancelled .btn-action { pointer-events: none; opacity: 0.5; cursor: not-allowed; }
|
||||||
margin-bottom: 20px;
|
|
||||||
padding-bottom: 15px;
|
|
||||||
border-bottom: 2px solid #f8f9fa;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-title { font-size: 1.3rem; font-weight: 600; color: #333; }
|
/* Pagination */
|
||||||
|
|
||||||
/* Back Button */
|
|
||||||
.back-button {
|
|
||||||
position: fixed;
|
|
||||||
top: 20px;
|
|
||||||
right: 20px;
|
|
||||||
z-index: 1100;
|
|
||||||
background: linear-gradient(45deg, #dc3545, #c82333);
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
padding: 12px 20px;
|
|
||||||
border-radius: 25px;
|
|
||||||
font-weight: 600;
|
|
||||||
transition: all 0.3s;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.back-button:hover {
|
|
||||||
background: linear-gradient(45deg, #c82333, #a71e2a);
|
|
||||||
transform: translateY(-2px);
|
|
||||||
color: white;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fade-in {
|
|
||||||
animation: fadeIn 0.3s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fadeIn {
|
|
||||||
from { opacity: 0; transform: translateY(10px); }
|
|
||||||
to { opacity: 1; transform: translateY(0); }
|
|
||||||
}
|
|
||||||
/* Pagination Fix */
|
|
||||||
.pagination {
|
.pagination {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
|
|
@ -256,133 +374,169 @@
|
||||||
.pagination .page-item .page-link {
|
.pagination .page-item .page-link {
|
||||||
padding: 6px 12px;
|
padding: 6px 12px;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
border: 1px solid #dee2e6;
|
border: 1px solid #e5e7eb;
|
||||||
color: #28a745;
|
color: var(--green-main);
|
||||||
font-size: 0.85rem;
|
font-size: 0.83rem;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
background: white;
|
background: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pagination .page-item.active .page-link {
|
.pagination .page-item.active .page-link {
|
||||||
background: #28a745;
|
background: var(--green-main);
|
||||||
border-color: #28a745;
|
border-color: var(--green-main);
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pagination .page-item.disabled .page-link {
|
.pagination .page-item.disabled .page-link { color: #d1d5db; pointer-events: none; }
|
||||||
color: #adb5bd;
|
.pagination .page-item .page-link:hover { background: #f0fdf4; border-color: var(--green-main); }
|
||||||
pointer-events: none;
|
|
||||||
|
.table-footer {
|
||||||
|
padding: 14px 20px;
|
||||||
|
border-top: 1px solid #f3f4f6;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pagination .page-item .page-link:hover {
|
/* Alert */
|
||||||
background: #e9f7ef;
|
.alert-success-custom {
|
||||||
border-color: #28a745;
|
background: #f0fdf4;
|
||||||
color: #28a745;
|
border: 1px solid #bbf7d0;
|
||||||
}
|
color: #166534;
|
||||||
/* Cancelled row styling */
|
border-radius: 10px;
|
||||||
tr.row-cancelled {
|
padding: 12px 16px;
|
||||||
background-color: #e9ecef !important;
|
font-size: 0.875rem;
|
||||||
opacity: 0.75;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
tr.row-cancelled td {
|
.fade-in {
|
||||||
color: #6c757d !important;
|
animation: fadeIn 0.3s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
tr.row-cancelled strong,
|
@keyframes fadeIn {
|
||||||
tr.row-cancelled .text-success {
|
from { opacity: 0; transform: translateY(10px); }
|
||||||
color: #6c757d !important;
|
to { opacity: 1; transform: translateY(0); }
|
||||||
}
|
}
|
||||||
|
|
||||||
tr.row-cancelled select,
|
/* ===== RESPONSIVE ===== */
|
||||||
tr.row-cancelled .btn-action {
|
@media (max-width: 1100px) {
|
||||||
pointer-events: none;
|
|
||||||
opacity: 0.5;
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.sidebar { width: 100%; position: relative; }
|
|
||||||
.main-content { margin-left: 0; }
|
|
||||||
.stats-grid { grid-template-columns: repeat(2, 1fr); }
|
.stats-grid { grid-template-columns: repeat(2, 1fr); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.sidebar { transform: translateX(-100%); }
|
||||||
|
.sidebar.open { transform: translateX(0); box-shadow: 4px 0 24px rgba(0,0,0,0.2); }
|
||||||
|
.main-content { margin-left: 0; }
|
||||||
|
.hamburger-btn { display: flex; align-items: center; justify-content: center; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
.stats-grid { grid-template-columns: 1fr 1fr; gap: 10px; }
|
||||||
|
.stat-card { padding: 14px 12px; }
|
||||||
|
.stat-value { font-size: 1.3rem; }
|
||||||
|
.stat-icon { font-size: 1.4rem; }
|
||||||
|
.content-area { padding: 14px 14px 20px; }
|
||||||
|
.topbar { padding: 0 14px; }
|
||||||
|
.btn-back-website span { display: none; }
|
||||||
|
.btn-back-website { padding: 9px 12px; }
|
||||||
|
.table-card-header { flex-direction: column; align-items: flex-start; }
|
||||||
|
.table-controls { width: 100%; }
|
||||||
|
.table-controls .form-select, .table-controls a { flex: 1; }
|
||||||
|
.table-footer { flex-direction: column; align-items: flex-start; gap: 10px; }
|
||||||
|
.data-table th, .data-table td { padding: 9px 10px; font-size: 0.8rem; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 380px) {
|
||||||
|
.stats-grid { grid-template-columns: 1fr; }
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<!-- Back Button -->
|
|
||||||
<a href="{{ route('home') }}" class="back-button">
|
|
||||||
<i class="fas fa-arrow-left me-2"></i>Kembali ke Website
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div class="admin-container">
|
<div class="sidebar-overlay" id="sidebarOverlay" onclick="closeSidebar()"></div>
|
||||||
|
|
||||||
<!-- Sidebar -->
|
<!-- Sidebar -->
|
||||||
<nav class="sidebar">
|
<nav class="sidebar" id="sidebar">
|
||||||
<div class="sidebar-header">
|
<div class="sidebar-header">
|
||||||
<h3>🌱 Bibit Cabai</h3>
|
<span class="brand-icon">🌱</span>
|
||||||
<p>Admin Dashboard</p>
|
<h3>Bibit Cabai</h3>
|
||||||
<small class="text-light">{{ Auth::user()->name ?? 'Admin User' }}</small>
|
<p class="subtitle">Admin Dashboard</p>
|
||||||
|
<span class="admin-name">{{ Auth::user()->name ?? 'Admin User' }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="sidebar-menu">
|
<div class="sidebar-menu">
|
||||||
|
<div class="menu-section-label">Menu Utama</div>
|
||||||
|
|
||||||
<a href="{{ route('admin.dashboard') }}" class="menu-item">
|
<a href="{{ route('admin.dashboard') }}" class="menu-item">
|
||||||
<i class="fas fa-tachometer-alt"></i>Dashboard
|
<i class="fas fa-tachometer-alt"></i><span>Dashboard</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('admin.products.index') }}" class="menu-item">
|
<a href="{{ route('admin.products.index') }}" class="menu-item">
|
||||||
<i class="fas fa-seedling"></i>Kelola Produk
|
<i class="fas fa-seedling"></i><span>Kelola Produk</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('admin.orders') }}" class="menu-item active">
|
<a href="{{ route('admin.orders') }}" class="menu-item active">
|
||||||
<i class="fas fa-shopping-cart"></i>Pesanan
|
<i class="fas fa-shopping-cart"></i><span>Pesanan</span>
|
||||||
</a>
|
</a>
|
||||||
{{-- ↓ TAMBAHKAN DI SINI ↓ --}}
|
|
||||||
<a href="{{ route('admin.cancellations') }}" class="menu-item">
|
<a href="{{ route('admin.cancellations') }}" class="menu-item">
|
||||||
<i class="fas fa-times-circle"></i>Pengajuan Batal
|
<i class="fas fa-times-circle"></i><span>Pengajuan Batal</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('admin.users') }}" class="menu-item">
|
<a href="{{ route('admin.users') }}" class="menu-item">
|
||||||
<i class="fas fa-users"></i>Pengguna
|
<i class="fas fa-users"></i><span>Pengguna</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('admin.laporan') }}" class="menu-item">
|
<a href="{{ route('admin.laporan') }}" class="menu-item">
|
||||||
<i class="fas fa-chart-line"></i>Laporan
|
<i class="fas fa-chart-line"></i><span>Laporan</span>
|
||||||
</a>
|
</a>
|
||||||
<!-- <a href="{{ route('admin.settings') }}" class="menu-item">
|
</div>
|
||||||
<i class="fas fa-cog"></i>Pengaturan
|
|
||||||
</a> -->
|
<div class="sidebar-footer">
|
||||||
<div class="mt-4 px-3">
|
|
||||||
<form method="POST" action="{{ route('admin.logout') }}">
|
<form method="POST" action="{{ route('admin.logout') }}">
|
||||||
@csrf
|
@csrf
|
||||||
<button type="submit" class="btn btn-outline-light btn-sm w-100">
|
<button type="submit" class="btn-logout" onclick="return confirm('Apakah Anda yakin ingin logout?')">
|
||||||
<i class="fas fa-sign-out-alt me-2"></i>Logout
|
<i class="fas fa-sign-out-alt"></i><span>Logout</span>
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<!-- Main Content -->
|
<!-- Main Content -->
|
||||||
<div class="main-content">
|
<div class="main-content">
|
||||||
<div class="admin-header">
|
|
||||||
<nav aria-label="breadcrumb">
|
|
||||||
<ol class="breadcrumb">
|
|
||||||
<li class="breadcrumb-item">
|
|
||||||
<a href="{{ route('admin.dashboard') }}">
|
|
||||||
<i class="fas fa-home"></i> Dashboard
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="breadcrumb-item active" aria-current="page">Pesanan</li>
|
|
||||||
</ol>
|
|
||||||
</nav>
|
|
||||||
<h2>Orders Management</h2>
|
|
||||||
<p class="mb-0">Kelola semua pesanan pelanggan di sini!</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<!-- Topbar -->
|
||||||
|
<header class="topbar">
|
||||||
|
<div class="topbar-left">
|
||||||
|
<button class="hamburger-btn" id="hamburgerBtn" onclick="toggleSidebar()" aria-label="Toggle menu">
|
||||||
|
<i class="fas fa-bars"></i>
|
||||||
|
</button>
|
||||||
|
<div class="topbar-title">
|
||||||
|
<div class="topbar-breadcrumb">
|
||||||
|
<a href="{{ route('admin.dashboard') }}"><i class="fas fa-home"></i> Dashboard</a>
|
||||||
|
/ Pesanan
|
||||||
|
</div>
|
||||||
|
<h2>Orders Management</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a href="{{ route('home') }}" class="btn-back-website">
|
||||||
|
<i class="fas fa-arrow-left"></i>
|
||||||
|
<span>Kembali ke Website</span>
|
||||||
|
</a>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<!-- Content -->
|
||||||
<div class="content-area fade-in">
|
<div class="content-area fade-in">
|
||||||
|
|
||||||
@if(session('success'))
|
@if(session('success'))
|
||||||
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
<div class="alert-success-custom">
|
||||||
<i class="fas fa-check-circle me-2"></i>{{ session('success') }}
|
<i class="fas fa-check-circle"></i>
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
<span>{{ session('success') }}</span>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<!-- Stats Cards -->
|
<!-- Stats Grid -->
|
||||||
<div class="stats-grid">
|
<div class="stats-grid">
|
||||||
<div class="stat-card primary">
|
<div class="stat-card primary">
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -393,36 +547,36 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-card warning">
|
<div class="stat-card warning">
|
||||||
<div>
|
<div>
|
||||||
<div class="stat-label">Pending Orders</div>
|
<div class="stat-label">Pending</div>
|
||||||
<div class="stat-value">{{ \App\Models\Transaksi::where('order_status', 'pending')->count() }}</div>
|
<div class="stat-value">{{ \App\Models\Transaksi::where('order_status', 'pending')->count() }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-icon"><i class="fas fa-clock"></i></div>
|
<div class="stat-icon"><i class="fas fa-clock"></i></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-card info">
|
<div class="stat-card info">
|
||||||
<div>
|
<div>
|
||||||
<div class="stat-label">Processing Orders</div>
|
<div class="stat-label">Processing</div>
|
||||||
<div class="stat-value">{{ \App\Models\Transaksi::where('order_status', 'processing')->count() }}</div>
|
<div class="stat-value">{{ \App\Models\Transaksi::where('order_status', 'processing')->count() }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-icon"><i class="fas fa-box"></i></div>
|
<div class="stat-icon"><i class="fas fa-box"></i></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-card success">
|
<div class="stat-card success">
|
||||||
<div>
|
<div>
|
||||||
<div class="stat-label">Delivered Orders</div>
|
<div class="stat-label">Delivered</div>
|
||||||
<div class="stat-value">{{ \App\Models\Transaksi::where('order_status', 'delivered')->count() }}</div>
|
<div class="stat-value">{{ \App\Models\Transaksi::where('order_status', 'delivered')->count() }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-icon"><i class="fas fa-check-circle"></i></div>
|
<div class="stat-icon"><i class="fas fa-check-circle"></i></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Orders Table -->
|
<!-- Table Card -->
|
||||||
<div class="page-header">
|
<div class="table-card">
|
||||||
<div class="section-header">
|
<div class="table-card-header">
|
||||||
<h3 class="section-title">
|
<div class="section-title">
|
||||||
<i class="fas fa-shopping-cart text-success me-2"></i>
|
<i class="fas fa-shopping-cart text-success"></i>
|
||||||
Daftar Pesanan ({{ $orders->total() }})
|
Daftar Pesanan ({{ $orders->total() }})
|
||||||
</h3>
|
</div>
|
||||||
<div class="d-flex gap-2 align-items-center">
|
<div class="table-controls">
|
||||||
<select class="form-select form-select-sm" id="filterStatus" onchange="filterOrders()" style="width: 160px;">
|
<select class="form-select form-select-sm" id="filterStatus" onchange="filterOrders()" style="min-width:140px;">
|
||||||
<option value="">Semua Status</option>
|
<option value="">Semua Status</option>
|
||||||
<option value="pending">Pending</option>
|
<option value="pending">Pending</option>
|
||||||
<option value="processing">Processing</option>
|
<option value="processing">Processing</option>
|
||||||
|
|
@ -440,14 +594,14 @@
|
||||||
<table class="data-table" id="ordersTable">
|
<table class="data-table" id="ordersTable">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Invoice Number</th>
|
<th>Invoice</th>
|
||||||
<th>Customer</th>
|
<th>Customer</th>
|
||||||
<th>Phone</th>
|
<th>Phone</th>
|
||||||
<th>Order Status</th>
|
<th>Order Status</th>
|
||||||
<th>Payment Status</th>
|
<th>Payment Status</th>
|
||||||
<th>Metode Pembayaran</th>
|
<th>Metode</th>
|
||||||
<th>Total</th>
|
<th>Total</th>
|
||||||
<th>Order Date</th>
|
<th>Tanggal</th>
|
||||||
<th>Aksi</th>
|
<th>Aksi</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
@ -459,8 +613,7 @@ class="{{ $order->order_status === 'cancelled' ? 'row-cancelled' : '' }}">
|
||||||
<td>{{ $order->customer_name }}</td>
|
<td>{{ $order->customer_name }}</td>
|
||||||
<td>{{ $order->customer_phone }}</td>
|
<td>{{ $order->customer_phone }}</td>
|
||||||
<td>
|
<td>
|
||||||
<select class="badge-status badge-{{ $order->order_status }} border-0 cursor-pointer"
|
<select class="badge-status badge-{{ $order->order_status }} border-0"
|
||||||
style="cursor:pointer; appearance:auto;"
|
|
||||||
onchange="updateStatus({{ $order->id }}, 'order_status', this.value, this)">
|
onchange="updateStatus({{ $order->id }}, 'order_status', this.value, this)">
|
||||||
<option value="pending" {{ $order->order_status == 'pending' ? 'selected' : '' }}>Pending</option>
|
<option value="pending" {{ $order->order_status == 'pending' ? 'selected' : '' }}>Pending</option>
|
||||||
<option value="processing" {{ $order->order_status == 'processing' ? 'selected' : '' }}>Processing</option>
|
<option value="processing" {{ $order->order_status == 'processing' ? 'selected' : '' }}>Processing</option>
|
||||||
|
|
@ -469,14 +622,11 @@ class="{{ $order->order_status === 'cancelled' ? 'row-cancelled' : '' }}">
|
||||||
<option value="cancelled" {{ $order->order_status == 'cancelled' ? 'selected' : '' }}>Cancelled</option>
|
<option value="cancelled" {{ $order->order_status == 'cancelled' ? 'selected' : '' }}>Cancelled</option>
|
||||||
</select>
|
</select>
|
||||||
@if($order->cancellation && $order->cancellation->status === 'pending')
|
@if($order->cancellation && $order->cancellation->status === 'pending')
|
||||||
<br><span class="badge-status badge-warning mt-1" style="font-size:0.7rem;">
|
<br><span class="badge-status badge-warning mt-1" style="font-size:0.68rem;">⚠ Minta Batal</span>
|
||||||
⚠ Minta Batal
|
|
||||||
</span>
|
|
||||||
@endif
|
@endif
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<select class="badge-status badge-{{ $order->payment_status }} border-0"
|
<select class="badge-status badge-{{ $order->payment_status }} border-0"
|
||||||
style="cursor:pointer; appearance:auto;"
|
|
||||||
onchange="updateStatus({{ $order->id }}, 'payment_status', this.value, this)">
|
onchange="updateStatus({{ $order->id }}, 'payment_status', this.value, this)">
|
||||||
<option value="pending" {{ $order->payment_status == 'pending' ? 'selected' : '' }}>Pending</option>
|
<option value="pending" {{ $order->payment_status == 'pending' ? 'selected' : '' }}>Pending</option>
|
||||||
<option value="paid" {{ $order->payment_status == 'paid' ? 'selected' : '' }}>Paid</option>
|
<option value="paid" {{ $order->payment_status == 'paid' ? 'selected' : '' }}>Paid</option>
|
||||||
|
|
@ -484,38 +634,40 @@ class="{{ $order->order_status === 'cancelled' ? 'row-cancelled' : '' }}">
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="badge-status" style="background:#ced4da;color:#212529;">
|
<span class="badge-status" style="background:#f3f4f6;color:#374151;">
|
||||||
{{ ucwords(str_replace('_', ' ', $order->payment_method ?? '-')) }}
|
{{ ucwords(str_replace('_', ' ', $order->payment_method ?? '-')) }}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td><strong class="text-success">Rp {{ number_format($order->total_amount, 0, ',', '.') }}</strong></td>
|
<td><strong class="text-success">Rp {{ number_format($order->total_amount, 0, ',', '.') }}</strong></td>
|
||||||
<td><small>{{ $order->created_at->format('d M Y H:i') }}</small></td>
|
<td><small style="color:#6b7280;">{{ $order->created_at->format('d M Y H:i') }}</small></td>
|
||||||
<td>
|
<td>
|
||||||
<div class="d-flex gap-1">
|
<div class="d-flex gap-1 flex-nowrap">
|
||||||
<a href="{{ route('admin.transaksis.show', $order->id) }}"
|
<a href="{{ route('admin.transaksis.show', $order->id) }}" class="btn-action btn-view" title="Lihat Detail">
|
||||||
class="btn-action btn-view" title="View Details">
|
|
||||||
<i class="fas fa-eye"></i>
|
<i class="fas fa-eye"></i>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('admin.transaksis.edit', $order->id) }}"
|
<a href="{{ route('admin.transaksis.edit', $order->id) }}" class="btn-action btn-edit" title="Edit">
|
||||||
class="btn-action btn-edit" title="Edit">
|
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('admin.transaksis.print', $order->id) }}"
|
<a href="{{ route('admin.transaksis.print', $order->id) }}" class="btn-action btn-print" title="Print Invoice" target="_blank">
|
||||||
class="btn-action btn-print" title="Print Invoice" target="_blank">
|
|
||||||
<i class="fas fa-print"></i>
|
<i class="fas fa-print"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@empty
|
@empty
|
||||||
|
<tr>
|
||||||
|
<td colspan="9" style="text-align:center; padding:40px; color:#9ca3af;">
|
||||||
|
<i class="fas fa-inbox" style="font-size:2rem; display:block; margin-bottom:10px; opacity:0.3;"></i>
|
||||||
|
Belum ada pesanan
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
@endforelse
|
@endforelse
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Pagination -->
|
<div class="table-footer">
|
||||||
<div class="d-flex justify-content-between align-items-center mt-4">
|
<small style="color:#6b7280;">
|
||||||
<small class="text-muted">
|
|
||||||
Menampilkan {{ $orders->firstItem() ?? 0 }} sampai {{ $orders->lastItem() ?? 0 }}
|
Menampilkan {{ $orders->firstItem() ?? 0 }} sampai {{ $orders->lastItem() ?? 0 }}
|
||||||
dari {{ $orders->total() }} pesanan
|
dari {{ $orders->total() }} pesanan
|
||||||
</small>
|
</small>
|
||||||
|
|
@ -525,11 +677,32 @@ class="btn-action btn-print" title="Print Invoice" target="_blank">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Bootstrap JS -->
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
// Sidebar toggle
|
||||||
|
function toggleSidebar() {
|
||||||
|
const sidebar = document.getElementById('sidebar');
|
||||||
|
const overlay = document.getElementById('sidebarOverlay');
|
||||||
|
sidebar.classList.toggle('open');
|
||||||
|
overlay.classList.toggle('show');
|
||||||
|
document.body.style.overflow = sidebar.classList.contains('open') ? 'hidden' : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeSidebar() {
|
||||||
|
const sidebar = document.getElementById('sidebar');
|
||||||
|
const overlay = document.getElementById('sidebarOverlay');
|
||||||
|
sidebar.classList.remove('open');
|
||||||
|
overlay.classList.remove('show');
|
||||||
|
document.body.style.overflow = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('resize', function() {
|
||||||
|
if (window.innerWidth > 900) closeSidebar();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Filter orders
|
||||||
function filterOrders() {
|
function filterOrders() {
|
||||||
const filterValue = document.getElementById('filterStatus').value.toLowerCase();
|
const filterValue = document.getElementById('filterStatus').value.toLowerCase();
|
||||||
const rows = document.querySelectorAll('#ordersTable tbody tr[data-status]');
|
const rows = document.querySelectorAll('#ordersTable tbody tr[data-status]');
|
||||||
|
|
@ -539,8 +712,8 @@ function filterOrders() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update status via AJAX
|
||||||
function updateStatus(orderId, field, value, selectEl) {
|
function updateStatus(orderId, field, value, selectEl) {
|
||||||
// Jika status sudah cancelled, tidak bisa diubah
|
|
||||||
if (field === 'order_status') {
|
if (field === 'order_status') {
|
||||||
const row = selectEl.closest('tr');
|
const row = selectEl.closest('tr');
|
||||||
const currentStatus = row.getAttribute('data-status');
|
const currentStatus = row.getAttribute('data-status');
|
||||||
|
|
@ -564,17 +737,13 @@ function updateStatus(orderId, field, value, selectEl) {
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
// Update warna badge sesuai nilai baru
|
|
||||||
const badgeClasses = ['badge-pending','badge-processing','badge-shipped','badge-delivered','badge-cancelled','badge-paid','badge-failed'];
|
const badgeClasses = ['badge-pending','badge-processing','badge-shipped','badge-delivered','badge-cancelled','badge-paid','badge-failed'];
|
||||||
selectEl.classList.remove(...badgeClasses);
|
selectEl.classList.remove(...badgeClasses);
|
||||||
selectEl.classList.add('badge-' + value);
|
selectEl.classList.add('badge-' + value);
|
||||||
|
|
||||||
// Update data-status di row jika yang diubah adalah order_status
|
|
||||||
if (field === 'order_status') {
|
if (field === 'order_status') {
|
||||||
const row = selectEl.closest('tr');
|
const row = selectEl.closest('tr');
|
||||||
row.setAttribute('data-status', value);
|
row.setAttribute('data-status', value);
|
||||||
|
|
||||||
// Tambahkan/hapus class abu-abu jika status cancelled
|
|
||||||
if (value === 'cancelled') {
|
if (value === 'cancelled') {
|
||||||
row.classList.add('row-cancelled');
|
row.classList.add('row-cancelled');
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -582,7 +751,6 @@ function updateStatus(orderId, field, value, selectEl) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tampilkan notifikasi kecil
|
|
||||||
showToast('Status berhasil diupdate!');
|
showToast('Status berhasil diupdate!');
|
||||||
} else {
|
} else {
|
||||||
alert('Gagal update: ' + data.message);
|
alert('Gagal update: ' + data.message);
|
||||||
|
|
@ -594,7 +762,7 @@ function updateStatus(orderId, field, value, selectEl) {
|
||||||
function showToast(msg) {
|
function showToast(msg) {
|
||||||
const toast = document.createElement('div');
|
const toast = document.createElement('div');
|
||||||
toast.innerText = msg;
|
toast.innerText = msg;
|
||||||
toast.style.cssText = 'position:fixed;bottom:20px;right:20px;background:#28a745;color:white;padding:10px 20px;border-radius:8px;z-index:9999;font-size:14px;';
|
toast.style.cssText = 'position:fixed;bottom:24px;right:24px;background:#16a34a;color:white;padding:10px 20px;border-radius:8px;z-index:9999;font-size:14px;font-weight:500;box-shadow:0 4px 12px rgba(0,0,0,0.15);';
|
||||||
document.body.appendChild(toast);
|
document.body.appendChild(toast);
|
||||||
setTimeout(() => toast.remove(), 2500);
|
setTimeout(() => toast.remove(), 2500);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,238 +1,814 @@
|
||||||
@extends('admin.layouts.app')
|
<!DOCTYPE html>
|
||||||
|
<html lang="id">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Edit Produk - Bibit Cabai</title>
|
||||||
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||||
|
|
||||||
@section('title', 'Edit Produk')
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||||
|
|
||||||
@section('content')
|
<style>
|
||||||
<!-- Back Button -->
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
<a href="{{ route('admin.products.index') }}" class="back-button">
|
|
||||||
<i class="fas fa-arrow-left me-2"></i>Kembali ke Daftar Produk
|
:root {
|
||||||
</a>
|
--sidebar-width: 260px;
|
||||||
<!-- Main Content -->
|
--green-dark: #15803d;
|
||||||
<div class="main-content">
|
--green-main: #16a34a;
|
||||||
<div class="admin-header">
|
}
|
||||||
<nav aria-label="breadcrumb">
|
|
||||||
<ol class="breadcrumb">
|
body {
|
||||||
<li class="breadcrumb-item">
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
<a href="{{ route('admin.dashboard') }}">
|
background: #f1f5f2;
|
||||||
<i class="fas fa-home"></i> Dashboard
|
overflow-x: hidden;
|
||||||
</a>
|
}
|
||||||
</li>
|
|
||||||
<li class="breadcrumb-item">
|
/* ===== SIDEBAR ===== */
|
||||||
<a href="{{ route('admin.products.index') }}">Kelola Produk</a>
|
.sidebar {
|
||||||
</li>
|
width: var(--sidebar-width);
|
||||||
<li class="breadcrumb-item active" aria-current="page">Edit Produk</li>
|
background: linear-gradient(180deg, var(--green-dark) 0%, #14532d 100%);
|
||||||
</ol>
|
color: white;
|
||||||
</nav>
|
min-height: 100vh;
|
||||||
<h2>Edit Produk</h2>
|
position: fixed;
|
||||||
<p class="mb-0">Edit informasi produk {{ $product->name }}</p>
|
top: 0; left: 0;
|
||||||
|
z-index: 1050;
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-header {
|
||||||
|
padding: 24px 20px 20px;
|
||||||
|
text-align: center;
|
||||||
|
border-bottom: 1px solid rgba(255,255,255,0.12);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-header .brand-icon { font-size: 2rem; margin-bottom: 6px; display: block; }
|
||||||
|
.sidebar-header h3 { font-size: 1.35rem; font-weight: 700; margin-bottom: 2px; }
|
||||||
|
.sidebar-header .subtitle { opacity: 0.65; font-size: 0.78rem; margin-bottom: 6px; }
|
||||||
|
.sidebar-header .admin-name {
|
||||||
|
display: inline-block;
|
||||||
|
background: rgba(255,255,255,0.15);
|
||||||
|
padding: 3px 12px;
|
||||||
|
border-radius: 20px;
|
||||||
|
font-size: 0.78rem;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-menu { padding: 12px 0; flex: 1; }
|
||||||
|
|
||||||
|
.menu-section-label {
|
||||||
|
font-size: 0.68rem;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
opacity: 0.45;
|
||||||
|
padding: 12px 20px 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 12px 20px;
|
||||||
|
color: rgba(255,255,255,0.82);
|
||||||
|
text-decoration: none;
|
||||||
|
transition: all 0.2s;
|
||||||
|
border-left: 3px solid transparent;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-item i { width: 18px; font-size: 0.95rem; flex-shrink: 0; text-align: center; }
|
||||||
|
|
||||||
|
.menu-item:hover {
|
||||||
|
background: rgba(255,255,255,0.1);
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
border-left-color: rgba(255,255,255,0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-item.active {
|
||||||
|
background: rgba(255,255,255,0.15);
|
||||||
|
color: white;
|
||||||
|
border-left-color: #fff;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-footer {
|
||||||
|
padding: 16px 20px;
|
||||||
|
border-top: 1px solid rgba(255,255,255,0.12);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-logout {
|
||||||
|
width: 100%;
|
||||||
|
background: rgba(255,255,255,0.12);
|
||||||
|
color: white;
|
||||||
|
border: 1.5px solid rgba(255,255,255,0.3);
|
||||||
|
padding: 9px 16px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-logout:hover {
|
||||||
|
background: rgba(255,255,255,0.22);
|
||||||
|
border-color: rgba(255,255,255,0.5);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-overlay {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
background: rgba(0,0,0,0.45);
|
||||||
|
z-index: 1040;
|
||||||
|
backdrop-filter: blur(2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-overlay.show { display: block; }
|
||||||
|
|
||||||
|
/* ===== MAIN CONTENT ===== */
|
||||||
|
.main-content {
|
||||||
|
margin-left: var(--sidebar-width);
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== TOPBAR ===== */
|
||||||
|
.topbar {
|
||||||
|
background: white;
|
||||||
|
height: 64px;
|
||||||
|
padding: 0 24px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
box-shadow: 0 1px 0 #e5e7eb;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topbar-left { display: flex; align-items: center; gap: 14px; }
|
||||||
|
|
||||||
|
.hamburger-btn {
|
||||||
|
display: none;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: #374151;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
padding: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 6px;
|
||||||
|
transition: background 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger-btn:hover { background: #f3f4f6; }
|
||||||
|
|
||||||
|
.topbar-breadcrumb { font-size: 0.8rem; color: #6b7280; margin-bottom: 2px; }
|
||||||
|
.topbar-breadcrumb a { color: var(--green-main); text-decoration: none; }
|
||||||
|
.topbar-breadcrumb a:hover { text-decoration: underline; }
|
||||||
|
.topbar-title h2 { font-size: 1.1rem; font-weight: 700; color: #111827; margin: 0; }
|
||||||
|
.topbar-title p { font-size: 0.75rem; color: #6b7280; margin: 0; }
|
||||||
|
|
||||||
|
.btn-back-header {
|
||||||
|
background: linear-gradient(135deg, #dc2626, #b91c1c);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 9px 18px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.825rem;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 7px;
|
||||||
|
transition: all 0.2s;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-back-header:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 4px 12px rgba(220,38,38,0.35);
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== CONTENT AREA ===== */
|
||||||
|
.content-area { padding: 20px 24px 32px; flex: 1; }
|
||||||
|
|
||||||
|
/* ===== FORM CARD ===== */
|
||||||
|
.form-card {
|
||||||
|
background: white;
|
||||||
|
border-radius: 14px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.06), 0 4px 10px rgba(0,0,0,0.04);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-card-header {
|
||||||
|
padding: 20px 24px 16px;
|
||||||
|
border-bottom: 1px solid #f3f4f6;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-card-header-icon {
|
||||||
|
width: 38px; height: 38px;
|
||||||
|
background: #fef9c3;
|
||||||
|
border-radius: 10px;
|
||||||
|
display: flex; align-items: center; justify-content: center;
|
||||||
|
color: #ca8a04;
|
||||||
|
font-size: 1rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-card-header h3 { font-size: 1rem; font-weight: 700; color: #111827; margin: 0; }
|
||||||
|
.form-card-header p { font-size: 0.78rem; color: #6b7280; margin: 0; }
|
||||||
|
|
||||||
|
.form-card-body { padding: 24px; }
|
||||||
|
|
||||||
|
/* ===== FORM ELEMENTS ===== */
|
||||||
|
.form-label {
|
||||||
|
font-size: 0.82rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #374151;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.req { color: #dc2626; }
|
||||||
|
|
||||||
|
.form-control, .form-select {
|
||||||
|
border: 1.5px solid #e5e7eb;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
padding: 9px 12px;
|
||||||
|
color: #111827;
|
||||||
|
transition: border-color 0.2s, box-shadow 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control:focus, .form-select:focus {
|
||||||
|
border-color: var(--green-main);
|
||||||
|
box-shadow: 0 0 0 3px rgba(22,163,74,0.12);
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control.is-invalid, .form-select.is-invalid { border-color: #dc2626; }
|
||||||
|
|
||||||
|
.input-group-text {
|
||||||
|
background: #f9fafb;
|
||||||
|
border: 1.5px solid #e5e7eb;
|
||||||
|
border-radius: 8px 0 0 8px;
|
||||||
|
color: #6b7280;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group .form-control,
|
||||||
|
.input-group .form-select { border-radius: 0 8px 8px 0; }
|
||||||
|
|
||||||
|
.form-text { font-size: 0.75rem; color: #9ca3af; margin-top: 4px; }
|
||||||
|
textarea.form-control { resize: vertical; min-height: 100px; }
|
||||||
|
|
||||||
|
/* ===== CURRENT IMAGE ===== */
|
||||||
|
.current-image-box {
|
||||||
|
border: 1.5px solid #e5e7eb;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 14px;
|
||||||
|
background: #f9fafb;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.current-image-box img {
|
||||||
|
width: 80px; height: 80px;
|
||||||
|
object-fit: cover;
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.current-image-info { font-size: 0.8rem; color: #6b7280; }
|
||||||
|
.current-image-info strong { display: block; color: #374151; margin-bottom: 3px; font-size: 0.82rem; }
|
||||||
|
|
||||||
|
/* ===== IMAGE UPLOAD ===== */
|
||||||
|
.image-upload-area {
|
||||||
|
border: 2px dashed #d1d5db;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 20px;
|
||||||
|
text-align: center;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
background: #fafafa;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-upload-area:hover { border-color: var(--green-main); background: #f0fdf4; }
|
||||||
|
.image-upload-area input[type=file] {
|
||||||
|
position: absolute; inset: 0; width: 100%; height: 100%;
|
||||||
|
opacity: 0; cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-icon { font-size: 2rem; color: #d1d5db; margin-bottom: 8px; }
|
||||||
|
.upload-text { font-size: 0.82rem; color: #6b7280; }
|
||||||
|
.upload-hint { font-size: 0.72rem; color: #9ca3af; margin-top: 4px; }
|
||||||
|
|
||||||
|
.image-preview-box { display: none; margin-top: 14px; }
|
||||||
|
.image-preview-box img {
|
||||||
|
max-width: 150px; max-height: 150px;
|
||||||
|
border-radius: 10px; object-fit: cover;
|
||||||
|
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== INFO BANNER ===== */
|
||||||
|
.info-banner {
|
||||||
|
background: #fffbeb;
|
||||||
|
border: 1px solid #fde68a;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 10px;
|
||||||
|
font-size: 0.82rem;
|
||||||
|
color: #92400e;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-banner i { margin-top: 1px; flex-shrink: 0; }
|
||||||
|
|
||||||
|
/* ===== SECTION DIVIDER ===== */
|
||||||
|
.section-divider {
|
||||||
|
font-size: 0.72rem;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: #9ca3af;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
border-bottom: 1px solid #f3f4f6;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== ACTION BUTTONS ===== */
|
||||||
|
.form-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 10px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
padding-top: 20px;
|
||||||
|
border-top: 1px solid #f3f4f6;
|
||||||
|
margin-top: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-cancel {
|
||||||
|
background: #f9fafb;
|
||||||
|
color: #374151;
|
||||||
|
border: 1.5px solid #e5e7eb;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 10px 20px;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 600;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-flex; align-items: center; gap: 7px;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-cancel:hover { background: #f3f4f6; color: #111827; text-decoration: none; }
|
||||||
|
|
||||||
|
.btn-reset-form {
|
||||||
|
background: #fff7ed;
|
||||||
|
color: #c2410c;
|
||||||
|
border: 1.5px solid #fed7aa;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 10px 20px;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 600;
|
||||||
|
display: inline-flex; align-items: center; gap: 7px;
|
||||||
|
transition: all 0.2s;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-reset-form:hover { background: #ffedd5; }
|
||||||
|
|
||||||
|
.btn-save {
|
||||||
|
background: linear-gradient(135deg, #ca8a04, #a16207);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 10px 24px;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 700;
|
||||||
|
display: inline-flex; align-items: center; gap: 7px;
|
||||||
|
transition: all 0.2s;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-save:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 4px 12px rgba(202,138,4,0.35);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-in { animation: fadeIn 0.3s ease; }
|
||||||
|
|
||||||
|
@keyframes fadeIn {
|
||||||
|
from { opacity: 0; transform: translateY(8px); }
|
||||||
|
to { opacity: 1; transform: translateY(0); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== RESPONSIVE ===== */
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.sidebar { transform: translateX(-100%); }
|
||||||
|
.sidebar.open { transform: translateX(0); box-shadow: 4px 0 24px rgba(0,0,0,0.2); }
|
||||||
|
.main-content { margin-left: 0; }
|
||||||
|
.hamburger-btn { display: flex; align-items: center; justify-content: center; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
.content-area { padding: 14px 14px 24px; }
|
||||||
|
.topbar { padding: 0 14px; height: 58px; }
|
||||||
|
.btn-back-header span { display: none; }
|
||||||
|
.btn-back-header { padding: 9px 12px; }
|
||||||
|
.form-card-body { padding: 16px; }
|
||||||
|
.form-actions { justify-content: stretch; }
|
||||||
|
.form-actions > * { flex: 1; justify-content: center; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="sidebar-overlay" id="sidebarOverlay" onclick="closeSidebar()"></div>
|
||||||
|
|
||||||
|
<!-- ===== SIDEBAR ===== -->
|
||||||
|
<nav class="sidebar" id="sidebar">
|
||||||
|
<div class="sidebar-header">
|
||||||
|
<span class="brand-icon">🌱</span>
|
||||||
|
<h3>Bibit Cabai</h3>
|
||||||
|
<p class="subtitle">Admin Dashboard</p>
|
||||||
|
<span class="admin-name">{{ Auth::user()->name ?? 'Admin User' }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="sidebar-menu">
|
||||||
|
<div class="menu-section-label">Menu Utama</div>
|
||||||
|
<a href="{{ route('admin.dashboard') }}" class="menu-item">
|
||||||
|
<i class="fas fa-tachometer-alt"></i><span>Dashboard</span>
|
||||||
|
</a>
|
||||||
|
<a href="{{ route('admin.products.index') }}" class="menu-item active">
|
||||||
|
<i class="fas fa-seedling"></i><span>Kelola Produk</span>
|
||||||
|
</a>
|
||||||
|
<a href="{{ route('admin.orders') }}" class="menu-item">
|
||||||
|
<i class="fas fa-shopping-cart"></i><span>Pesanan</span>
|
||||||
|
</a>
|
||||||
|
<a href="{{ route('admin.cancellations') }}" class="menu-item">
|
||||||
|
<i class="fas fa-times-circle"></i><span>Pengajuan Batal</span>
|
||||||
|
</a>
|
||||||
|
<a href="{{ route('admin.users') }}" class="menu-item">
|
||||||
|
<i class="fas fa-users"></i><span>Pengguna</span>
|
||||||
|
</a>
|
||||||
|
<a href="{{ route('admin.laporan') }}" class="menu-item">
|
||||||
|
<i class="fas fa-chart-line"></i><span>Laporan</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="sidebar-footer">
|
||||||
|
<form method="POST" action="{{ route('admin.logout') }}">
|
||||||
|
@csrf
|
||||||
|
<button type="submit" class="btn-logout">
|
||||||
|
<i class="fas fa-sign-out-alt"></i><span>Logout</span>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<!-- ===== MAIN ===== -->
|
||||||
|
<div class="main-content">
|
||||||
|
|
||||||
|
<!-- Topbar -->
|
||||||
|
<header class="topbar">
|
||||||
|
<div class="topbar-left">
|
||||||
|
<button class="hamburger-btn" onclick="toggleSidebar()">
|
||||||
|
<i class="fas fa-bars"></i>
|
||||||
|
</button>
|
||||||
|
<div class="topbar-title">
|
||||||
|
<div class="topbar-breadcrumb">
|
||||||
|
<a href="{{ route('admin.dashboard') }}"><i class="fas fa-home"></i> Dashboard</a>
|
||||||
|
/ <a href="{{ route('admin.products.index') }}">Kelola Produk</a>
|
||||||
|
/ Edit Produk
|
||||||
|
</div>
|
||||||
|
<h2>Edit Produk</h2>
|
||||||
|
<p>Edit informasi produk {{ $product->name }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a href="{{ route('admin.products.index') }}" class="btn-back-header">
|
||||||
|
<i class="fas fa-arrow-left"></i>
|
||||||
|
<span>Kembali ke Produk</span>
|
||||||
|
</a>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<!-- Content -->
|
||||||
<div class="content-area fade-in">
|
<div class="content-area fade-in">
|
||||||
<!-- Display Validation Errors -->
|
|
||||||
@if ($errors->any())
|
@if ($errors->any())
|
||||||
<div class="alert alert-danger">
|
<div class="alert alert-danger alert-dismissible fade show mb-4" role="alert">
|
||||||
<ul class="mb-0">
|
<i class="fas fa-exclamation-circle me-2"></i>
|
||||||
|
<strong>Terdapat kesalahan:</strong>
|
||||||
|
<ul class="mb-0 mt-1">
|
||||||
@foreach ($errors->all() as $error)
|
@foreach ($errors->all() as $error)
|
||||||
<li>{{ $error }}</li>
|
<li>{{ $error }}</li>
|
||||||
@endforeach
|
@endforeach
|
||||||
</ul>
|
</ul>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<div class="card">
|
@if (session('success'))
|
||||||
<div class="card-header">
|
<div class="alert alert-success alert-dismissible fade show mb-4" role="alert">
|
||||||
<h4 class="mb-0">
|
<i class="fas fa-check-circle me-2"></i>{{ session('success') }}
|
||||||
<i class="fas fa-edit text-warning me-2"></i>
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||||
Form Edit Produk
|
|
||||||
</h4>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
@endif
|
||||||
<form action="{{ route('admin.products.update', $product) }}" method="POST" enctype="multipart/form-data">
|
|
||||||
|
<div class="form-card">
|
||||||
|
<div class="form-card-header">
|
||||||
|
<div class="form-card-header-icon">
|
||||||
|
<i class="fas fa-edit"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3>Form Edit Produk</h3>
|
||||||
|
<p>Ubah data produk sesuai kebutuhan</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-card-body">
|
||||||
|
<form action="{{ route('admin.products.update', $product) }}" method="POST" enctype="multipart/form-data" id="productForm">
|
||||||
@csrf
|
@csrf
|
||||||
@method('PUT')
|
@method('PUT')
|
||||||
|
|
||||||
<div class="row">
|
<!-- INFORMASI DASAR -->
|
||||||
<!-- Nama Produk -->
|
<div class="section-divider">Informasi Dasar</div>
|
||||||
<div class="col-md-6 mb-3">
|
|
||||||
<label for="name" class="form-label">Nama Produk <span class="text-danger">*</span></label>
|
<div class="row g-3 mb-3">
|
||||||
<input type="text" class="form-control @error('name') is-invalid @enderror"
|
<div class="col-md-6">
|
||||||
id="name" name="name" value="{{ old('name', $product->name) }}" required>
|
<label class="form-label">Nama Produk <span class="req">*</span></label>
|
||||||
|
<div class="input-group">
|
||||||
|
<span class="input-group-text"><i class="fas fa-seedling"></i></span>
|
||||||
|
<input type="text"
|
||||||
|
class="form-control @error('name') is-invalid @enderror"
|
||||||
|
name="name" id="name"
|
||||||
|
value="{{ old('name', $product->name) }}"
|
||||||
|
placeholder="Contoh: Bibit Cabai Rawit Genni"
|
||||||
|
required>
|
||||||
|
</div>
|
||||||
@error('name')
|
@error('name')
|
||||||
<div class="invalid-feedback">{{ $message }}</div>
|
<div class="invalid-feedback d-block">{{ $message }}</div>
|
||||||
@enderror
|
@enderror
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Kategori -->
|
<div class="col-md-6">
|
||||||
<div class="col-md-6 mb-3">
|
<label class="form-label">Kategori <span class="req">*</span></label>
|
||||||
<label for="category" class="form-label">Kategori <span class="text-danger">*</span></label>
|
<div class="input-group">
|
||||||
<select class="form-select @error('category') is-invalid @enderror" id="category" name="category" required>
|
<span class="input-group-text"><i class="fas fa-list"></i></span>
|
||||||
|
<select class="form-select @error('category') is-invalid @enderror"
|
||||||
|
name="category" id="category" required>
|
||||||
<option value="">Pilih Kategori</option>
|
<option value="">Pilih Kategori</option>
|
||||||
<option value="Sayuran" {{ old('category', $product->category) === 'Sayuran' ? 'selected' : '' }}>Sayuran</option>
|
<option value="Sayuran" {{ old('category', $product->category) === 'Sayuran' ? 'selected' : '' }}>Sayuran</option>
|
||||||
<option value="Buah" {{ old('category', $product->category) === 'Buah' ? 'selected' : '' }}>Buah</option>
|
<option value="Buah" {{ old('category', $product->category) === 'Buah' ? 'selected' : '' }}>Buah</option>
|
||||||
<option value="Herbal" {{ old('category', $product->category) === 'Herbal' ? 'selected' : '' }}>Herbal</option>
|
<option value="Herbal" {{ old('category', $product->category) === 'Herbal' ? 'selected' : '' }}>Herbal</option>
|
||||||
<option value="Hias" {{ old('category', $product->category) === 'Hias' ? 'selected' : '' }}>Hias</option>
|
<option value="Hias" {{ old('category', $product->category) === 'Hias' ? 'selected' : '' }}>Hias</option>
|
||||||
</select>
|
</select>
|
||||||
|
</div>
|
||||||
@error('category')
|
@error('category')
|
||||||
<div class="invalid-feedback">{{ $message }}</div>
|
<div class="invalid-feedback d-block">{{ $message }}</div>
|
||||||
@enderror
|
@enderror
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Harga -->
|
<!-- HARGA, STOK, STATUS, LABEL -->
|
||||||
<div class="col-md-6 mb-3">
|
<div class="row g-3 mb-3">
|
||||||
<label for="price" class="form-label">Harga <span class="text-danger">*</span></label>
|
<div class="col-sm-6 col-md-3">
|
||||||
|
<label class="form-label">Harga <span class="req">*</span></label>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<span class="input-group-text">Rp</span>
|
<span class="input-group-text">Rp</span>
|
||||||
<input type="number" class="form-control @error('price') is-invalid @enderror"
|
<input type="number"
|
||||||
id="price" name="price" value="{{ old('price', $product->price) }}"
|
class="form-control @error('price') is-invalid @enderror"
|
||||||
min="0" step="0.01" required>
|
name="price" id="price"
|
||||||
|
value="{{ old('price', $product->price) }}"
|
||||||
|
min="0" step="1000" placeholder="0" required>
|
||||||
</div>
|
</div>
|
||||||
@error('price')
|
@error('price')
|
||||||
<div class="invalid-feedback">{{ $message }}</div>
|
<div class="invalid-feedback d-block">{{ $message }}</div>
|
||||||
@enderror
|
@enderror
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Stok -->
|
<div class="col-sm-6 col-md-3">
|
||||||
<div class="col-md-6 mb-3">
|
<label class="form-label">Stok <span class="req">*</span></label>
|
||||||
<label for="stock" class="form-label">Stok <span class="text-danger">*</span></label>
|
<div class="input-group">
|
||||||
<input type="number" class="form-control @error('stock') is-invalid @enderror"
|
<span class="input-group-text"><i class="fas fa-boxes"></i></span>
|
||||||
id="stock" name="stock" value="{{ old('stock', $product->stock) }}"
|
<input type="number"
|
||||||
min="0" required>
|
class="form-control @error('stock') is-invalid @enderror"
|
||||||
|
name="stock" id="stock"
|
||||||
|
value="{{ old('stock', $product->stock) }}"
|
||||||
|
min="0" placeholder="0" required>
|
||||||
|
</div>
|
||||||
@error('stock')
|
@error('stock')
|
||||||
<div class="invalid-feedback">{{ $message }}</div>
|
<div class="invalid-feedback d-block">{{ $message }}</div>
|
||||||
@enderror
|
@enderror
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Status -->
|
<div class="col-sm-6 col-md-3">
|
||||||
<div class="col-md-6 mb-3">
|
<label class="form-label">Status <span class="req">*</span></label>
|
||||||
<label for="status" class="form-label">Status <span class="text-danger">*</span></label>
|
<div class="input-group">
|
||||||
<select class="form-select @error('status') is-invalid @enderror" id="status" name="status" required>
|
<span class="input-group-text"><i class="fas fa-toggle-on"></i></span>
|
||||||
|
<select class="form-select @error('status') is-invalid @enderror"
|
||||||
|
name="status" id="status" required>
|
||||||
<option value="aktif" {{ old('status', $product->status) === 'aktif' ? 'selected' : '' }}>Aktif</option>
|
<option value="aktif" {{ old('status', $product->status) === 'aktif' ? 'selected' : '' }}>Aktif</option>
|
||||||
<option value="nonaktif" {{ old('status', $product->status) === 'nonaktif' ? 'selected' : '' }}>Non-aktif</option>
|
<option value="nonaktif" {{ old('status', $product->status) === 'nonaktif' ? 'selected' : '' }}>Non-aktif</option>
|
||||||
</select>
|
</select>
|
||||||
|
</div>
|
||||||
@error('status')
|
@error('status')
|
||||||
<div class="invalid-feedback">{{ $message }}</div>
|
<div class="invalid-feedback d-block">{{ $message }}</div>
|
||||||
@enderror
|
@enderror
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Label -->
|
<div class="col-sm-6 col-md-3">
|
||||||
<div class="col-md-6 mb-3">
|
<label class="form-label">Label</label>
|
||||||
<label for="label" class="form-label">Label</label>
|
<div class="input-group">
|
||||||
<select class="form-select @error('label') is-invalid @enderror" id="label" name="label">
|
<span class="input-group-text"><i class="fas fa-tag"></i></span>
|
||||||
<option value="">Tidak Ada Label</option>
|
<select class="form-select @error('label') is-invalid @enderror"
|
||||||
|
name="label" id="label">
|
||||||
|
<option value="">Tidak Ada</option>
|
||||||
<option value="baru" {{ old('label', $product->label) === 'baru' ? 'selected' : '' }}>Baru</option>
|
<option value="baru" {{ old('label', $product->label) === 'baru' ? 'selected' : '' }}>Baru</option>
|
||||||
<option value="populer" {{ old('label', $product->label) === 'populer' ? 'selected' : '' }}>Populer</option>
|
<option value="populer" {{ old('label', $product->label) === 'populer' ? 'selected' : '' }}>Populer</option>
|
||||||
<option value="diskon" {{ old('label', $product->label) === 'diskon' ? 'selected' : '' }}>Diskon</option>
|
<option value="diskon" {{ old('label', $product->label) === 'diskon' ? 'selected' : '' }}>Diskon</option>
|
||||||
<option value="terbatas" {{ old('label', $product->label) === 'terbatas' ? 'selected' : '' }}>Terbatas</option>
|
<option value="terbatas" {{ old('label', $product->label) === 'terbatas' ? 'selected' : '' }}>Terbatas</option>
|
||||||
</select>
|
</select>
|
||||||
|
</div>
|
||||||
@error('label')
|
@error('label')
|
||||||
<div class="invalid-feedback">{{ $message }}</div>
|
<div class="invalid-feedback d-block">{{ $message }}</div>
|
||||||
@enderror
|
@enderror
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Deskripsi -->
|
|
||||||
<div class="col-12 mb-3">
|
|
||||||
<label for="description" class="form-label">Deskripsi <span class="text-danger">*</span></label>
|
|
||||||
<textarea class="form-control @error('description') is-invalid @enderror"
|
|
||||||
id="description" name="description" rows="4" required>{{ old('description', $product->description) }}</textarea>
|
|
||||||
@error('description')
|
|
||||||
<div class="invalid-feedback">{{ $message }}</div>
|
|
||||||
@enderror
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Gambar Saat Ini -->
|
<!-- DESKRIPSI -->
|
||||||
@if($product->image_url)
|
|
||||||
<div class="col-12 mb-3">
|
|
||||||
<label class="form-label">Gambar Saat Ini</label>
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<img src="{{ $product->image_url }}" alt="{{ $product->name }}"
|
<label class="form-label">Deskripsi Produk <span class="req">*</span></label>
|
||||||
class="img-thumbnail" style="max-width: 200px;">
|
<textarea class="form-control @error('description') is-invalid @enderror"
|
||||||
|
name="description" id="description" rows="4"
|
||||||
|
placeholder="Jelaskan keunggulan dan cara perawatan bibit..." required>{{ old('description', $product->description) }}</textarea>
|
||||||
|
<div class="form-text">Deskripsi yang detail akan membantu pelanggan memahami produk Anda.</div>
|
||||||
|
@error('description')
|
||||||
|
<div class="invalid-feedback d-block">{{ $message }}</div>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- GAMBAR -->
|
||||||
|
<div class="section-divider" style="margin-top:24px">Gambar Produk</div>
|
||||||
|
|
||||||
|
@if($product->image_url)
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Gambar Saat Ini</label>
|
||||||
|
<div class="current-image-box">
|
||||||
|
<img src="{{ $product->image_url }}" alt="{{ $product->name }}">
|
||||||
|
<div class="current-image-info">
|
||||||
|
<strong>{{ $product->name }}</strong>
|
||||||
|
Gambar produk yang sedang aktif. Upload gambar baru di bawah untuk menggantinya.
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<!-- Upload Gambar Baru -->
|
<div class="mb-3">
|
||||||
<div class="col-12 mb-3">
|
<label class="form-label">
|
||||||
<label for="image" class="form-label">Gambar Produk (Opsional)</label>
|
Upload Gambar Baru
|
||||||
<input type="file" class="form-control @error('image') is-invalid @enderror"
|
<span style="font-weight:400;color:#9ca3af">(Opsional — kosongkan jika tidak ingin mengubah)</span>
|
||||||
id="image" name="image" accept="image/*">
|
</label>
|
||||||
<div class="form-text">Format: JPG, PNG, JPEG. Maksimal 2MB. Kosongkan jika tidak ingin mengubah gambar.</div>
|
<div class="image-upload-area" id="uploadArea">
|
||||||
|
<input type="file" name="image" id="image" accept="image/*"
|
||||||
|
onchange="previewImage(this)">
|
||||||
|
<div id="uploadPlaceholder">
|
||||||
|
<div class="upload-icon"><i class="fas fa-cloud-upload-alt"></i></div>
|
||||||
|
<div class="upload-text">Klik atau seret gambar ke sini</div>
|
||||||
|
<div class="upload-hint">JPG, PNG, GIF — Maks. 2MB — Disarankan 500×500px</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@error('image')
|
@error('image')
|
||||||
<div class="invalid-feedback">{{ $message }}</div>
|
<div class="invalid-feedback d-block">{{ $message }}</div>
|
||||||
@enderror
|
@enderror
|
||||||
|
<div class="image-preview-box" id="imagePreview">
|
||||||
|
<img id="previewImg" src="" alt="Preview">
|
||||||
|
<div class="form-text mt-1">
|
||||||
|
<span id="previewName"></span>
|
||||||
|
<a href="#" onclick="clearImage(); return false;" style="color:#dc2626;margin-left:8px">
|
||||||
|
<i class="fas fa-times"></i> Hapus
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Action Buttons -->
|
<!-- INFO BANNER -->
|
||||||
<div class="d-flex justify-content-between mt-4">
|
<div class="info-banner">
|
||||||
<a href="{{ route('admin.products.index') }}" class="btn btn-secondary">
|
<i class="fas fa-exclamation-triangle"></i>
|
||||||
<i class="fas fa-arrow-left me-2"></i>Kembali
|
<div>Pastikan semua perubahan sudah benar sebelum menyimpan. Perubahan akan langsung tampil di website.</div>
|
||||||
</a>
|
|
||||||
<div>
|
|
||||||
<button type="reset" class="btn btn-outline-warning me-2">
|
|
||||||
<i class="fas fa-undo me-2"></i>Reset
|
|
||||||
</button>
|
|
||||||
<button type="submit" class="btn btn-success">
|
|
||||||
<i class="fas fa-save me-2"></i>Update Produk
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- TOMBOL AKSI -->
|
||||||
|
<div class="form-actions">
|
||||||
|
<a href="{{ route('admin.products.index') }}" class="btn-cancel">
|
||||||
|
<i class="fas fa-times"></i> Batal
|
||||||
|
</a>
|
||||||
|
<button type="reset" class="btn-reset-form" onclick="clearImage()">
|
||||||
|
<i class="fas fa-undo"></i> Reset
|
||||||
|
</button>
|
||||||
|
<button type="submit" class="btn-save">
|
||||||
|
<i class="fas fa-save"></i> Update Produk
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
<script>
|
||||||
|
// ===== SIDEBAR =====
|
||||||
|
function toggleSidebar() {
|
||||||
|
document.getElementById('sidebar').classList.toggle('open');
|
||||||
|
document.getElementById('sidebarOverlay').classList.toggle('show');
|
||||||
|
}
|
||||||
|
function closeSidebar() {
|
||||||
|
document.getElementById('sidebar').classList.remove('open');
|
||||||
|
document.getElementById('sidebarOverlay').classList.remove('show');
|
||||||
|
}
|
||||||
|
window.addEventListener('resize', function() {
|
||||||
|
if (window.innerWidth > 900) closeSidebar();
|
||||||
|
});
|
||||||
|
|
||||||
<style>
|
// ===== IMAGE PREVIEW =====
|
||||||
.back-button {
|
function previewImage(input) {
|
||||||
position: fixed;
|
if (input.files && input.files[0]) {
|
||||||
top: 20px;
|
if (input.files[0].size > 2 * 1024 * 1024) {
|
||||||
right: 20px;
|
alert('Ukuran file terlalu besar! Maksimal 2MB.');
|
||||||
z-index: 1100;
|
input.value = '';
|
||||||
background: linear-gradient(45deg, #ffc107, #e0a800);
|
return;
|
||||||
color: #212529;
|
}
|
||||||
border: none;
|
const reader = new FileReader();
|
||||||
padding: 12px 20px;
|
reader.onload = function(e) {
|
||||||
border-radius: 25px;
|
document.getElementById('previewImg').src = e.target.result;
|
||||||
font-weight: 600;
|
document.getElementById('previewName').textContent = input.files[0].name;
|
||||||
transition: all 0.3s ease;
|
document.getElementById('imagePreview').style.display = 'block';
|
||||||
text-decoration: none;
|
document.getElementById('uploadPlaceholder').style.opacity = '0.4';
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(input.files[0]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.back-button:hover {
|
function clearImage() {
|
||||||
background: linear-gradient(45deg, #e0a800, #c69500);
|
document.getElementById('image').value = '';
|
||||||
transform: translateY(-2px);
|
document.getElementById('imagePreview').style.display = 'none';
|
||||||
color: #212529;
|
document.getElementById('uploadPlaceholder').style.opacity = '1';
|
||||||
text-decoration: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.card {
|
// ===== PRICE: digits only =====
|
||||||
border: none;
|
document.getElementById('price').addEventListener('input', function() {
|
||||||
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
|
this.value = this.value.replace(/[^0-9]/g, '');
|
||||||
border-radius: 12px;
|
});
|
||||||
}
|
|
||||||
|
|
||||||
.card-header {
|
// ===== DRAG & DROP =====
|
||||||
background: linear-gradient(45deg, #f8f9fa, #e9ecef);
|
const uploadArea = document.getElementById('uploadArea');
|
||||||
border-bottom: 1px solid #dee2e6;
|
['dragover','dragenter'].forEach(evt => {
|
||||||
border-radius: 12px 12px 0 0 !important;
|
uploadArea.addEventListener(evt, function(e) {
|
||||||
}
|
e.preventDefault();
|
||||||
|
this.style.borderColor = 'var(--green-main)';
|
||||||
|
this.style.background = '#f0fdf4';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
['dragleave','drop'].forEach(evt => {
|
||||||
|
uploadArea.addEventListener(evt, function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
this.style.borderColor = '#d1d5db';
|
||||||
|
this.style.background = '#fafafa';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
.form-label {
|
// Auto-dismiss alerts
|
||||||
font-weight: 600;
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
color: #495057;
|
document.querySelectorAll('.alert').forEach(function(alert) {
|
||||||
}
|
setTimeout(function() {
|
||||||
|
const a = bootstrap.Alert.getOrCreateInstance(alert);
|
||||||
.text-danger {
|
if (a) a.close();
|
||||||
color: #dc3545 !important;
|
}, 5000);
|
||||||
}
|
});
|
||||||
|
document.getElementById('name').focus();
|
||||||
.fade-in {
|
});
|
||||||
animation: fadeIn 0.3s ease-in-out;
|
</script>
|
||||||
}
|
</body>
|
||||||
|
</html>
|
||||||
@keyframes fadeIn {
|
|
||||||
from { opacity: 0; transform: translateY(10px); }
|
|
||||||
to { opacity: 1; transform: translateY(0); }
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@endsection
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -9,137 +9,442 @@
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||||
<style>
|
<style>
|
||||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: #f8f9fa; }
|
|
||||||
.admin-container { display: flex; min-height: 100vh; }
|
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--sidebar-width: 260px;
|
||||||
|
--green-dark: #15803d;
|
||||||
|
--green-main: #16a34a;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
|
background: #f1f5f2;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== SIDEBAR ===== */
|
||||||
.sidebar {
|
.sidebar {
|
||||||
width: 280px; background: linear-gradient(180deg, #28a745, #20c997);
|
width: var(--sidebar-width);
|
||||||
color: white; min-height: 100vh; position: fixed; top: 0; left: 0; z-index: 1000;
|
background: linear-gradient(180deg, var(--green-dark) 0%, #14532d 100%);
|
||||||
|
color: white;
|
||||||
|
min-height: 100vh;
|
||||||
|
position: fixed;
|
||||||
|
top: 0; left: 0;
|
||||||
|
z-index: 1050;
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-header {
|
.sidebar-header {
|
||||||
padding: 25px 20px; text-align: center;
|
padding: 24px 20px 20px;
|
||||||
border-bottom: 1px solid rgba(255,255,255,0.1);
|
text-align: center;
|
||||||
|
border-bottom: 1px solid rgba(255,255,255,0.12);
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
.sidebar-header h3 { font-size: 1.8rem; font-weight: bold; margin-bottom: 5px; }
|
|
||||||
.sidebar-header p { opacity: 0.8; font-size: 0.9rem; }
|
.sidebar-header .brand-icon { font-size: 2rem; margin-bottom: 6px; display: block; }
|
||||||
.sidebar-menu { padding: 20px 0; }
|
.sidebar-header h3 { font-size: 1.35rem; font-weight: 700; margin-bottom: 2px; }
|
||||||
|
.sidebar-header .subtitle { opacity: 0.65; font-size: 0.78rem; margin-bottom: 6px; }
|
||||||
|
.sidebar-header .admin-name {
|
||||||
|
display: inline-block;
|
||||||
|
background: rgba(255,255,255,0.15);
|
||||||
|
padding: 3px 12px;
|
||||||
|
border-radius: 20px;
|
||||||
|
font-size: 0.78rem;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-menu { padding: 12px 0; flex: 1; }
|
||||||
|
|
||||||
|
.menu-section-label {
|
||||||
|
font-size: 0.68rem;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
opacity: 0.45;
|
||||||
|
padding: 12px 20px 6px;
|
||||||
|
}
|
||||||
|
|
||||||
.menu-item {
|
.menu-item {
|
||||||
display: block; padding: 15px 25px; color: white;
|
display: flex;
|
||||||
text-decoration: none; transition: all 0.3s; border-left: 4px solid transparent;
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 12px 20px;
|
||||||
|
color: rgba(255,255,255,0.82);
|
||||||
|
text-decoration: none;
|
||||||
|
transition: all 0.2s;
|
||||||
|
border-left: 3px solid transparent;
|
||||||
|
font-size: 0.9rem;
|
||||||
}
|
}
|
||||||
.menu-item:hover, .menu-item.active {
|
|
||||||
background: rgba(255,255,255,0.2); color: white;
|
|
||||||
border-left-color: #fff; transform: translateX(5px); text-decoration: none;
|
|
||||||
}
|
|
||||||
.menu-item i { width: 20px; margin-right: 10px; }
|
|
||||||
|
|
||||||
.main-content { margin-left: 280px; flex: 1; min-height: 100vh; }
|
.menu-item i { width: 18px; font-size: 0.95rem; flex-shrink: 0; text-align: center; }
|
||||||
.admin-header {
|
|
||||||
background: white; padding: 20px 30px;
|
|
||||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1); border-bottom: 1px solid #dee2e6;
|
|
||||||
}
|
|
||||||
.content-area { padding: 30px; }
|
|
||||||
.breadcrumb { background: transparent; padding: 0; margin-bottom: 10px; }
|
|
||||||
.breadcrumb-item a { color: #28a745; text-decoration: none; }
|
|
||||||
|
|
||||||
.back-button {
|
.menu-item:hover {
|
||||||
position: fixed; top: 20px; right: 20px; z-index: 1100;
|
background: rgba(255,255,255,0.1);
|
||||||
background: linear-gradient(45deg, #dc3545, #c82333);
|
color: white;
|
||||||
color: white; border: none; padding: 12px 20px;
|
text-decoration: none;
|
||||||
border-radius: 25px; font-weight: 600; text-decoration: none; transition: all 0.3s;
|
border-left-color: rgba(255,255,255,0.5);
|
||||||
}
|
}
|
||||||
.back-button:hover { color: white; transform: translateY(-2px); }
|
|
||||||
|
|
||||||
.fade-in { animation: fadeIn 0.3s ease-in-out; }
|
.menu-item.active {
|
||||||
|
background: rgba(255,255,255,0.15);
|
||||||
|
color: white;
|
||||||
|
border-left-color: #fff;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-footer {
|
||||||
|
padding: 16px 20px;
|
||||||
|
border-top: 1px solid rgba(255,255,255,0.12);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-logout {
|
||||||
|
width: 100%;
|
||||||
|
background: rgba(255,255,255,0.12);
|
||||||
|
color: white;
|
||||||
|
border: 1.5px solid rgba(255,255,255,0.3);
|
||||||
|
padding: 9px 16px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-logout:hover {
|
||||||
|
background: rgba(255,255,255,0.22);
|
||||||
|
border-color: rgba(255,255,255,0.5);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-overlay {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
background: rgba(0,0,0,0.45);
|
||||||
|
z-index: 1040;
|
||||||
|
backdrop-filter: blur(2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-overlay.show { display: block; }
|
||||||
|
|
||||||
|
/* ===== MAIN CONTENT ===== */
|
||||||
|
.main-content {
|
||||||
|
margin-left: var(--sidebar-width);
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== TOPBAR ===== */
|
||||||
|
.topbar {
|
||||||
|
background: white;
|
||||||
|
height: 64px;
|
||||||
|
padding: 0 24px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
box-shadow: 0 1px 0 #e5e7eb;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topbar-left { display: flex; align-items: center; gap: 14px; }
|
||||||
|
|
||||||
|
.hamburger-btn {
|
||||||
|
display: none;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: #374151;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
padding: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 6px;
|
||||||
|
transition: background 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger-btn:hover { background: #f3f4f6; }
|
||||||
|
|
||||||
|
.topbar-breadcrumb { font-size: 0.8rem; color: #6b7280; margin-bottom: 2px; }
|
||||||
|
.topbar-breadcrumb a { color: var(--green-main); text-decoration: none; }
|
||||||
|
.topbar-breadcrumb a:hover { text-decoration: underline; }
|
||||||
|
.topbar-title h2 { font-size: 1.1rem; font-weight: 700; color: #111827; margin: 0; }
|
||||||
|
.topbar-title p { font-size: 0.75rem; color: #6b7280; margin: 0; }
|
||||||
|
|
||||||
|
.topbar-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
|
||||||
|
|
||||||
|
.btn-topbar {
|
||||||
|
border: none;
|
||||||
|
padding: 8px 14px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
transition: all 0.2s;
|
||||||
|
white-space: nowrap;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-topbar:hover { transform: translateY(-1px); text-decoration: none; }
|
||||||
|
|
||||||
|
.btn-topbar-back {
|
||||||
|
background: linear-gradient(135deg, #dc2626, #b91c1c);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-topbar-back:hover { box-shadow: 0 4px 12px rgba(220,38,38,0.35); color: white; }
|
||||||
|
|
||||||
|
.btn-topbar-save {
|
||||||
|
background: linear-gradient(135deg, var(--green-main), var(--green-dark));
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-topbar-save:hover { box-shadow: 0 4px 12px rgba(22,163,74,0.35); color: white; }
|
||||||
|
|
||||||
|
/* ===== CONTENT AREA ===== */
|
||||||
|
.content-area { padding: 20px 24px 32px; flex: 1; }
|
||||||
|
|
||||||
|
/* ===== INFO CARD ===== */
|
||||||
|
.info-card {
|
||||||
|
background: white;
|
||||||
|
border-radius: 14px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.06), 0 4px 10px rgba(0,0,0,0.04);
|
||||||
|
overflow: hidden;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-card-header {
|
||||||
|
padding: 16px 20px;
|
||||||
|
border-bottom: 1px solid #f3f4f6;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-card-icon {
|
||||||
|
width: 34px; height: 34px;
|
||||||
|
border-radius: 9px;
|
||||||
|
display: flex; align-items: center; justify-content: center;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-blue { background: #eff6ff; color: #2563eb; }
|
||||||
|
.icon-green { background: #f0fdf4; color: var(--green-main); }
|
||||||
|
.icon-orange { background: #fff7ed; color: #ea580c; }
|
||||||
|
.icon-purple { background: #faf5ff; color: #7c3aed; }
|
||||||
|
.icon-gray { background: #f3f4f6; color: #6b7280; }
|
||||||
|
|
||||||
|
.info-card-header h3 { font-size: 0.9rem; font-weight: 700; color: #111827; margin: 0; }
|
||||||
|
.info-card-header p { font-size: 0.75rem; color: #6b7280; margin: 0; }
|
||||||
|
|
||||||
|
.info-card-body { padding: 20px; }
|
||||||
|
|
||||||
|
/* ===== SECTION DIVIDER ===== */
|
||||||
|
.section-divider {
|
||||||
|
font-size: 0.72rem;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: #9ca3af;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
border-bottom: 1px solid #f3f4f6;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== FORM STYLES ===== */
|
||||||
|
.form-label-custom {
|
||||||
|
font-size: 0.78rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #374151;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control-custom,
|
||||||
|
.form-select-custom {
|
||||||
|
font-size: 0.84rem;
|
||||||
|
padding: 8px 12px;
|
||||||
|
border: 1.5px solid #e5e7eb;
|
||||||
|
border-radius: 8px;
|
||||||
|
width: 100%;
|
||||||
|
color: #111827;
|
||||||
|
background: white;
|
||||||
|
transition: border-color 0.2s, box-shadow 0.2s;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control-custom:focus,
|
||||||
|
.form-select-custom:focus {
|
||||||
|
border-color: var(--green-main);
|
||||||
|
box-shadow: 0 0 0 3px rgba(22,163,74,0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control-custom.readonly,
|
||||||
|
.form-control-custom[readonly] {
|
||||||
|
background: #f9fafb;
|
||||||
|
color: #6b7280;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control-custom.is-invalid,
|
||||||
|
.form-select-custom.is-invalid {
|
||||||
|
border-color: #dc2626;
|
||||||
|
}
|
||||||
|
|
||||||
|
.invalid-feedback-custom {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: #dc2626;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea.form-control-custom { resize: vertical; min-height: 80px; }
|
||||||
|
|
||||||
|
.lock-badge {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
color: #9ca3af;
|
||||||
|
background: #f3f4f6;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 10px;
|
||||||
|
margin-left: 8px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== ORDER SUMMARY TABLE ===== */
|
||||||
|
.summary-table { width: 100%; border-collapse: collapse; font-size: 0.83rem; }
|
||||||
|
.summary-table td { padding: 7px 0; color: #374151; border-bottom: 1px solid #f9fafb; }
|
||||||
|
.summary-table td:last-child { text-align: right; font-weight: 600; }
|
||||||
|
.summary-table tfoot td {
|
||||||
|
border-top: 2px solid #f3f4f6;
|
||||||
|
border-bottom: none;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--green-main);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== FADE IN ===== */
|
||||||
|
.fade-in { animation: fadeIn 0.3s ease; }
|
||||||
|
|
||||||
@keyframes fadeIn {
|
@keyframes fadeIn {
|
||||||
from { opacity: 0; transform: translateY(10px); }
|
from { opacity: 0; transform: translateY(8px); }
|
||||||
to { opacity: 1; transform: translateY(0); }
|
to { opacity: 1; transform: translateY(0); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
/* ===== RESPONSIVE ===== */
|
||||||
.sidebar { width: 100%; position: relative; }
|
@media (max-width: 900px) {
|
||||||
|
.sidebar { transform: translateX(-100%); }
|
||||||
|
.sidebar.open { transform: translateX(0); box-shadow: 4px 0 24px rgba(0,0,0,0.2); }
|
||||||
.main-content { margin-left: 0; }
|
.main-content { margin-left: 0; }
|
||||||
|
.hamburger-btn { display: flex; align-items: center; justify-content: center; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
.content-area { padding: 14px 14px 24px; }
|
||||||
|
.topbar { padding: 0 14px; height: auto; min-height: 58px; flex-wrap: wrap; gap: 8px; padding-top: 10px; padding-bottom: 10px; }
|
||||||
|
.topbar-actions .btn-topbar span { display: none; }
|
||||||
|
.topbar-actions .btn-topbar { padding: 8px 10px; }
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<a href="{{ route('home') }}" class="back-button">
|
<div class="sidebar-overlay" id="sidebarOverlay" onclick="closeSidebar()"></div>
|
||||||
<i class="fas fa-arrow-left me-2"></i>Kembali ke Website
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div class="admin-container">
|
<!-- ===== SIDEBAR ===== -->
|
||||||
|
<nav class="sidebar" id="sidebar">
|
||||||
{{-- Sidebar --}}
|
|
||||||
<nav class="sidebar">
|
|
||||||
<div class="sidebar-header">
|
<div class="sidebar-header">
|
||||||
<h3>🌱 Bibit Cabai</h3>
|
<span class="brand-icon">🌱</span>
|
||||||
<p>Admin Dashboard</p>
|
<h3>Bibit Cabai</h3>
|
||||||
<small class="text-light">{{ Auth::user()->name ?? 'Admin User' }}</small>
|
<p class="subtitle">Admin Dashboard</p>
|
||||||
|
<span class="admin-name">{{ Auth::user()->name ?? 'Admin User' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="sidebar-menu">
|
<div class="sidebar-menu">
|
||||||
|
<div class="menu-section-label">Menu Utama</div>
|
||||||
<a href="{{ route('admin.dashboard') }}" class="menu-item">
|
<a href="{{ route('admin.dashboard') }}" class="menu-item">
|
||||||
<i class="fas fa-tachometer-alt"></i>Dashboard
|
<i class="fas fa-tachometer-alt"></i><span>Dashboard</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('admin.products.index') }}" class="menu-item">
|
<a href="{{ route('admin.products.index') }}" class="menu-item">
|
||||||
<i class="fas fa-seedling"></i>Kelola Produk
|
<i class="fas fa-seedling"></i><span>Kelola Produk</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('admin.orders') }}" class="menu-item active">
|
<a href="{{ route('admin.orders') }}" class="menu-item active">
|
||||||
<i class="fas fa-shopping-cart"></i>Pesanan
|
<i class="fas fa-shopping-cart"></i><span>Pesanan</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('admin.cancellations') }}" class="menu-item">
|
<a href="{{ route('admin.cancellations') }}" class="menu-item">
|
||||||
<i class="fas fa-times-circle"></i>Pengajuan Batal
|
<i class="fas fa-times-circle"></i><span>Pengajuan Batal</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('admin.users') }}" class="menu-item">
|
<a href="{{ route('admin.users') }}" class="menu-item">
|
||||||
<i class="fas fa-users"></i>Pengguna
|
<i class="fas fa-users"></i><span>Pengguna</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('admin.laporan') }}" class="menu-item">
|
<a href="{{ route('admin.laporan') }}" class="menu-item">
|
||||||
<i class="fas fa-chart-line"></i>Laporan
|
<i class="fas fa-chart-line"></i><span>Laporan</span>
|
||||||
</a>
|
</a>
|
||||||
<!-- <a href="{{ route('admin.settings') }}" class="menu-item">
|
</div>
|
||||||
<i class="fas fa-cog"></i>Pengaturan -->
|
<div class="sidebar-footer">
|
||||||
</a>
|
|
||||||
<div class="mt-4 px-3">
|
|
||||||
<form method="POST" action="{{ route('admin.logout') }}">
|
<form method="POST" action="{{ route('admin.logout') }}">
|
||||||
@csrf
|
@csrf
|
||||||
<button type="submit" class="btn btn-outline-light btn-sm w-100">
|
<button type="submit" class="btn-logout">
|
||||||
<i class="fas fa-sign-out-alt me-2"></i>Logout
|
<i class="fas fa-sign-out-alt"></i><span>Logout</span>
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
{{-- Main Content --}}
|
<!-- ===== MAIN ===== -->
|
||||||
<div class="main-content">
|
<div class="main-content">
|
||||||
<div class="admin-header">
|
|
||||||
<nav aria-label="breadcrumb">
|
|
||||||
<ol class="breadcrumb">
|
|
||||||
<li class="breadcrumb-item"><a href="{{ route('admin.dashboard') }}"><i class="fas fa-home"></i> Dashboard</a></li>
|
|
||||||
<li class="breadcrumb-item"><a href="{{ route('admin.orders') }}">Pesanan</a></li>
|
|
||||||
<li class="breadcrumb-item active">Edit {{ $transaksi->invoice_number }}</li>
|
|
||||||
</ol>
|
|
||||||
</nav>
|
|
||||||
<div class="d-flex justify-content-between align-items-center">
|
|
||||||
<div>
|
|
||||||
<h2>Edit Order</h2>
|
|
||||||
<p class="mb-0">{{ $transaksi->invoice_number }}</p>
|
|
||||||
</div>
|
|
||||||
<a href="{{ route('admin.transaksis.show', $transaksi->id) }}" class="btn btn-secondary">
|
|
||||||
<i class="fas fa-arrow-left me-1"></i> Back
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<!-- Topbar -->
|
||||||
|
<header class="topbar">
|
||||||
|
<div class="topbar-left">
|
||||||
|
<button class="hamburger-btn" onclick="toggleSidebar()">
|
||||||
|
<i class="fas fa-bars"></i>
|
||||||
|
</button>
|
||||||
|
<div class="topbar-title">
|
||||||
|
<div class="topbar-breadcrumb">
|
||||||
|
<a href="{{ route('admin.dashboard') }}"><i class="fas fa-home"></i> Dashboard</a>
|
||||||
|
/ <a href="{{ route('admin.orders') }}">Pesanan</a>
|
||||||
|
/ <a href="{{ route('admin.transaksis.show', $transaksi->id) }}">{{ $transaksi->invoice_number }}</a>
|
||||||
|
/ Edit
|
||||||
|
</div>
|
||||||
|
<h2>Edit Order</h2>
|
||||||
|
<p>{{ $transaksi->invoice_number }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="topbar-actions">
|
||||||
|
<a href="{{ route('admin.transaksis.show', $transaksi->id) }}" class="btn-topbar btn-topbar-back">
|
||||||
|
<i class="fas fa-arrow-left"></i>
|
||||||
|
<span>Kembali</span>
|
||||||
|
</a>
|
||||||
|
<button type="submit" form="editOrderForm" class="btn-topbar btn-topbar-save">
|
||||||
|
<i class="fas fa-save"></i>
|
||||||
|
<span>Simpan</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<!-- Content -->
|
||||||
<div class="content-area fade-in">
|
<div class="content-area fade-in">
|
||||||
|
|
||||||
@if ($errors->any())
|
@if ($errors->any())
|
||||||
<div class="alert alert-danger alert-dismissible fade show">
|
<div class="alert alert-danger alert-dismissible fade show mb-4" role="alert">
|
||||||
<strong>Error!</strong>
|
<i class="fas fa-exclamation-circle me-2"></i><strong>Error!</strong>
|
||||||
<ul class="mb-0 mt-2">
|
<ul class="mb-0 mt-1">
|
||||||
@foreach ($errors->all() as $error)
|
@foreach ($errors->all() as $error)
|
||||||
<li>{{ $error }}</li>
|
<li style="font-size:0.85rem;">{{ $error }}</li>
|
||||||
@endforeach
|
@endforeach
|
||||||
</ul>
|
</ul>
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||||
|
|
@ -147,216 +452,235 @@
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@if(session('success'))
|
@if(session('success'))
|
||||||
<div class="alert alert-success alert-dismissible fade show">
|
<div class="alert alert-success alert-dismissible fade show mb-4" role="alert">
|
||||||
<i class="fas fa-check-circle me-2"></i>{{ session('success') }}
|
<i class="fas fa-check-circle me-2"></i>{{ session('success') }}
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<form action="{{ route('admin.transaksis.update', $transaksi->id) }}" method="POST">
|
<form id="editOrderForm" action="{{ route('admin.transaksis.update', $transaksi->id) }}" method="POST">
|
||||||
@csrf
|
@csrf
|
||||||
@method('PUT')
|
@method('PUT')
|
||||||
|
|
||||||
<div class="row">
|
<div class="row g-3">
|
||||||
|
|
||||||
{{-- Kolom Kiri --}}
|
<!-- ===== KOLOM KIRI (8/12) ===== -->
|
||||||
<div class="col-lg-8">
|
<div class="col-lg-8">
|
||||||
|
|
||||||
{{-- Order Details --}}
|
<!-- Order Details (editable) -->
|
||||||
<div class="card shadow mb-4" style="border-radius:12px;">
|
<div class="info-card">
|
||||||
<div class="card-header py-3" style="background:#f8f9fa; border-radius:12px 12px 0 0;">
|
<div class="info-card-header">
|
||||||
<h6 class="m-0 fw-bold text-primary">Order Details</h6>
|
<div class="info-card-icon icon-blue">
|
||||||
|
<i class="fas fa-file-alt"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div>
|
||||||
|
<h3>Order Details</h3>
|
||||||
|
<p>Status & informasi pesanan yang dapat diubah</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-card-body">
|
||||||
|
<div class="row g-4">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="section-divider">Invoice</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label fw-semibold">Invoice Number</label>
|
<label class="form-label-custom">Invoice Number</label>
|
||||||
<input type="text" class="form-control bg-light"
|
<input type="text" class="form-control-custom readonly"
|
||||||
value="{{ $transaksi->invoice_number }}" readonly>
|
value="{{ $transaksi->invoice_number }}" readonly>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label fw-semibold">Order Status <span class="text-danger">*</span></label>
|
<label class="form-label-custom">Tanggal Order</label>
|
||||||
<select class="form-select @error('order_status') is-invalid @enderror"
|
<input type="text" class="form-control-custom readonly"
|
||||||
name="order_status" required>
|
value="{{ $transaksi->created_at->format('d M Y, H:i') }}" readonly>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="section-divider">Update Status</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label-custom">Order Status <span style="color:#dc2626;">*</span></label>
|
||||||
|
<select name="order_status" class="form-select-custom @error('order_status') is-invalid @enderror" required>
|
||||||
@foreach(['pending','processing','shipped','delivered','cancelled'] as $s)
|
@foreach(['pending','processing','shipped','delivered','cancelled'] as $s)
|
||||||
<option value="{{ $s }}"
|
<option value="{{ $s }}" {{ old('order_status', $transaksi->order_status) == $s ? 'selected' : '' }}>
|
||||||
{{ old('order_status', $transaksi->order_status) == $s ? 'selected' : '' }}>
|
|
||||||
{{ ucfirst($s) }}
|
{{ ucfirst($s) }}
|
||||||
</option>
|
</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
@error('order_status')
|
@error('order_status')
|
||||||
<div class="invalid-feedback">{{ $message }}</div>
|
<div class="invalid-feedback-custom">{{ $message }}</div>
|
||||||
@enderror
|
@enderror
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label fw-semibold">Payment Status <span class="text-danger">*</span></label>
|
<label class="form-label-custom">Payment Status <span style="color:#dc2626;">*</span></label>
|
||||||
<select class="form-select @error('payment_status') is-invalid @enderror"
|
<select name="payment_status" class="form-select-custom @error('payment_status') is-invalid @enderror" required>
|
||||||
name="payment_status" required>
|
|
||||||
@foreach(['pending','paid','failed'] as $p)
|
@foreach(['pending','paid','failed'] as $p)
|
||||||
<option value="{{ $p }}"
|
<option value="{{ $p }}" {{ old('payment_status', $transaksi->payment_status) == $p ? 'selected' : '' }}>
|
||||||
{{ old('payment_status', $transaksi->payment_status) == $p ? 'selected' : '' }}>
|
|
||||||
{{ ucfirst($p) }}
|
{{ ucfirst($p) }}
|
||||||
</option>
|
</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
@error('payment_status')
|
@error('payment_status')
|
||||||
<div class="invalid-feedback">{{ $message }}</div>
|
<div class="invalid-feedback-custom">{{ $message }}</div>
|
||||||
@enderror
|
@enderror
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
|
||||||
<label class="form-label fw-semibold">Tracking Number</label>
|
<div class="row g-3 mt-1">
|
||||||
<input type="text" class="form-control @error('tracking_number') is-invalid @enderror"
|
<div class="col-md-6">
|
||||||
name="tracking_number"
|
<label class="form-label-custom">Tracking Number</label>
|
||||||
|
<input type="text" name="tracking_number"
|
||||||
|
class="form-control-custom @error('tracking_number') is-invalid @enderror"
|
||||||
value="{{ old('tracking_number', $transaksi->tracking_number) }}"
|
value="{{ old('tracking_number', $transaksi->tracking_number) }}"
|
||||||
placeholder="Enter tracking number">
|
placeholder="Masukkan nomor resi...">
|
||||||
@error('tracking_number')
|
@error('tracking_number')
|
||||||
<div class="invalid-feedback">{{ $message }}</div>
|
<div class="invalid-feedback-custom">{{ $message }}</div>
|
||||||
@enderror
|
@enderror
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="col-md-6">
|
||||||
<label class="form-label fw-semibold">Notes</label>
|
<label class="form-label-custom">Catatan / Notes</label>
|
||||||
<textarea class="form-control @error('notes') is-invalid @enderror"
|
<textarea name="notes"
|
||||||
name="notes" rows="3"
|
class="form-control-custom @error('notes') is-invalid @enderror"
|
||||||
placeholder="Enter any notes...">{{ old('notes', $transaksi->notes) }}</textarea>
|
placeholder="Catatan tambahan...">{{ old('notes', $transaksi->notes) }}</textarea>
|
||||||
@error('notes')
|
@error('notes')
|
||||||
<div class="invalid-feedback">{{ $message }}</div>
|
<div class="invalid-feedback-custom">{{ $message }}</div>
|
||||||
@enderror
|
@enderror
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{{-- Customer Information (readonly) --}}
|
<!-- Customer Information (readonly) -->
|
||||||
<div class="card shadow mb-4" style="border-radius:12px;">
|
<div class="info-card">
|
||||||
<div class="card-header py-3" style="background:#f8f9fa; border-radius:12px 12px 0 0;">
|
<div class="info-card-header">
|
||||||
<h6 class="m-0 fw-bold text-primary">
|
<div class="info-card-icon icon-purple">
|
||||||
Customer Information
|
<i class="fas fa-user"></i>
|
||||||
<small class="text-muted fw-normal ms-2" style="font-size:0.75rem;">
|
|
||||||
<i class="fas fa-lock"></i> Tidak dapat diubah
|
|
||||||
</small>
|
|
||||||
</h6>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div>
|
||||||
<div class="mb-3">
|
<h3>Customer Information</h3>
|
||||||
<label class="form-label fw-semibold">Customer Name</label>
|
<p>Informasi pembeli <span class="lock-badge"><i class="fas fa-lock"></i> Tidak dapat diubah</span></p>
|
||||||
<input type="text" class="form-control bg-light"
|
|
||||||
value="{{ $transaksi->customer_name }}" readonly>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="mb-3">
|
|
||||||
<label class="form-label fw-semibold">Phone</label>
|
|
||||||
<input type="text" class="form-control bg-light"
|
|
||||||
value="{{ $transaksi->customer_phone }}" readonly>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="info-card-body">
|
||||||
|
<div class="row g-3">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<label class="form-label-custom">Nama Customer</label>
|
||||||
|
<input type="text" class="form-control-custom" value="{{ $transaksi->customer_name }}" readonly>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<div class="mb-3">
|
<label class="form-label-custom">Telepon</label>
|
||||||
<label class="form-label fw-semibold">Email</label>
|
<input type="text" class="form-control-custom" value="{{ $transaksi->customer_phone }}" readonly>
|
||||||
<input type="text" class="form-control bg-light"
|
|
||||||
value="{{ $transaksi->customer_email ?? '-' }}" readonly>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label class="form-label-custom">Email</label>
|
||||||
|
<input type="text" class="form-control-custom" value="{{ $transaksi->customer_email ?? '-' }}" readonly>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{-- Shipping Information (readonly) --}}
|
<!-- Shipping Information (readonly) -->
|
||||||
<div class="card shadow mb-4" style="border-radius:12px;">
|
<div class="info-card">
|
||||||
<div class="card-header py-3" style="background:#f8f9fa; border-radius:12px 12px 0 0;">
|
<div class="info-card-header">
|
||||||
<h6 class="m-0 fw-bold text-primary">
|
<div class="info-card-icon icon-orange">
|
||||||
Shipping Information
|
<i class="fas fa-truck"></i>
|
||||||
<small class="text-muted fw-normal ms-2" style="font-size:0.75rem;">
|
|
||||||
<i class="fas fa-lock"></i> Tidak dapat diubah
|
|
||||||
</small>
|
|
||||||
</h6>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div>
|
||||||
<div class="mb-3">
|
<h3>Pengiriman</h3>
|
||||||
<label class="form-label fw-semibold">Shipping Address</label>
|
<p>Alamat & info pengiriman <span class="lock-badge"><i class="fas fa-lock"></i> Tidak dapat diubah</span></p>
|
||||||
<textarea class="form-control bg-light" rows="3"
|
|
||||||
readonly>{{ $transaksi->shipping_address }}</textarea>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-4">
|
|
||||||
<div class="mb-3">
|
|
||||||
<label class="form-label fw-semibold">City</label>
|
|
||||||
<input type="text" class="form-control bg-light"
|
|
||||||
value="{{ $transaksi->city }}" readonly>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="info-card-body">
|
||||||
|
<div class="row g-3">
|
||||||
|
<div class="col-12">
|
||||||
|
<label class="form-label-custom">Alamat Pengiriman</label>
|
||||||
|
<textarea class="form-control-custom" rows="3" readonly>{{ $transaksi->shipping_address }}</textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<div class="mb-3">
|
<label class="form-label-custom">Kota</label>
|
||||||
<label class="form-label fw-semibold">Province</label>
|
<input type="text" class="form-control-custom" value="{{ $transaksi->city }}" readonly>
|
||||||
<input type="text" class="form-control bg-light"
|
|
||||||
value="{{ $transaksi->province }}" readonly>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<div class="mb-3">
|
<label class="form-label-custom">Provinsi</label>
|
||||||
<label class="form-label fw-semibold">Postal Code</label>
|
<input type="text" class="form-control-custom" value="{{ $transaksi->province }}" readonly>
|
||||||
<input type="text" class="form-control bg-light"
|
|
||||||
value="{{ $transaksi->postal_code }}" readonly>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label-custom">Kode Pos</label>
|
||||||
|
<input type="text" class="form-control-custom" value="{{ $transaksi->postal_code }}" readonly>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{{-- Akhir col-lg-8 --}}
|
<!-- Akhir col-lg-8 -->
|
||||||
|
|
||||||
{{-- Kolom Kanan --}}
|
<!-- ===== KOLOM KANAN (4/12) ===== -->
|
||||||
<div class="col-lg-4">
|
<div class="col-lg-4">
|
||||||
|
|
||||||
{{-- Order Summary --}}
|
<!-- Order Summary -->
|
||||||
<div class="card shadow mb-4" style="border-radius:12px;">
|
<div class="info-card">
|
||||||
<div class="card-header py-3" style="background:#f8f9fa; border-radius:12px 12px 0 0;">
|
<div class="info-card-header">
|
||||||
<h6 class="m-0 fw-bold text-primary">Order Summary</h6>
|
<div class="info-card-icon icon-green">
|
||||||
|
<i class="fas fa-box"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div>
|
||||||
<h5 class="text-primary">{{ $transaksi->invoice_number }}</h5>
|
<h3>Order Summary</h3>
|
||||||
<p class="text-muted mb-3">{{ $transaksi->created_at->format('d M Y, H:i') }}</p>
|
<p>Ringkasan produk pesanan</p>
|
||||||
<table class="table table-sm table-borderless">
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-card-body">
|
||||||
|
<table class="summary-table">
|
||||||
<tbody>
|
<tbody>
|
||||||
@foreach($transaksi->details as $detail)
|
@foreach($transaksi->details as $detail)
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ $detail->product->name ?? 'N/A' }}</td>
|
<td>{{ $detail->product->name ?? 'N/A' }}</td>
|
||||||
<td class="text-end">x{{ $detail->quantity }}</td>
|
<td style="text-align:center;color:#9ca3af;">x{{ $detail->quantity }}</td>
|
||||||
<td class="text-end">Rp {{ number_format($detail->subtotal, 0, ',', '.') }}</td>
|
<td>Rp {{ number_format($detail->subtotal, 0, ',', '.') }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
<tfoot class="border-top">
|
<tfoot>
|
||||||
<tr>
|
<tr>
|
||||||
<th colspan="2">Total:</th>
|
<td colspan="2" style="font-size:0.8rem;color:#6b7280;">Total Amount</td>
|
||||||
<th class="text-end">Rp {{ number_format($transaksi->total_amount, 0, ',', '.') }}</th>
|
<td style="color:var(--green-main);font-size:0.95rem;">Rp {{ number_format($transaksi->total_amount, 0, ',', '.') }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tfoot>
|
</tfoot>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{-- Action Buttons --}}
|
<!-- Action Buttons -->
|
||||||
<div class="card shadow" style="border-radius:12px;">
|
<div class="info-card">
|
||||||
<div class="card-body">
|
<div class="info-card-header">
|
||||||
<button type="submit" class="btn btn-primary w-100 mb-2">
|
<div class="info-card-icon icon-gray">
|
||||||
<i class="fas fa-save me-1"></i> Update Order
|
<i class="fas fa-cog"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3>Aksi</h3>
|
||||||
|
<p>Simpan atau batalkan perubahan</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-card-body" style="display:flex;flex-direction:column;gap:10px;">
|
||||||
|
<button type="submit" form="editOrderForm"
|
||||||
|
style="width:100%;padding:10px 16px;border-radius:9px;border:none;
|
||||||
|
background:linear-gradient(135deg,var(--green-main),var(--green-dark));
|
||||||
|
color:white;font-weight:700;font-size:0.875rem;cursor:pointer;
|
||||||
|
display:flex;align-items:center;justify-content:center;gap:8px;
|
||||||
|
transition:all 0.2s;">
|
||||||
|
<i class="fas fa-save"></i> Update Order
|
||||||
</button>
|
</button>
|
||||||
<a href="{{ route('admin.transaksis.show', $transaksi->id) }}"
|
<a href="{{ route('admin.transaksis.show', $transaksi->id) }}"
|
||||||
class="btn btn-secondary w-100">
|
style="width:100%;padding:10px 16px;border-radius:9px;
|
||||||
<i class="fas fa-times me-1"></i> Cancel
|
border:1.5px solid #e5e7eb;background:#f9fafb;
|
||||||
|
color:#374151;font-weight:600;font-size:0.875rem;cursor:pointer;
|
||||||
|
display:flex;align-items:center;justify-content:center;gap:8px;
|
||||||
|
text-decoration:none;transition:all 0.2s;">
|
||||||
|
<i class="fas fa-times"></i> Batal
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{{-- Akhir col-lg-4 --}}
|
<!-- Akhir col-lg-4 -->
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
@ -364,8 +688,28 @@ class="btn btn-secondary w-100">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
<script>
|
||||||
|
function toggleSidebar() {
|
||||||
|
document.getElementById('sidebar').classList.toggle('open');
|
||||||
|
document.getElementById('sidebarOverlay').classList.toggle('show');
|
||||||
|
}
|
||||||
|
function closeSidebar() {
|
||||||
|
document.getElementById('sidebar').classList.remove('open');
|
||||||
|
document.getElementById('sidebarOverlay').classList.remove('show');
|
||||||
|
}
|
||||||
|
window.addEventListener('resize', function() {
|
||||||
|
if (window.innerWidth > 900) closeSidebar();
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
document.querySelectorAll('.alert').forEach(function(alert) {
|
||||||
|
setTimeout(function() {
|
||||||
|
const a = bootstrap.Alert.getOrCreateInstance(alert);
|
||||||
|
if (a) a.close();
|
||||||
|
}, 5000);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -6,331 +6,530 @@
|
||||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||||
<title>Kelola Pengguna - Bibit Cabai Admin</title>
|
<title>Kelola Pengguna - Bibit Cabai Admin</title>
|
||||||
|
|
||||||
<!-- Bootstrap CSS -->
|
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
|
||||||
<!-- Font Awesome -->
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--sidebar-width: 260px;
|
||||||
|
--green-dark: #15803d;
|
||||||
|
--green-main: #16a34a;
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
background: #f8f9fa;
|
background: #f1f5f2;
|
||||||
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.admin-container {
|
/* ===== SIDEBAR ===== */
|
||||||
display: flex;
|
|
||||||
min-height: 100vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sidebar */
|
|
||||||
.sidebar {
|
.sidebar {
|
||||||
width: 280px;
|
width: var(--sidebar-width);
|
||||||
background: linear-gradient(180deg, #28a745, #20c997);
|
background: linear-gradient(180deg, var(--green-dark) 0%, #14532d 100%);
|
||||||
color: white;
|
color: white;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0; left: 0;
|
||||||
left: 0;
|
z-index: 1050;
|
||||||
z-index: 1000;
|
transition: transform 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-header {
|
.sidebar-header {
|
||||||
padding: 25px 20px;
|
padding: 24px 20px 20px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border-bottom: 1px solid rgba(255,255,255,0.1);
|
border-bottom: 1px solid rgba(255,255,255,0.12);
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-header h3 {
|
.sidebar-header .brand-icon { font-size: 2rem; margin-bottom: 6px; display: block; }
|
||||||
font-size: 1.8rem;
|
.sidebar-header h3 { font-size: 1.35rem; font-weight: 700; margin-bottom: 2px; }
|
||||||
font-weight: bold;
|
.sidebar-header .subtitle { opacity: 0.65; font-size: 0.78rem; margin-bottom: 6px; }
|
||||||
margin-bottom: 5px;
|
.sidebar-header .admin-name {
|
||||||
|
display: inline-block;
|
||||||
|
background: rgba(255,255,255,0.15);
|
||||||
|
padding: 3px 12px;
|
||||||
|
border-radius: 20px;
|
||||||
|
font-size: 0.78rem;
|
||||||
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-header p { opacity: 0.8; font-size: 0.9rem; }
|
.sidebar-menu { padding: 12px 0; flex: 1; }
|
||||||
|
|
||||||
.sidebar-menu { padding: 20px 0; }
|
.menu-section-label {
|
||||||
|
font-size: 0.68rem;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
opacity: 0.45;
|
||||||
|
padding: 12px 20px 6px;
|
||||||
|
}
|
||||||
|
|
||||||
.menu-item {
|
.menu-item {
|
||||||
display: block;
|
display: flex;
|
||||||
padding: 15px 25px;
|
align-items: center;
|
||||||
color: white;
|
gap: 12px;
|
||||||
|
padding: 12px 20px;
|
||||||
|
color: rgba(255,255,255,0.82);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
transition: all 0.3s;
|
transition: all 0.2s;
|
||||||
border-left: 4px solid transparent;
|
border-left: 3px solid transparent;
|
||||||
|
font-size: 0.9rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-item:hover, .menu-item.active {
|
.menu-item i { width: 18px; font-size: 0.95rem; flex-shrink: 0; text-align: center; }
|
||||||
background: rgba(255,255,255,0.2);
|
|
||||||
|
.menu-item:hover {
|
||||||
|
background: rgba(255,255,255,0.1);
|
||||||
color: white;
|
color: white;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
border-left-color: rgba(255,255,255,0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-item.active {
|
||||||
|
background: rgba(255,255,255,0.15);
|
||||||
|
color: white;
|
||||||
border-left-color: #fff;
|
border-left-color: #fff;
|
||||||
transform: translateX(5px);
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-item i { width: 20px; margin-right: 10px; }
|
.sidebar-footer {
|
||||||
|
padding: 16px 20px;
|
||||||
|
border-top: 1px solid rgba(255,255,255,0.12);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Main Content */
|
.btn-logout {
|
||||||
|
width: 100%;
|
||||||
|
background: rgba(255,255,255,0.12);
|
||||||
|
color: white;
|
||||||
|
border: 1.5px solid rgba(255,255,255,0.3);
|
||||||
|
padding: 9px 16px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-logout:hover {
|
||||||
|
background: rgba(255,255,255,0.22);
|
||||||
|
border-color: rgba(255,255,255,0.5);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-overlay {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
background: rgba(0,0,0,0.45);
|
||||||
|
z-index: 1040;
|
||||||
|
backdrop-filter: blur(2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-overlay.show { display: block; }
|
||||||
|
|
||||||
|
/* ===== MAIN CONTENT ===== */
|
||||||
.main-content {
|
.main-content {
|
||||||
margin-left: 280px;
|
margin-left: var(--sidebar-width);
|
||||||
flex: 1;
|
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.admin-header {
|
/* ===== TOPBAR ===== */
|
||||||
|
.topbar {
|
||||||
background: white;
|
background: white;
|
||||||
padding: 20px 30px;
|
height: 64px;
|
||||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
padding: 0 24px;
|
||||||
border-bottom: 1px solid #dee2e6;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
box-shadow: 0 1px 0 #e5e7eb;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content-area { padding: 30px; }
|
.topbar-left { display: flex; align-items: center; gap: 14px; }
|
||||||
|
|
||||||
.page-header {
|
.hamburger-btn {
|
||||||
background: white;
|
display: none;
|
||||||
padding: 30px;
|
background: none;
|
||||||
border-radius: 12px;
|
border: none;
|
||||||
box-shadow: 0 4px 6px rgba(0,0,0,0.05);
|
color: #374151;
|
||||||
margin-bottom: 30px;
|
font-size: 1.25rem;
|
||||||
|
padding: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 6px;
|
||||||
|
transition: background 0.15s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.breadcrumb { background: transparent; padding: 0; margin-bottom: 10px; }
|
.hamburger-btn:hover { background: #f3f4f6; }
|
||||||
.breadcrumb-item a { color: #28a745; text-decoration: none; }
|
|
||||||
|
|
||||||
/* Stats Cards */
|
.topbar-breadcrumb { font-size: 0.8rem; color: #6b7280; margin-bottom: 2px; }
|
||||||
|
.topbar-breadcrumb a { color: var(--green-main); text-decoration: none; }
|
||||||
|
.topbar-title h2 { font-size: 1.1rem; font-weight: 700; color: #111827; margin: 0; }
|
||||||
|
.topbar-title p { font-size: 0.75rem; color: #6b7280; margin: 0; }
|
||||||
|
|
||||||
|
.btn-back-website {
|
||||||
|
background: linear-gradient(135deg, #dc2626, #b91c1c);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 9px 18px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.825rem;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 7px;
|
||||||
|
transition: all 0.2s;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-back-website:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 4px 12px rgba(220,38,38,0.35);
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== CONTENT AREA ===== */
|
||||||
|
.content-area { padding: 20px 24px 24px; flex: 1; }
|
||||||
|
|
||||||
|
/* ===== STATS GRID ===== */
|
||||||
.stats-grid {
|
.stats-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(4, 1fr);
|
grid-template-columns: repeat(4, 1fr);
|
||||||
gap: 20px;
|
gap: 16px;
|
||||||
margin-bottom: 30px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stat-card {
|
.stat-card {
|
||||||
background: white;
|
background: white;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
padding: 20px;
|
padding: 18px 16px;
|
||||||
box-shadow: 0 4px 6px rgba(0,0,0,0.05);
|
box-shadow: 0 1px 3px rgba(0,0,0,0.06), 0 4px 10px rgba(0,0,0,0.04);
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-left: 4px solid;
|
border-left: 4px solid;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stat-card.primary { border-left-color: #007bff; }
|
.stat-card.primary { border-left-color: #2563eb; }
|
||||||
.stat-card.warning { border-left-color: #ffc107; }
|
.stat-card.warning { border-left-color: #d97706; }
|
||||||
.stat-card.info { border-left-color: #17a2b8; }
|
.stat-card.success { border-left-color: var(--green-main); }
|
||||||
.stat-card.success { border-left-color: #28a745; }
|
.stat-card.info { border-left-color: #0891b2; }
|
||||||
|
|
||||||
.stat-label {
|
.stat-label {
|
||||||
font-size: 0.75rem;
|
font-size: 0.72rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
margin-bottom: 5px;
|
letter-spacing: 0.04em;
|
||||||
|
margin-bottom: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stat-card.primary .stat-label { color: #007bff; }
|
.stat-card.primary .stat-label { color: #2563eb; }
|
||||||
.stat-card.warning .stat-label { color: #ffc107; }
|
.stat-card.warning .stat-label { color: #d97706; }
|
||||||
.stat-card.info .stat-label { color: #17a2b8; }
|
.stat-card.success .stat-label { color: var(--green-main); }
|
||||||
.stat-card.success .stat-label { color: #28a745; }
|
.stat-card.info .stat-label { color: #0891b2; }
|
||||||
|
|
||||||
.stat-value { font-size: 1.5rem; font-weight: 700; color: #333; }
|
.stat-value { font-size: 1.5rem; font-weight: 800; color: #111827; }
|
||||||
.stat-icon { font-size: 2rem; color: #dee2e6; }
|
.stat-icon { font-size: 1.75rem; color: #e5e7eb; }
|
||||||
|
|
||||||
/* Section Header */
|
/* ===== TABLE CARD ===== */
|
||||||
.section-header {
|
.table-card {
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
padding-bottom: 15px;
|
|
||||||
border-bottom: 2px solid #f8f9fa;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-title { font-size: 1.3rem; font-weight: 600; color: #333; }
|
|
||||||
|
|
||||||
/* Table */
|
|
||||||
.data-table {
|
|
||||||
width: 100%;
|
|
||||||
border-collapse: collapse;
|
|
||||||
background: white;
|
background: white;
|
||||||
|
border-radius: 14px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.06), 0 4px 10px rgba(0,0,0,0.04);
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.table-card-header {
|
||||||
|
padding: 18px 20px;
|
||||||
|
border-bottom: 1px solid #f3f4f6;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #111827;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Search */
|
||||||
|
.search-bar {
|
||||||
|
padding: 14px 20px;
|
||||||
|
border-bottom: 1px solid #f3f4f6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== TABLE ===== */
|
||||||
|
.data-table { width: 100%; border-collapse: collapse; }
|
||||||
|
|
||||||
.data-table th, .data-table td {
|
.data-table th, .data-table td {
|
||||||
padding: 12px 15px;
|
padding: 11px 14px;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
border-bottom: 1px solid #dee2e6;
|
border-bottom: 1px solid #f3f4f6;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
.data-table th {
|
.data-table th {
|
||||||
background: #f8f9fa;
|
background: #f9fafb;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #495057;
|
color: #6b7280;
|
||||||
font-size: 0.85rem;
|
font-size: 0.78rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.data-table tbody tr:hover { background-color: #f8f9fc; }
|
.data-table tbody tr:hover { background: #f9fafb; }
|
||||||
|
|
||||||
/* Badges */
|
/* ===== BADGES ===== */
|
||||||
.badge-role {
|
.badge-role {
|
||||||
padding: 4px 10px;
|
padding: 4px 10px;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
font-size: 0.75rem;
|
font-size: 0.72rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.badge-admin { background: #cce5ff; color: #004085; }
|
.badge-admin { background: #dbeafe; color: #1e40af; }
|
||||||
.badge-user { background: #d4edda; color: #155724; }
|
.badge-user { background: #dcfce7; color: #166534; }
|
||||||
.badge-verified { background: #d4edda; color: #155724; }
|
.badge-verified { background: #dcfce7; color: #166534; }
|
||||||
.badge-unverified { background: #e2e3e5; color: #383d41; }
|
.badge-unverified { background: #f3f4f6; color: #6b7280; }
|
||||||
|
|
||||||
/* Action Buttons */
|
/* ===== ACTION BUTTONS ===== */
|
||||||
.btn-action {
|
.btn-action {
|
||||||
padding: 6px 10px;
|
padding: 6px 9px;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.3s;
|
transition: all 0.2s;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-action:hover {
|
.btn-action:hover {
|
||||||
transform: translateY(-1px);
|
transform: translateY(-1px);
|
||||||
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
|
box-shadow: 0 2px 6px rgba(0,0,0,0.15);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-view { background: #17a2b8; color: white; }
|
.btn-view { background: #0891b2; color: white; }
|
||||||
.btn-edit { background: #ffc107; color: #212529; }
|
.btn-edit { background: #d97706; color: white; }
|
||||||
.btn-delete { background: #dc3545; color: white; }
|
.btn-delete { background: #dc2626; color: white; }
|
||||||
|
|
||||||
/* Back Button */
|
/* ===== TABLE FOOTER ===== */
|
||||||
.back-button {
|
.table-footer {
|
||||||
position: fixed;
|
padding: 14px 20px;
|
||||||
top: 20px;
|
border-top: 1px solid #f3f4f6;
|
||||||
right: 20px;
|
display: flex;
|
||||||
z-index: 1100;
|
justify-content: space-between;
|
||||||
background: linear-gradient(45deg, #dc3545, #c82333);
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== MOBILE CARDS ===== */
|
||||||
|
.mobile-card-list { display: none; padding: 14px; }
|
||||||
|
|
||||||
|
.user-card {
|
||||||
|
background: white;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 16px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.06), 0 4px 10px rgba(0,0,0,0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-card-top {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-card-avatar {
|
||||||
|
width: 42px; height: 42px;
|
||||||
|
background: linear-gradient(135deg, var(--green-dark), var(--green-main));
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
color: white;
|
color: white;
|
||||||
border: none;
|
font-weight: 700;
|
||||||
padding: 12px 20px;
|
font-size: 1rem;
|
||||||
border-radius: 25px;
|
flex-shrink: 0;
|
||||||
font-weight: 600;
|
|
||||||
transition: all 0.3s;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.back-button:hover {
|
.user-card-name { font-weight: 700; font-size: 0.95rem; color: #111827; }
|
||||||
background: linear-gradient(45deg, #c82333, #a71e2a);
|
.user-card-email { font-size: 0.78rem; color: #9ca3af; margin-top: 2px; }
|
||||||
transform: translateY(-2px);
|
|
||||||
color: white;
|
.user-card-badges { display: flex; gap: 6px; flex-wrap: wrap; }
|
||||||
text-decoration: none;
|
|
||||||
|
.user-card-meta {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
font-size: 0.8rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fade-in {
|
.user-card-meta-item .label { color: #9ca3af; font-size: 0.7rem; text-transform: uppercase; font-weight: 600; margin-bottom: 2px; }
|
||||||
animation: fadeIn 0.3s ease-in-out;
|
.user-card-meta-item .value { color: #374151; }
|
||||||
}
|
|
||||||
|
.user-card-actions { display: flex; gap: 8px; }
|
||||||
|
.user-card-actions .btn-action { flex: 1; justify-content: center; padding: 8px; }
|
||||||
|
|
||||||
|
/* ===== FADE IN ===== */
|
||||||
|
.fade-in { animation: fadeIn 0.3s ease; }
|
||||||
|
|
||||||
@keyframes fadeIn {
|
@keyframes fadeIn {
|
||||||
from { opacity: 0; transform: translateY(10px); }
|
from { opacity: 0; transform: translateY(8px); }
|
||||||
to { opacity: 1; transform: translateY(0); }
|
to { opacity: 1; transform: translateY(0); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
/* ===== RESPONSIVE ===== */
|
||||||
.sidebar { width: 100%; position: relative; }
|
@media (max-width: 900px) {
|
||||||
|
.sidebar { transform: translateX(-100%); }
|
||||||
|
.sidebar.open { transform: translateX(0); box-shadow: 4px 0 24px rgba(0,0,0,0.2); }
|
||||||
.main-content { margin-left: 0; }
|
.main-content { margin-left: 0; }
|
||||||
|
.hamburger-btn { display: flex; align-items: center; justify-content: center; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1100px) {
|
||||||
.stats-grid { grid-template-columns: repeat(2, 1fr); }
|
.stats-grid { grid-template-columns: repeat(2, 1fr); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
.desktop-table-wrap { display: none; }
|
||||||
|
.mobile-card-list { display: block; }
|
||||||
|
.stats-grid { grid-template-columns: repeat(2, 1fr); gap: 10px; }
|
||||||
|
.content-area { padding: 14px 14px 20px; }
|
||||||
|
.topbar { padding: 0 14px; }
|
||||||
|
.btn-back-website span { display: none; }
|
||||||
|
.btn-back-website { padding: 9px 12px; }
|
||||||
|
.table-card-header { flex-direction: column; align-items: stretch; }
|
||||||
|
.table-card-header .btn { width: 100%; }
|
||||||
|
.table-footer { flex-direction: column; align-items: flex-start; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 400px) {
|
||||||
|
.stats-grid { grid-template-columns: 1fr; }
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<!-- Back Button -->
|
|
||||||
<a href="{{ route('home') }}" class="back-button">
|
|
||||||
<i class="fas fa-arrow-left me-2"></i>Kembali ke Website
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div class="admin-container">
|
<div class="sidebar-overlay" id="sidebarOverlay" onclick="closeSidebar()"></div>
|
||||||
|
|
||||||
<!-- Sidebar -->
|
<!-- Sidebar -->
|
||||||
<nav class="sidebar">
|
<nav class="sidebar" id="sidebar">
|
||||||
<div class="sidebar-header">
|
<div class="sidebar-header">
|
||||||
<h3>🌱 Bibit Cabai</h3>
|
<span class="brand-icon">🌱</span>
|
||||||
<p>Admin Dashboard</p>
|
<h3>Bibit Cabai</h3>
|
||||||
<small class="text-light">{{ Auth::user()->name ?? 'Admin User' }}</small>
|
<p class="subtitle">Admin Dashboard</p>
|
||||||
|
<span class="admin-name">{{ Auth::user()->name ?? 'Admin User' }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="sidebar-menu">
|
<div class="sidebar-menu">
|
||||||
|
<div class="menu-section-label">Menu Utama</div>
|
||||||
|
|
||||||
<a href="{{ route('admin.dashboard') }}" class="menu-item">
|
<a href="{{ route('admin.dashboard') }}" class="menu-item">
|
||||||
<i class="fas fa-tachometer-alt"></i>Dashboard
|
<i class="fas fa-tachometer-alt"></i><span>Dashboard</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('admin.products.index') }}" class="menu-item">
|
<a href="{{ route('admin.products.index') }}" class="menu-item">
|
||||||
<i class="fas fa-seedling"></i>Kelola Produk
|
<i class="fas fa-seedling"></i><span>Kelola Produk</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('admin.orders') }}" class="menu-item">
|
<a href="{{ route('admin.orders') }}" class="menu-item">
|
||||||
<i class="fas fa-shopping-cart"></i>Pesanan
|
<i class="fas fa-shopping-cart"></i><span>Pesanan</span>
|
||||||
</a>
|
</a>
|
||||||
{{-- ↓ TAMBAHKAN DI SINI ↓ --}}
|
|
||||||
<a href="{{ route('admin.cancellations') }}" class="menu-item">
|
<a href="{{ route('admin.cancellations') }}" class="menu-item">
|
||||||
<i class="fas fa-times-circle"></i>Pengajuan Batal
|
<i class="fas fa-times-circle"></i><span>Pengajuan Batal</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('admin.users') }}" class="menu-item active">
|
<a href="{{ route('admin.users') }}" class="menu-item active">
|
||||||
<i class="fas fa-users"></i>Pengguna
|
<i class="fas fa-users"></i><span>Pengguna</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('admin.laporan') }}" class="menu-item">
|
<a href="{{ route('admin.laporan') }}" class="menu-item">
|
||||||
<i class="fas fa-chart-line"></i>Laporan
|
<i class="fas fa-chart-line"></i><span>Laporan</span>
|
||||||
</a>
|
</a>
|
||||||
<!-- <a href="{{ route('admin.settings') }}" class="menu-item">
|
</div>
|
||||||
<i class="fas fa-cog"></i>Pengaturan
|
|
||||||
</a> -->
|
<div class="sidebar-footer">
|
||||||
<div class="mt-4 px-3">
|
|
||||||
<form method="POST" action="{{ route('admin.logout') }}">
|
<form method="POST" action="{{ route('admin.logout') }}">
|
||||||
@csrf
|
@csrf
|
||||||
<button type="submit" class="btn btn-outline-light btn-sm w-100">
|
<button type="submit" class="btn-logout">
|
||||||
<i class="fas fa-sign-out-alt me-2"></i>Logout
|
<i class="fas fa-sign-out-alt"></i><span>Logout</span>
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<!-- Main Content -->
|
<!-- Main Content -->
|
||||||
<div class="main-content">
|
<div class="main-content">
|
||||||
<div class="admin-header">
|
|
||||||
<nav aria-label="breadcrumb">
|
|
||||||
<ol class="breadcrumb">
|
|
||||||
<li class="breadcrumb-item">
|
|
||||||
<a href="{{ route('admin.dashboard') }}">
|
|
||||||
<i class="fas fa-home"></i> Dashboard
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="breadcrumb-item active" aria-current="page">Pengguna</li>
|
|
||||||
</ol>
|
|
||||||
</nav>
|
|
||||||
<h2>Kelola Pengguna</h2>
|
|
||||||
<p class="mb-0">Kelola semua pengguna terdaftar di sini!</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<!-- Topbar -->
|
||||||
|
<header class="topbar">
|
||||||
|
<div class="topbar-left">
|
||||||
|
<button class="hamburger-btn" onclick="toggleSidebar()" aria-label="Toggle menu">
|
||||||
|
<i class="fas fa-bars"></i>
|
||||||
|
</button>
|
||||||
|
<div class="topbar-title">
|
||||||
|
<div class="topbar-breadcrumb">
|
||||||
|
<a href="{{ route('admin.dashboard') }}"><i class="fas fa-home"></i> Dashboard</a>
|
||||||
|
/ Pengguna
|
||||||
|
</div>
|
||||||
|
<h2>Kelola Pengguna</h2>
|
||||||
|
<p>Kelola semua pengguna terdaftar di sini!</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a href="{{ route('home') }}" class="btn-back-website">
|
||||||
|
<i class="fas fa-arrow-left"></i>
|
||||||
|
<span>Kembali ke Website</span>
|
||||||
|
</a>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<!-- Content -->
|
||||||
<div class="content-area fade-in">
|
<div class="content-area fade-in">
|
||||||
|
|
||||||
@if(session('success'))
|
@if(session('success'))
|
||||||
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
<div class="alert alert-success alert-dismissible fade show mb-4" role="alert">
|
||||||
<i class="fas fa-check-circle me-2"></i>{{ session('success') }}
|
<i class="fas fa-check-circle me-2"></i>{{ session('success') }}
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@if(session('error'))
|
@if(session('error'))
|
||||||
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
<div class="alert alert-danger alert-dismissible fade show mb-4" role="alert">
|
||||||
<i class="fas fa-exclamation-circle me-2"></i>{{ session('error') }}
|
<i class="fas fa-exclamation-circle me-2"></i>{{ session('error') }}
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<!-- Stats Cards -->
|
<!-- Stats -->
|
||||||
<div class="stats-grid">
|
<div class="stats-grid">
|
||||||
<div class="stat-card primary">
|
<div class="stat-card primary">
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -362,20 +561,20 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Users Table -->
|
<!-- Table Card -->
|
||||||
<div class="page-header">
|
<div class="table-card">
|
||||||
<div class="section-header">
|
<div class="table-card-header">
|
||||||
<h3 class="section-title">
|
<div class="section-title">
|
||||||
<i class="fas fa-users text-success me-2"></i>
|
<i class="fas fa-users text-success"></i>
|
||||||
Daftar Pengguna ({{ $totalUsers ?? 0 }})
|
Daftar Pengguna ({{ $totalUsers ?? 0 }})
|
||||||
</h3>
|
</div>
|
||||||
<a href="{{ route('admin.users.create') }}" class="btn btn-primary btn-sm">
|
<a href="{{ route('admin.users.create') }}" class="btn btn-primary btn-sm">
|
||||||
<i class="fas fa-plus me-1"></i>Tambah Pengguna
|
<i class="fas fa-plus me-1"></i>Tambah Pengguna
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Search -->
|
<!-- Search -->
|
||||||
<div class="mb-3">
|
<div class="search-bar">
|
||||||
<div class="input-group" style="max-width:400px;">
|
<div class="input-group" style="max-width:400px;">
|
||||||
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
||||||
<input type="text" class="form-control" id="searchInput"
|
<input type="text" class="form-control" id="searchInput"
|
||||||
|
|
@ -384,11 +583,13 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@if(isset($users) && $users->count() > 0)
|
@if(isset($users) && $users->count() > 0)
|
||||||
<div class="table-responsive">
|
|
||||||
|
<!-- DESKTOP TABLE -->
|
||||||
|
<div class="desktop-table-wrap table-responsive">
|
||||||
<table class="data-table" id="usersTable">
|
<table class="data-table" id="usersTable">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>ID</th>
|
<th style="padding-left:20px;">ID</th>
|
||||||
<th>Nama</th>
|
<th>Nama</th>
|
||||||
<th>Email</th>
|
<th>Email</th>
|
||||||
<th>Telepon</th>
|
<th>Telepon</th>
|
||||||
|
|
@ -401,11 +602,13 @@
|
||||||
<tbody>
|
<tbody>
|
||||||
@foreach($users as $user)
|
@foreach($users as $user)
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ ($users->currentPage() - 1) * $users->perPage() + $loop->iteration }}</td>
|
<td style="padding-left:20px; color:#6b7280;">
|
||||||
<td><strong>{{ $user->name }}</strong></td>
|
{{ ($users->currentPage() - 1) * $users->perPage() + $loop->iteration }}
|
||||||
<td>{{ $user->email }}</td>
|
</td>
|
||||||
<td>{{ $user->phone ?? '-' }}</td>
|
<td><strong style="color:#111827;">{{ $user->name }}</strong></td>
|
||||||
<td><small>{{ \Illuminate\Support\Str::limit($user->address ?? '-', 30) }}</small></td>
|
<td style="color:#374151;">{{ $user->email }}</td>
|
||||||
|
<td style="color:#374151;">{{ $user->phone ?? '-' }}</td>
|
||||||
|
<td><small style="color:#6b7280;">{{ \Illuminate\Support\Str::limit($user->address ?? '-', 30) }}</small></td>
|
||||||
<td>
|
<td>
|
||||||
@if($user->is_admin == 1)
|
@if($user->is_admin == 1)
|
||||||
<span class="badge-role badge-admin">Admin</span>
|
<span class="badge-role badge-admin">Admin</span>
|
||||||
|
|
@ -449,38 +652,134 @@ class="btn-action btn-edit" title="Edit">
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- MOBILE CARD LIST -->
|
||||||
|
<div class="mobile-card-list" id="mobileUserList">
|
||||||
|
@foreach($users as $user)
|
||||||
|
<div class="user-card" data-search="{{ strtolower($user->name . ' ' . $user->email . ' ' . ($user->phone ?? '')) }}">
|
||||||
|
<div class="user-card-top">
|
||||||
|
<div class="d-flex align-items-center gap-3">
|
||||||
|
<div class="user-card-avatar">
|
||||||
|
{{ strtoupper(substr($user->name, 0, 1)) }}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="user-card-name">{{ $user->name }}</div>
|
||||||
|
<div class="user-card-email">{{ $user->email }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="user-card-badges">
|
||||||
|
@if($user->is_admin == 1)
|
||||||
|
<span class="badge-role badge-admin">Admin</span>
|
||||||
|
@else
|
||||||
|
<span class="badge-role badge-user">User</span>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="user-card-meta">
|
||||||
|
<div class="user-card-meta-item">
|
||||||
|
<div class="label">Telepon</div>
|
||||||
|
<div class="value">{{ $user->phone ?? '-' }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="user-card-meta-item">
|
||||||
|
<div class="label">Status Email</div>
|
||||||
|
<div class="value">
|
||||||
|
@if($user->email_verified_at)
|
||||||
|
<span class="badge-role badge-verified" style="font-size:0.68rem;">
|
||||||
|
<i class="fas fa-check me-1"></i>Terverifikasi
|
||||||
|
</span>
|
||||||
|
@else
|
||||||
|
<span class="badge-role badge-unverified" style="font-size:0.68rem;">Belum Verifikasi</span>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@if($user->address)
|
||||||
|
<div class="user-card-meta-item" style="grid-column:span 2;">
|
||||||
|
<div class="label">Alamat</div>
|
||||||
|
<div class="value">{{ \Illuminate\Support\Str::limit($user->address, 60) }}</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="user-card-actions">
|
||||||
|
<a href="{{ route('admin.users.show', $user) }}" class="btn-action btn-view" title="Detail">
|
||||||
|
<i class="fas fa-eye"></i>
|
||||||
|
</a>
|
||||||
|
<a href="{{ route('admin.users.edit', $user) }}" class="btn-action btn-edit" title="Edit">
|
||||||
|
<i class="fas fa-edit"></i> Edit
|
||||||
|
</a>
|
||||||
|
<form method="POST" action="{{ route('admin.users.destroy', $user) }}"
|
||||||
|
style="flex:0;"
|
||||||
|
onsubmit="return confirm('Yakin ingin menghapus pengguna ini?')">
|
||||||
|
@csrf
|
||||||
|
@method('DELETE')
|
||||||
|
<button type="submit" class="btn-action btn-delete" title="Hapus">
|
||||||
|
<i class="fas fa-trash"></i>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Pagination -->
|
<!-- Pagination -->
|
||||||
<div class="d-flex justify-content-between align-items-center mt-4">
|
<div class="table-footer">
|
||||||
<small class="text-muted">
|
<small style="color:#6b7280;">
|
||||||
Menampilkan {{ $users->firstItem() }} sampai {{ $users->lastItem() }}
|
Menampilkan {{ $users->firstItem() }}–{{ $users->lastItem() }}
|
||||||
dari {{ $users->total() }} pengguna
|
dari {{ $users->total() }} pengguna
|
||||||
</small>
|
</small>
|
||||||
<div>{{ $users->links() }}</div>
|
<div>{{ $users->links() }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@else
|
@else
|
||||||
<div class="text-center py-5">
|
<div style="text-align:center; padding:50px 20px; color:#9ca3af;">
|
||||||
<i class="fas fa-users fa-3x text-muted mb-3 d-block"></i>
|
<i class="fas fa-users" style="font-size:2.5rem; display:block; margin-bottom:12px; opacity:0.3;"></i>
|
||||||
<h5 class="text-muted">Belum ada pengguna terdaftar</h5>
|
<h5 style="color:#6b7280;">Belum ada pengguna terdaftar</h5>
|
||||||
<p class="text-muted">Mulai dengan menambahkan pengguna baru.</p>
|
<p style="font-size:0.875rem;">Mulai dengan menambahkan pengguna baru.</p>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Bootstrap JS -->
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
// Live search
|
// ===== SIDEBAR =====
|
||||||
|
function toggleSidebar() {
|
||||||
|
const sidebar = document.getElementById('sidebar');
|
||||||
|
const overlay = document.getElementById('sidebarOverlay');
|
||||||
|
sidebar.classList.toggle('open');
|
||||||
|
overlay.classList.toggle('show');
|
||||||
|
document.body.style.overflow = sidebar.classList.contains('open') ? 'hidden' : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeSidebar() {
|
||||||
|
const sidebar = document.getElementById('sidebar');
|
||||||
|
const overlay = document.getElementById('sidebarOverlay');
|
||||||
|
sidebar.classList.remove('open');
|
||||||
|
overlay.classList.remove('show');
|
||||||
|
document.body.style.overflow = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('resize', function() {
|
||||||
|
if (window.innerWidth > 900) closeSidebar();
|
||||||
|
});
|
||||||
|
|
||||||
|
// ===== LIVE SEARCH (desktop table + mobile cards) =====
|
||||||
document.getElementById('searchInput').addEventListener('keyup', function() {
|
document.getElementById('searchInput').addEventListener('keyup', function() {
|
||||||
const filter = this.value.toLowerCase();
|
const filter = this.value.toLowerCase();
|
||||||
|
|
||||||
|
// Desktop table rows
|
||||||
const rows = document.querySelectorAll('#usersTable tbody tr');
|
const rows = document.querySelectorAll('#usersTable tbody tr');
|
||||||
rows.forEach(row => {
|
rows.forEach(row => {
|
||||||
const text = row.textContent.toLowerCase();
|
row.style.display = row.textContent.toLowerCase().includes(filter) ? '' : 'none';
|
||||||
row.style.display = text.includes(filter) ? '' : 'none';
|
});
|
||||||
|
|
||||||
|
// Mobile cards
|
||||||
|
const cards = document.querySelectorAll('.user-card');
|
||||||
|
cards.forEach(card => {
|
||||||
|
const text = card.getAttribute('data-search') || card.textContent.toLowerCase();
|
||||||
|
card.style.display = text.includes(filter) ? '' : 'none';
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -4,222 +4,764 @@
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Edit Pengguna - Bibit Cabai Admin</title>
|
<title>Edit Pengguna - Bibit Cabai Admin</title>
|
||||||
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||||
<style>
|
<style>
|
||||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
body { font-family:'Segoe UI',sans-serif; background:#f8f9fa; }
|
|
||||||
.admin-container { display:flex; min-height:100vh; }
|
:root {
|
||||||
|
--sidebar-width: 260px;
|
||||||
|
--green-dark: #15803d;
|
||||||
|
--green-main: #16a34a;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
|
background: #f1f5f2;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== SIDEBAR ===== */
|
||||||
.sidebar {
|
.sidebar {
|
||||||
width:280px; background:linear-gradient(180deg,#28a745,#20c997);
|
width: var(--sidebar-width);
|
||||||
color:white; min-height:100vh; position:fixed; top:0; left:0; z-index:1000;
|
background: linear-gradient(180deg, var(--green-dark) 0%, #14532d 100%);
|
||||||
|
color: white;
|
||||||
|
min-height: 100vh;
|
||||||
|
position: fixed;
|
||||||
|
top: 0; left: 0;
|
||||||
|
z-index: 1050;
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
.sidebar-header { padding:25px 20px; text-align:center; border-bottom:1px solid rgba(255,255,255,0.1); }
|
|
||||||
.sidebar-header h3 { font-size:1.8rem; font-weight:bold; margin-bottom:5px; }
|
.sidebar-header {
|
||||||
.sidebar-menu { padding:20px 0; }
|
padding: 24px 20px 20px;
|
||||||
|
text-align: center;
|
||||||
|
border-bottom: 1px solid rgba(255,255,255,0.12);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-header .brand-icon { font-size: 2rem; margin-bottom: 6px; display: block; }
|
||||||
|
.sidebar-header h3 { font-size: 1.35rem; font-weight: 700; margin-bottom: 2px; }
|
||||||
|
.sidebar-header .subtitle { opacity: 0.65; font-size: 0.78rem; margin-bottom: 6px; }
|
||||||
|
.sidebar-header .admin-name {
|
||||||
|
display: inline-block;
|
||||||
|
background: rgba(255,255,255,0.15);
|
||||||
|
padding: 3px 12px;
|
||||||
|
border-radius: 20px;
|
||||||
|
font-size: 0.78rem;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-menu { padding: 12px 0; flex: 1; }
|
||||||
|
|
||||||
|
.menu-section-label {
|
||||||
|
font-size: 0.68rem;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
opacity: 0.45;
|
||||||
|
padding: 12px 20px 6px;
|
||||||
|
}
|
||||||
|
|
||||||
.menu-item {
|
.menu-item {
|
||||||
display:block; padding:15px 25px; color:white; text-decoration:none;
|
display: flex;
|
||||||
transition:all 0.3s; border-left:4px solid transparent;
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 12px 20px;
|
||||||
|
color: rgba(255,255,255,0.82);
|
||||||
|
text-decoration: none;
|
||||||
|
transition: all 0.2s;
|
||||||
|
border-left: 3px solid transparent;
|
||||||
|
font-size: 0.9rem;
|
||||||
}
|
}
|
||||||
.menu-item:hover, .menu-item.active {
|
|
||||||
background:rgba(255,255,255,0.2); color:white;
|
.menu-item i { width: 18px; font-size: 0.95rem; flex-shrink: 0; text-align: center; }
|
||||||
border-left-color:#fff; transform:translateX(5px);
|
|
||||||
|
.menu-item:hover {
|
||||||
|
background: rgba(255,255,255,0.1);
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
border-left-color: rgba(255,255,255,0.5);
|
||||||
}
|
}
|
||||||
.menu-item i { width:20px; margin-right:10px; }
|
|
||||||
.main-content { margin-left:280px; flex:1; }
|
.menu-item.active {
|
||||||
.admin-header { background:white; padding:20px 30px; box-shadow:0 2px 4px rgba(0,0,0,0.1); }
|
background: rgba(255,255,255,0.15);
|
||||||
.content-area { padding:30px; }
|
color: white;
|
||||||
.form-card { background:white; border-radius:12px; padding:35px; box-shadow:0 4px 6px rgba(0,0,0,0.05); max-width:700px; }
|
border-left-color: #fff;
|
||||||
.form-label { font-weight:600; color:#495057; }
|
font-weight: 600;
|
||||||
.form-control:focus { border-color:#28a745; box-shadow:0 0 0 0.2rem rgba(40,167,69,0.25); }
|
|
||||||
.btn-save { background:linear-gradient(45deg,#28a745,#20c997); border:none; color:white; padding:12px 30px; border-radius:8px; font-weight:600; }
|
|
||||||
.btn-save:hover { opacity:0.9; color:white; }
|
|
||||||
.breadcrumb { background:transparent; padding:0; margin-bottom:10px; }
|
|
||||||
.breadcrumb-item a { color:#28a745; text-decoration:none; }
|
|
||||||
.back-button {
|
|
||||||
position:fixed; top:20px; right:20px; z-index:1100;
|
|
||||||
background:linear-gradient(45deg,#dc3545,#c82333);
|
|
||||||
color:white; border:none; padding:12px 20px;
|
|
||||||
border-radius:25px; font-weight:600; text-decoration:none; transition:all 0.3s;
|
|
||||||
}
|
}
|
||||||
.back-button:hover { transform:translateY(-2px); color:white; }
|
|
||||||
.section-divider { border-top:2px solid #f8f9fa; margin:25px 0; }
|
.sidebar-footer {
|
||||||
.user-info-badge {
|
padding: 16px 20px;
|
||||||
background:#f8f9fa; border-radius:8px; padding:12px 15px;
|
border-top: 1px solid rgba(255,255,255,0.12);
|
||||||
margin-bottom:20px; font-size:0.85rem; color:#6c757d;
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-logout {
|
||||||
|
width: 100%;
|
||||||
|
background: rgba(255,255,255,0.12);
|
||||||
|
color: white;
|
||||||
|
border: 1.5px solid rgba(255,255,255,0.3);
|
||||||
|
padding: 9px 16px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-logout:hover {
|
||||||
|
background: rgba(255,255,255,0.22);
|
||||||
|
border-color: rgba(255,255,255,0.5);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-overlay {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
background: rgba(0,0,0,0.45);
|
||||||
|
z-index: 1040;
|
||||||
|
backdrop-filter: blur(2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-overlay.show { display: block; }
|
||||||
|
|
||||||
|
/* ===== MAIN CONTENT ===== */
|
||||||
|
.main-content {
|
||||||
|
margin-left: var(--sidebar-width);
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== TOPBAR ===== */
|
||||||
|
.topbar {
|
||||||
|
background: white;
|
||||||
|
height: 64px;
|
||||||
|
padding: 0 24px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
box-shadow: 0 1px 0 #e5e7eb;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topbar-left { display: flex; align-items: center; gap: 14px; }
|
||||||
|
|
||||||
|
.hamburger-btn {
|
||||||
|
display: none;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: #374151;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
padding: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 6px;
|
||||||
|
transition: background 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger-btn:hover { background: #f3f4f6; }
|
||||||
|
|
||||||
|
.topbar-breadcrumb { font-size: 0.8rem; color: #6b7280; margin-bottom: 2px; }
|
||||||
|
.topbar-breadcrumb a { color: var(--green-main); text-decoration: none; }
|
||||||
|
.topbar-breadcrumb a:hover { text-decoration: underline; }
|
||||||
|
.topbar-title h2 { font-size: 1.1rem; font-weight: 700; color: #111827; margin: 0; }
|
||||||
|
.topbar-title p { font-size: 0.75rem; color: #6b7280; margin: 0; }
|
||||||
|
|
||||||
|
.topbar-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
|
||||||
|
|
||||||
|
.btn-topbar {
|
||||||
|
border: none;
|
||||||
|
padding: 8px 14px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
transition: all 0.2s;
|
||||||
|
white-space: nowrap;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-topbar:hover { transform: translateY(-1px); text-decoration: none; }
|
||||||
|
|
||||||
|
.btn-topbar-back {
|
||||||
|
background: linear-gradient(135deg, #dc2626, #b91c1c);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-topbar-back:hover { box-shadow: 0 4px 12px rgba(220,38,38,0.35); color: white; }
|
||||||
|
|
||||||
|
.btn-topbar-save {
|
||||||
|
background: linear-gradient(135deg, var(--green-main), var(--green-dark));
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-topbar-save:hover { box-shadow: 0 4px 12px rgba(22,163,74,0.35); color: white; }
|
||||||
|
|
||||||
|
.btn-topbar-view {
|
||||||
|
background: linear-gradient(135deg, #0891b2, #0e7490);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-topbar-view:hover { box-shadow: 0 4px 12px rgba(8,145,178,0.35); color: white; }
|
||||||
|
|
||||||
|
/* ===== CONTENT AREA ===== */
|
||||||
|
.content-area { padding: 20px 24px 32px; flex: 1; }
|
||||||
|
|
||||||
|
/* ===== INFO CARD ===== */
|
||||||
|
.info-card {
|
||||||
|
background: white;
|
||||||
|
border-radius: 14px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.06), 0 4px 10px rgba(0,0,0,0.04);
|
||||||
|
overflow: hidden;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-card-header {
|
||||||
|
padding: 16px 20px;
|
||||||
|
border-bottom: 1px solid #f3f4f6;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-card-icon {
|
||||||
|
width: 34px; height: 34px;
|
||||||
|
border-radius: 9px;
|
||||||
|
display: flex; align-items: center; justify-content: center;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-blue { background: #eff6ff; color: #2563eb; }
|
||||||
|
.icon-green { background: #f0fdf4; color: var(--green-main); }
|
||||||
|
.icon-orange { background: #fff7ed; color: #ea580c; }
|
||||||
|
.icon-purple { background: #faf5ff; color: #7c3aed; }
|
||||||
|
.icon-yellow { background: #fefce8; color: #ca8a04; }
|
||||||
|
.icon-gray { background: #f3f4f6; color: #6b7280; }
|
||||||
|
.icon-red { background: #fef2f2; color: #dc2626; }
|
||||||
|
|
||||||
|
.info-card-header h3 { font-size: 0.9rem; font-weight: 700; color: #111827; margin: 0; }
|
||||||
|
.info-card-header p { font-size: 0.75rem; color: #6b7280; margin: 0; }
|
||||||
|
|
||||||
|
.info-card-body { padding: 20px; }
|
||||||
|
|
||||||
|
/* ===== SECTION DIVIDER ===== */
|
||||||
|
.section-divider {
|
||||||
|
font-size: 0.72rem;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: #9ca3af;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
border-bottom: 1px solid #f3f4f6;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== FORM STYLES ===== */
|
||||||
|
.form-label-custom {
|
||||||
|
font-size: 0.78rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #374151;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control-custom,
|
||||||
|
.form-select-custom {
|
||||||
|
font-size: 0.84rem;
|
||||||
|
padding: 8px 12px;
|
||||||
|
border: 1.5px solid #e5e7eb;
|
||||||
|
border-radius: 8px;
|
||||||
|
width: 100%;
|
||||||
|
color: #111827;
|
||||||
|
background: white;
|
||||||
|
transition: border-color 0.2s, box-shadow 0.2s;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control-custom:focus,
|
||||||
|
.form-select-custom:focus {
|
||||||
|
border-color: var(--green-main);
|
||||||
|
box-shadow: 0 0 0 3px rgba(22,163,74,0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control-custom.is-invalid,
|
||||||
|
.form-select-custom.is-invalid {
|
||||||
|
border-color: #dc2626;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea.form-control-custom { resize: vertical; min-height: 90px; }
|
||||||
|
|
||||||
|
.invalid-feedback-custom {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: #dc2626;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Password toggle */
|
||||||
|
.input-pw-wrap {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-pw-wrap .form-control-custom {
|
||||||
|
padding-right: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-pw-toggle {
|
||||||
|
position: absolute;
|
||||||
|
right: 10px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: #9ca3af;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
padding: 0;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-pw-toggle:hover { color: #374151; }
|
||||||
|
|
||||||
|
/* User info badge */
|
||||||
|
.user-meta-badge {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 10px;
|
||||||
|
background: #f9fafb;
|
||||||
|
border: 1px solid #f3f4f6;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: #6b7280;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-meta-badge span { display: flex; align-items: center; gap: 5px; }
|
||||||
|
.user-meta-badge strong { color: #111827; }
|
||||||
|
|
||||||
|
/* Checkbox custom */
|
||||||
|
.check-card {
|
||||||
|
border: 1.5px solid #e5e7eb;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 14px 16px;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: border-color 0.2s, background 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.check-card:has(input:checked) {
|
||||||
|
border-color: var(--green-main);
|
||||||
|
background: #f0fdf4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.check-card input[type="checkbox"] {
|
||||||
|
width: 17px; height: 17px;
|
||||||
|
accent-color: var(--green-main);
|
||||||
|
margin-top: 2px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.check-card-label { font-size: 0.84rem; font-weight: 600; color: #111827; }
|
||||||
|
.check-card-desc { font-size: 0.75rem; color: #6b7280; margin-top: 2px; }
|
||||||
|
.check-card-desc.text-danger { color: #dc2626 !important; }
|
||||||
|
|
||||||
|
/* ===== AVATAR MINI ===== */
|
||||||
|
.avatar-mini {
|
||||||
|
width: 44px; height: 44px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: linear-gradient(135deg, var(--green-main), var(--green-dark));
|
||||||
|
display: flex; align-items: center; justify-content: center;
|
||||||
|
font-size: 1.1rem; color: white; font-weight: 700;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== FADE IN ===== */
|
||||||
|
.fade-in { animation: fadeIn 0.3s ease; }
|
||||||
|
|
||||||
|
@keyframes fadeIn {
|
||||||
|
from { opacity: 0; transform: translateY(8px); }
|
||||||
|
to { opacity: 1; transform: translateY(0); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== RESPONSIVE ===== */
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.sidebar { transform: translateX(-100%); }
|
||||||
|
.sidebar.open { transform: translateX(0); box-shadow: 4px 0 24px rgba(0,0,0,0.2); }
|
||||||
|
.main-content { margin-left: 0; }
|
||||||
|
.hamburger-btn { display: flex; align-items: center; justify-content: center; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
.content-area { padding: 14px 14px 24px; }
|
||||||
|
.topbar { padding: 0 14px; height: auto; min-height: 58px; flex-wrap: wrap; gap: 8px; padding-top: 10px; padding-bottom: 10px; }
|
||||||
|
.topbar-actions .btn-topbar span { display: none; }
|
||||||
|
.topbar-actions .btn-topbar { padding: 8px 10px; }
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<a href="{{ route('home') }}" class="back-button">
|
<div class="sidebar-overlay" id="sidebarOverlay" onclick="closeSidebar()"></div>
|
||||||
<i class="fas fa-arrow-left me-2"></i>Kembali ke Website
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div class="admin-container">
|
<!-- ===== SIDEBAR ===== -->
|
||||||
<nav class="sidebar">
|
<nav class="sidebar" id="sidebar">
|
||||||
<div class="sidebar-header">
|
<div class="sidebar-header">
|
||||||
<h3>🌱 Bibit Cabai</h3>
|
<span class="brand-icon">🌱</span>
|
||||||
<p>Admin Dashboard</p>
|
<h3>Bibit Cabai</h3>
|
||||||
<small class="text-light">{{ Auth::user()->name ?? 'Admin' }}</small>
|
<p class="subtitle">Admin Dashboard</p>
|
||||||
|
<span class="admin-name">{{ Auth::user()->name ?? 'Admin User' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="sidebar-menu">
|
<div class="sidebar-menu">
|
||||||
<a href="{{ route('admin.dashboard') }}" class="menu-item"><i class="fas fa-tachometer-alt"></i>Dashboard</a>
|
<div class="menu-section-label">Menu Utama</div>
|
||||||
<a href="{{ route('admin.products.index') }}" class="menu-item"><i class="fas fa-seedling"></i>Kelola Produk</a>
|
<a href="{{ route('admin.dashboard') }}" class="menu-item">
|
||||||
<a href="{{ route('admin.orders') }}" class="menu-item"><i class="fas fa-shopping-cart"></i>Pesanan</a>
|
<i class="fas fa-tachometer-alt"></i><span>Dashboard</span>
|
||||||
<a href="{{ route('admin.users') }}" class="menu-item active"><i class="fas fa-users"></i>Pengguna</a>
|
</a>
|
||||||
<a href="{{ route('admin.reports') }}" class="menu-item"><i class="fas fa-chart-line"></i>Laporan</a>
|
<a href="{{ route('admin.products.index') }}" class="menu-item">
|
||||||
<!-- <a href="{{ route('admin.settings') }}" class="menu-item"><i class="fas fa-cog"></i>Pengaturan</a> -->
|
<i class="fas fa-seedling"></i><span>Kelola Produk</span>
|
||||||
<div class="mt-4 px-3">
|
</a>
|
||||||
|
<a href="{{ route('admin.orders') }}" class="menu-item">
|
||||||
|
<i class="fas fa-shopping-cart"></i><span>Pesanan</span>
|
||||||
|
</a>
|
||||||
|
<a href="{{ route('admin.cancellations') }}" class="menu-item">
|
||||||
|
<i class="fas fa-times-circle"></i><span>Pengajuan Batal</span>
|
||||||
|
</a>
|
||||||
|
<a href="{{ route('admin.users') }}" class="menu-item active">
|
||||||
|
<i class="fas fa-users"></i><span>Pengguna</span>
|
||||||
|
</a>
|
||||||
|
<a href="{{ route('admin.laporan') }}" class="menu-item">
|
||||||
|
<i class="fas fa-chart-line"></i><span>Laporan</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="sidebar-footer">
|
||||||
<form method="POST" action="{{ route('admin.logout') }}">
|
<form method="POST" action="{{ route('admin.logout') }}">
|
||||||
@csrf
|
@csrf
|
||||||
<button type="submit" class="btn btn-outline-light btn-sm w-100">
|
<button type="submit" class="btn-logout">
|
||||||
<i class="fas fa-sign-out-alt me-2"></i>Logout
|
<i class="fas fa-sign-out-alt"></i><span>Logout</span>
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
<!-- ===== MAIN ===== -->
|
||||||
<div class="main-content">
|
<div class="main-content">
|
||||||
<div class="admin-header">
|
|
||||||
<nav aria-label="breadcrumb">
|
<!-- Topbar -->
|
||||||
<ol class="breadcrumb">
|
<header class="topbar">
|
||||||
<li class="breadcrumb-item"><a href="{{ route('admin.dashboard') }}"><i class="fas fa-home"></i> Dashboard</a></li>
|
<div class="topbar-left">
|
||||||
<li class="breadcrumb-item"><a href="{{ route('admin.users') }}">Pengguna</a></li>
|
<button class="hamburger-btn" onclick="toggleSidebar()">
|
||||||
<li class="breadcrumb-item active">Edit Pengguna</li>
|
<i class="fas fa-bars"></i>
|
||||||
</ol>
|
</button>
|
||||||
</nav>
|
<div class="topbar-title">
|
||||||
|
<div class="topbar-breadcrumb">
|
||||||
|
<a href="{{ route('admin.dashboard') }}"><i class="fas fa-home"></i> Dashboard</a>
|
||||||
|
/ <a href="{{ route('admin.users') }}">Pengguna</a>
|
||||||
|
/ <a href="{{ route('admin.users.show', $user) }}">{{ $user->name }}</a>
|
||||||
|
/ Edit
|
||||||
|
</div>
|
||||||
<h2>Edit Pengguna</h2>
|
<h2>Edit Pengguna</h2>
|
||||||
<p class="mb-0">Perbarui informasi pengguna <strong>{{ $user->name }}</strong>.</p>
|
<p>{{ $user->name }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="content-area">
|
|
||||||
<div class="form-card">
|
|
||||||
|
|
||||||
<div class="user-info-badge">
|
|
||||||
<i class="fas fa-info-circle me-2 text-info"></i>
|
|
||||||
ID Pengguna: <strong>#{{ $user->id }}</strong> |
|
|
||||||
Terdaftar: <strong>{{ $user->created_at->format('d M Y') }}</strong>
|
|
||||||
@if($user->email_verified_at)
|
|
||||||
| <span class="text-success"><i class="fas fa-check-circle"></i> Email Terverifikasi</span>
|
|
||||||
@else
|
|
||||||
| <span class="text-muted"><i class="fas fa-clock"></i> Belum Verifikasi</span>
|
|
||||||
@endif
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="topbar-actions">
|
||||||
|
<a href="{{ route('admin.users') }}" class="btn-topbar btn-topbar-back">
|
||||||
|
<i class="fas fa-arrow-left"></i>
|
||||||
|
<span>Kembali</span>
|
||||||
|
</a>
|
||||||
|
<a href="{{ route('admin.users.show', $user) }}" class="btn-topbar btn-topbar-view">
|
||||||
|
<i class="fas fa-eye"></i>
|
||||||
|
<span>Lihat Detail</span>
|
||||||
|
</a>
|
||||||
|
<button type="submit" form="editUserForm" class="btn-topbar btn-topbar-save">
|
||||||
|
<i class="fas fa-save"></i>
|
||||||
|
<span>Simpan</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<!-- Content -->
|
||||||
|
<div class="content-area fade-in">
|
||||||
|
|
||||||
@if ($errors->any())
|
@if ($errors->any())
|
||||||
<div class="alert alert-danger">
|
<div class="alert alert-danger alert-dismissible fade show mb-4" role="alert">
|
||||||
<ul class="mb-0">
|
<i class="fas fa-exclamation-circle me-2"></i><strong>Error!</strong>
|
||||||
|
<ul class="mb-0 mt-1">
|
||||||
@foreach ($errors->all() as $error)
|
@foreach ($errors->all() as $error)
|
||||||
<li>{{ $error }}</li>
|
<li style="font-size:0.85rem;">{{ $error }}</li>
|
||||||
@endforeach
|
@endforeach
|
||||||
</ul>
|
</ul>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<form method="POST" action="{{ route('admin.users.update', $user) }}">
|
@if(session('success'))
|
||||||
|
<div class="alert alert-success alert-dismissible fade show mb-4" role="alert">
|
||||||
|
<i class="fas fa-check-circle me-2"></i>{{ session('success') }}
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<form id="editUserForm" method="POST" action="{{ route('admin.users.update', $user) }}">
|
||||||
@csrf
|
@csrf
|
||||||
@method('PUT')
|
@method('PUT')
|
||||||
|
|
||||||
<h5 class="mb-3 text-success"><i class="fas fa-user me-2"></i>Informasi Dasar</h5>
|
<div class="row g-3">
|
||||||
|
|
||||||
<div class="mb-3">
|
<!-- ===== KOLOM KIRI (8/12) ===== -->
|
||||||
<label class="form-label">Nama Lengkap <span class="text-danger">*</span></label>
|
<div class="col-lg-8">
|
||||||
<input type="text" name="name" class="form-control @error('name') is-invalid @enderror"
|
|
||||||
|
<!-- Informasi Dasar -->
|
||||||
|
<div class="info-card">
|
||||||
|
<div class="info-card-header">
|
||||||
|
<div class="info-card-icon icon-blue">
|
||||||
|
<i class="fas fa-user"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3>Informasi Dasar</h3>
|
||||||
|
<p>Nama, email, dan password pengguna</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-card-body">
|
||||||
|
|
||||||
|
<!-- User meta badge -->
|
||||||
|
<div class="user-meta-badge">
|
||||||
|
<span><i class="fas fa-hashtag" style="color:var(--green-main)"></i> ID: <strong>#{{ $user->id }}</strong></span>
|
||||||
|
<span><i class="fas fa-calendar" style="color:var(--green-main)"></i> Terdaftar: <strong>{{ $user->created_at->format('d M Y') }}</strong></span>
|
||||||
|
<span>
|
||||||
|
@if($user->email_verified_at)
|
||||||
|
<i class="fas fa-check-circle" style="color:#16a34a"></i> <strong style="color:#16a34a">Email Terverifikasi</strong>
|
||||||
|
@else
|
||||||
|
<i class="fas fa-clock" style="color:#9ca3af"></i> <span style="color:#9ca3af">Belum Verifikasi</span>
|
||||||
|
@endif
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row g-3">
|
||||||
|
<div class="col-12">
|
||||||
|
<label class="form-label-custom">Nama Lengkap <span style="color:#dc2626">*</span></label>
|
||||||
|
<input type="text" name="name"
|
||||||
|
class="form-control-custom @error('name') is-invalid @enderror"
|
||||||
value="{{ old('name', $user->name) }}" required>
|
value="{{ old('name', $user->name) }}" required>
|
||||||
@error('name')<div class="invalid-feedback">{{ $message }}</div>@enderror
|
@error('name')<div class="invalid-feedback-custom">{{ $message }}</div>@enderror
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-12">
|
||||||
<div class="mb-3">
|
<label class="form-label-custom">Email <span style="color:#dc2626">*</span></label>
|
||||||
<label class="form-label">Email <span class="text-danger">*</span></label>
|
<input type="email" name="email"
|
||||||
<input type="email" name="email" class="form-control @error('email') is-invalid @enderror"
|
class="form-control-custom @error('email') is-invalid @enderror"
|
||||||
value="{{ old('email', $user->email) }}" required>
|
value="{{ old('email', $user->email) }}" required>
|
||||||
@error('email')<div class="invalid-feedback">{{ $message }}</div>@enderror
|
@error('email')<div class="invalid-feedback-custom">{{ $message }}</div>@enderror
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="section-divider mt-4">Ganti Password</div>
|
||||||
<div class="col-md-6 mb-3">
|
<p style="font-size:0.78rem;color:#9ca3af;margin-bottom:14px;">Kosongkan jika tidak ingin mengganti password.</p>
|
||||||
<label class="form-label">Password Baru</label>
|
|
||||||
<div class="input-group">
|
<div class="row g-3">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label class="form-label-custom">Password Baru</label>
|
||||||
|
<div class="input-pw-wrap">
|
||||||
<input type="password" name="password" id="password"
|
<input type="password" name="password" id="password"
|
||||||
class="form-control @error('password') is-invalid @enderror"
|
class="form-control-custom @error('password') is-invalid @enderror"
|
||||||
placeholder="Minimal 8 karakter">
|
placeholder="Minimal 8 karakter">
|
||||||
<button type="button" class="btn btn-outline-secondary" onclick="togglePassword('password', 'eye1')">
|
<button type="button" class="btn-pw-toggle" onclick="togglePassword('password','eye1')">
|
||||||
<i class="fas fa-eye" id="eye1"></i>
|
<i class="fas fa-eye" id="eye1"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@error('password')<div class="text-danger small mt-1">{{ $message }}</div>@enderror
|
@error('password')<div class="invalid-feedback-custom">{{ $message }}</div>@enderror
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6 mb-3">
|
<div class="col-md-6">
|
||||||
<label class="form-label">Konfirmasi Password Baru</label>
|
<label class="form-label-custom">Konfirmasi Password Baru</label>
|
||||||
<div class="input-group">
|
<div class="input-pw-wrap">
|
||||||
<input type="password" name="password_confirmation" id="password_confirmation"
|
<input type="password" name="password_confirmation" id="password_confirmation"
|
||||||
class="form-control"
|
class="form-control-custom"
|
||||||
placeholder="Ulangi password baru">
|
placeholder="Ulangi password baru">
|
||||||
<button type="button" class="btn btn-outline-secondary" onclick="togglePassword('password_confirmation', 'eye2')">
|
<button type="button" class="btn-pw-toggle" onclick="togglePassword('password_confirmation','eye2')">
|
||||||
<i class="fas fa-eye" id="eye2"></i>
|
<i class="fas fa-eye" id="eye2"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="section-divider"></div>
|
</div>
|
||||||
<h5 class="mb-3 text-success"><i class="fas fa-address-card me-2"></i>Informasi Tambahan</h5>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<!-- Informasi Tambahan -->
|
||||||
<label class="form-label">Nomor Telepon</label>
|
<div class="info-card">
|
||||||
|
<div class="info-card-header">
|
||||||
|
<div class="info-card-icon icon-orange">
|
||||||
|
<i class="fas fa-address-card"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3>Informasi Tambahan</h3>
|
||||||
|
<p>Telepon dan alamat pengguna</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-card-body">
|
||||||
|
<div class="row g-3">
|
||||||
|
<div class="col-12">
|
||||||
|
<label class="form-label-custom">Nomor Telepon</label>
|
||||||
<input type="text" name="phone"
|
<input type="text" name="phone"
|
||||||
value="{{ old('phone', '+62') }}"
|
class="form-control-custom @error('phone') is-invalid @enderror"
|
||||||
|
value="{{ old('phone', $user->phone ?? '+62') }}"
|
||||||
placeholder="+62812xxxxxxxx">
|
placeholder="+62812xxxxxxxx">
|
||||||
@error('phone')<div class="invalid-feedback">{{ $message }}</div>@enderror
|
@error('phone')<div class="invalid-feedback-custom">{{ $message }}</div>@enderror
|
||||||
|
</div>
|
||||||
|
<div class="col-12">
|
||||||
|
<label class="form-label-custom">Alamat</label>
|
||||||
|
<textarea name="address"
|
||||||
|
class="form-control-custom @error('address') is-invalid @enderror"
|
||||||
|
rows="4">{{ old('address', $user->address) }}</textarea>
|
||||||
|
@error('address')<div class="invalid-feedback-custom">{{ $message }}</div>@enderror
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<!-- Hak Akses -->
|
||||||
<label class="form-label">Alamat</label>
|
<div class="info-card">
|
||||||
<textarea name="address" class="form-control @error('address') is-invalid @enderror"
|
<div class="info-card-header">
|
||||||
rows="4" style="min-height: 100px; resize: vertical;">{{ old('address', $user->address) }}</textarea>
|
<div class="info-card-icon icon-purple">
|
||||||
@error('address')<div class="invalid-feedback">{{ $message }}</div>@enderror
|
<i class="fas fa-shield-alt"></i>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
<div class="section-divider"></div>
|
<h3>Hak Akses</h3>
|
||||||
<h5 class="mb-3 text-success"><i class="fas fa-shield-alt me-2"></i>Hak Akses</h5>
|
<p>Role dan izin pengguna</p>
|
||||||
|
</div>
|
||||||
<div class="mb-4">
|
</div>
|
||||||
<div class="form-check">
|
<div class="info-card-body">
|
||||||
<input class="form-check-input" type="checkbox" name="is_admin" id="is_admin"
|
<label class="check-card" for="is_admin">
|
||||||
|
<input class="form-check-input" type="checkbox"
|
||||||
|
name="is_admin" id="is_admin"
|
||||||
{{ old('is_admin', $user->is_admin) ? 'checked' : '' }}
|
{{ old('is_admin', $user->is_admin) ? 'checked' : '' }}
|
||||||
{{ $user->id === auth()->id() ? 'disabled' : '' }}>
|
{{ $user->id === auth()->id() ? 'disabled' : '' }}>
|
||||||
<label class="form-check-label" for="is_admin">
|
<div>
|
||||||
<strong>Jadikan Admin</strong>
|
<div class="check-card-label"><i class="fas fa-shield-alt me-1" style="color:var(--green-main)"></i> Jadikan Admin</div>
|
||||||
@if($user->id === auth()->id())
|
@if($user->id === auth()->id())
|
||||||
<small class="text-danger d-block">Anda tidak dapat mengubah role akun sendiri.</small>
|
<div class="check-card-desc text-danger">Anda tidak dapat mengubah role akun sendiri.</div>
|
||||||
@else
|
@else
|
||||||
<small class="text-muted d-block">Admin memiliki akses penuh ke dashboard.</small>
|
<div class="check-card-desc">Admin memiliki akses penuh ke seluruh dashboard.</div>
|
||||||
@endif
|
@endif
|
||||||
|
</div>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="d-flex gap-2">
|
</div>
|
||||||
<button type="submit" class="btn btn-save">
|
<!-- Akhir col-lg-8 -->
|
||||||
<i class="fas fa-save me-2"></i>Simpan Perubahan
|
|
||||||
|
<!-- ===== KOLOM KANAN (4/12) ===== -->
|
||||||
|
<div class="col-lg-4">
|
||||||
|
|
||||||
|
<!-- User Profile Card -->
|
||||||
|
<div class="info-card">
|
||||||
|
<div class="info-card-header">
|
||||||
|
<div class="info-card-icon icon-green">
|
||||||
|
<i class="fas fa-id-card"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3>Profil Pengguna</h3>
|
||||||
|
<p>Ringkasan akun</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-card-body" style="text-align:center;">
|
||||||
|
<div style="width:64px;height:64px;border-radius:50%;
|
||||||
|
background:linear-gradient(135deg,var(--green-main),var(--green-dark));
|
||||||
|
display:flex;align-items:center;justify-content:center;
|
||||||
|
font-size:1.5rem;color:white;font-weight:700;
|
||||||
|
margin:0 auto 12px;">
|
||||||
|
{{ strtoupper(substr($user->name, 0, 1)) }}
|
||||||
|
</div>
|
||||||
|
<div style="font-weight:700;color:#111827;font-size:0.95rem;margin-bottom:4px;">{{ $user->name }}</div>
|
||||||
|
<div style="font-size:0.78rem;color:#6b7280;margin-bottom:12px;">{{ $user->email }}</div>
|
||||||
|
<div style="display:inline-flex;align-items:center;gap:6px;
|
||||||
|
padding:4px 12px;border-radius:20px;font-size:0.75rem;font-weight:700;
|
||||||
|
{{ $user->is_admin ? 'background:#dbeafe;color:#1e40af;' : 'background:#dcfce7;color:#14532d;' }}">
|
||||||
|
<i class="fas {{ $user->is_admin ? 'fa-shield-alt' : 'fa-user' }}"></i>
|
||||||
|
{{ $user->is_admin ? 'Admin' : 'User' }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Action Buttons -->
|
||||||
|
<div class="info-card">
|
||||||
|
<div class="info-card-header">
|
||||||
|
<div class="info-card-icon icon-gray">
|
||||||
|
<i class="fas fa-cog"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3>Aksi</h3>
|
||||||
|
<p>Simpan atau batalkan perubahan</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-card-body" style="display:flex;flex-direction:column;gap:10px;">
|
||||||
|
<button type="submit" form="editUserForm"
|
||||||
|
style="width:100%;padding:10px 16px;border-radius:9px;border:none;
|
||||||
|
background:linear-gradient(135deg,var(--green-main),var(--green-dark));
|
||||||
|
color:white;font-weight:700;font-size:0.875rem;cursor:pointer;
|
||||||
|
display:flex;align-items:center;justify-content:center;gap:8px;
|
||||||
|
transition:all 0.2s;">
|
||||||
|
<i class="fas fa-save"></i> Simpan Perubahan
|
||||||
</button>
|
</button>
|
||||||
<a href="{{ route('admin.users') }}" class="btn btn-outline-secondary">
|
<a href="{{ route('admin.users.show', $user) }}"
|
||||||
<i class="fas fa-times me-2"></i>Batal
|
style="width:100%;padding:10px 16px;border-radius:9px;
|
||||||
|
border:1.5px solid #bfdbfe;background:#eff6ff;
|
||||||
|
color:#2563eb;font-weight:600;font-size:0.875rem;
|
||||||
|
display:flex;align-items:center;justify-content:center;gap:8px;
|
||||||
|
text-decoration:none;transition:all 0.2s;">
|
||||||
|
<i class="fas fa-eye"></i> Lihat Detail
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('admin.users.show', $user) }}" class="btn btn-outline-info ms-auto">
|
<a href="{{ route('admin.users') }}"
|
||||||
<i class="fas fa-eye me-2"></i>Lihat Detail
|
style="width:100%;padding:10px 16px;border-radius:9px;
|
||||||
|
border:1.5px solid #e5e7eb;background:#f9fafb;
|
||||||
|
color:#374151;font-weight:600;font-size:0.875rem;
|
||||||
|
display:flex;align-items:center;justify-content:center;gap:8px;
|
||||||
|
text-decoration:none;transition:all 0.2s;">
|
||||||
|
<i class="fas fa-times"></i> Batal
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!-- Akhir col-lg-4 -->
|
||||||
|
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
|
function toggleSidebar() {
|
||||||
|
document.getElementById('sidebar').classList.toggle('open');
|
||||||
|
document.getElementById('sidebarOverlay').classList.toggle('show');
|
||||||
|
}
|
||||||
|
function closeSidebar() {
|
||||||
|
document.getElementById('sidebar').classList.remove('open');
|
||||||
|
document.getElementById('sidebarOverlay').classList.remove('show');
|
||||||
|
}
|
||||||
|
window.addEventListener('resize', function() {
|
||||||
|
if (window.innerWidth > 900) closeSidebar();
|
||||||
|
});
|
||||||
|
|
||||||
function togglePassword(fieldId, iconId) {
|
function togglePassword(fieldId, iconId) {
|
||||||
const field = document.getElementById(fieldId);
|
const field = document.getElementById(fieldId);
|
||||||
const icon = document.getElementById(iconId);
|
const icon = document.getElementById(iconId);
|
||||||
|
|
@ -231,6 +773,15 @@ function togglePassword(fieldId, iconId) {
|
||||||
icon.classList.replace('fa-eye-slash', 'fa-eye');
|
icon.classList.replace('fa-eye-slash', 'fa-eye');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
document.querySelectorAll('.alert').forEach(function(alert) {
|
||||||
|
setTimeout(function() {
|
||||||
|
const a = bootstrap.Alert.getOrCreateInstance(alert);
|
||||||
|
if (a) a.close();
|
||||||
|
}, 5000);
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
@ -4,180 +4,679 @@
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Detail Pengguna - Bibit Cabai Admin</title>
|
<title>Detail Pengguna - Bibit Cabai Admin</title>
|
||||||
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||||
<style>
|
<style>
|
||||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
body { font-family:'Segoe UI',sans-serif; background:#f8f9fa; }
|
|
||||||
.admin-container { display:flex; min-height:100vh; }
|
:root {
|
||||||
|
--sidebar-width: 260px;
|
||||||
|
--green-dark: #15803d;
|
||||||
|
--green-main: #16a34a;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
|
background: #f1f5f2;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== SIDEBAR ===== */
|
||||||
.sidebar {
|
.sidebar {
|
||||||
width:280px; background:linear-gradient(180deg,#28a745,#20c997);
|
width: var(--sidebar-width);
|
||||||
color:white; min-height:100vh; position:fixed; top:0; left:0; z-index:1000;
|
background: linear-gradient(180deg, var(--green-dark) 0%, #14532d 100%);
|
||||||
|
color: white;
|
||||||
|
min-height: 100vh;
|
||||||
|
position: fixed;
|
||||||
|
top: 0; left: 0;
|
||||||
|
z-index: 1050;
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
.sidebar-header { padding:25px 20px; text-align:center; border-bottom:1px solid rgba(255,255,255,0.1); }
|
|
||||||
.sidebar-header h3 { font-size:1.8rem; font-weight:bold; margin-bottom:5px; }
|
.sidebar-header {
|
||||||
.sidebar-menu { padding:20px 0; }
|
padding: 24px 20px 20px;
|
||||||
|
text-align: center;
|
||||||
|
border-bottom: 1px solid rgba(255,255,255,0.12);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-header .brand-icon { font-size: 2rem; margin-bottom: 6px; display: block; }
|
||||||
|
.sidebar-header h3 { font-size: 1.35rem; font-weight: 700; margin-bottom: 2px; }
|
||||||
|
.sidebar-header .subtitle { opacity: 0.65; font-size: 0.78rem; margin-bottom: 6px; }
|
||||||
|
.sidebar-header .admin-name {
|
||||||
|
display: inline-block;
|
||||||
|
background: rgba(255,255,255,0.15);
|
||||||
|
padding: 3px 12px;
|
||||||
|
border-radius: 20px;
|
||||||
|
font-size: 0.78rem;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-menu { padding: 12px 0; flex: 1; }
|
||||||
|
|
||||||
|
.menu-section-label {
|
||||||
|
font-size: 0.68rem;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
opacity: 0.45;
|
||||||
|
padding: 12px 20px 6px;
|
||||||
|
}
|
||||||
|
|
||||||
.menu-item {
|
.menu-item {
|
||||||
display:block; padding:15px 25px; color:white; text-decoration:none;
|
display: flex;
|
||||||
transition:all 0.3s; border-left:4px solid transparent;
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 12px 20px;
|
||||||
|
color: rgba(255,255,255,0.82);
|
||||||
|
text-decoration: none;
|
||||||
|
transition: all 0.2s;
|
||||||
|
border-left: 3px solid transparent;
|
||||||
|
font-size: 0.9rem;
|
||||||
}
|
}
|
||||||
.menu-item:hover, .menu-item.active {
|
|
||||||
background:rgba(255,255,255,0.2); color:white;
|
.menu-item i { width: 18px; font-size: 0.95rem; flex-shrink: 0; text-align: center; }
|
||||||
border-left-color:#fff; transform:translateX(5px);
|
|
||||||
|
.menu-item:hover {
|
||||||
|
background: rgba(255,255,255,0.1);
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
border-left-color: rgba(255,255,255,0.5);
|
||||||
}
|
}
|
||||||
.menu-item i { width:20px; margin-right:10px; }
|
|
||||||
.main-content { margin-left:280px; flex:1; }
|
.menu-item.active {
|
||||||
.admin-header { background:white; padding:20px 30px; box-shadow:0 2px 4px rgba(0,0,0,0.1); }
|
background: rgba(255,255,255,0.15);
|
||||||
.content-area { padding:30px; }
|
color: white;
|
||||||
.detail-card { background:white; border-radius:12px; padding:35px; box-shadow:0 4px 6px rgba(0,0,0,0.05); max-width:700px; }
|
border-left-color: #fff;
|
||||||
.avatar-circle {
|
font-weight: 600;
|
||||||
width:80px; height:80px; border-radius:50%;
|
}
|
||||||
background:linear-gradient(135deg,#28a745,#20c997);
|
|
||||||
|
.sidebar-footer {
|
||||||
|
padding: 16px 20px;
|
||||||
|
border-top: 1px solid rgba(255,255,255,0.12);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-logout {
|
||||||
|
width: 100%;
|
||||||
|
background: rgba(255,255,255,0.12);
|
||||||
|
color: white;
|
||||||
|
border: 1.5px solid rgba(255,255,255,0.3);
|
||||||
|
padding: 9px 16px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-logout:hover {
|
||||||
|
background: rgba(255,255,255,0.22);
|
||||||
|
border-color: rgba(255,255,255,0.5);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-overlay {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
background: rgba(0,0,0,0.45);
|
||||||
|
z-index: 1040;
|
||||||
|
backdrop-filter: blur(2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-overlay.show { display: block; }
|
||||||
|
|
||||||
|
/* ===== MAIN CONTENT ===== */
|
||||||
|
.main-content {
|
||||||
|
margin-left: var(--sidebar-width);
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== TOPBAR ===== */
|
||||||
|
.topbar {
|
||||||
|
background: white;
|
||||||
|
height: 64px;
|
||||||
|
padding: 0 24px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
box-shadow: 0 1px 0 #e5e7eb;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topbar-left { display: flex; align-items: center; gap: 14px; }
|
||||||
|
|
||||||
|
.hamburger-btn {
|
||||||
|
display: none;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: #374151;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
padding: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 6px;
|
||||||
|
transition: background 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hamburger-btn:hover { background: #f3f4f6; }
|
||||||
|
|
||||||
|
.topbar-breadcrumb { font-size: 0.8rem; color: #6b7280; margin-bottom: 2px; }
|
||||||
|
.topbar-breadcrumb a { color: var(--green-main); text-decoration: none; }
|
||||||
|
.topbar-breadcrumb a:hover { text-decoration: underline; }
|
||||||
|
.topbar-title h2 { font-size: 1.1rem; font-weight: 700; color: #111827; margin: 0; }
|
||||||
|
.topbar-title p { font-size: 0.75rem; color: #6b7280; margin: 0; }
|
||||||
|
|
||||||
|
.topbar-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
|
||||||
|
|
||||||
|
.btn-topbar {
|
||||||
|
border: none;
|
||||||
|
padding: 8px 14px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
transition: all 0.2s;
|
||||||
|
white-space: nowrap;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-topbar:hover { transform: translateY(-1px); text-decoration: none; }
|
||||||
|
|
||||||
|
.btn-topbar-back {
|
||||||
|
background: linear-gradient(135deg, #dc2626, #b91c1c);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-topbar-back:hover { box-shadow: 0 4px 12px rgba(220,38,38,0.35); color: white; }
|
||||||
|
|
||||||
|
.btn-topbar-edit {
|
||||||
|
background: linear-gradient(135deg, #ca8a04, #a16207);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-topbar-edit:hover { box-shadow: 0 4px 12px rgba(202,138,4,0.35); color: white; }
|
||||||
|
|
||||||
|
.btn-topbar-delete {
|
||||||
|
background: #fef2f2;
|
||||||
|
color: #dc2626;
|
||||||
|
border: 1.5px solid #fecaca;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-topbar-delete:hover { background: #fee2e2; color: #dc2626; }
|
||||||
|
|
||||||
|
/* ===== CONTENT AREA ===== */
|
||||||
|
.content-area { padding: 20px 24px 32px; flex: 1; }
|
||||||
|
|
||||||
|
/* ===== INFO CARD ===== */
|
||||||
|
.info-card {
|
||||||
|
background: white;
|
||||||
|
border-radius: 14px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.06), 0 4px 10px rgba(0,0,0,0.04);
|
||||||
|
overflow: hidden;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-card-header {
|
||||||
|
padding: 16px 20px;
|
||||||
|
border-bottom: 1px solid #f3f4f6;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-card-icon {
|
||||||
|
width: 34px; height: 34px;
|
||||||
|
border-radius: 9px;
|
||||||
display: flex; align-items: center; justify-content: center;
|
display: flex; align-items: center; justify-content: center;
|
||||||
font-size:2rem; color:white; font-weight:bold; margin-bottom:15px;
|
font-size: 0.9rem;
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
.info-row { display:flex; padding:14px 0; border-bottom:1px solid #f8f9fa; }
|
|
||||||
.info-row:last-child { border-bottom:none; }
|
.icon-blue { background: #eff6ff; color: #2563eb; }
|
||||||
.info-label { width:160px; font-weight:600; color:#6c757d; font-size:0.9rem; flex-shrink:0; }
|
.icon-green { background: #f0fdf4; color: var(--green-main); }
|
||||||
.info-value { color:#333; flex:1; }
|
.icon-orange { background: #fff7ed; color: #ea580c; }
|
||||||
.badge-role { padding:5px 12px; border-radius:12px; font-size:0.8rem; font-weight:600; }
|
.icon-purple { background: #faf5ff; color: #7c3aed; }
|
||||||
.badge-admin { background:#cce5ff; color:#004085; }
|
.icon-yellow { background: #fefce8; color: #ca8a04; }
|
||||||
.badge-user { background:#d4edda; color:#155724; }
|
.icon-gray { background: #f3f4f6; color: #6b7280; }
|
||||||
.badge-verified { background:#d4edda; color:#155724; }
|
|
||||||
.badge-unverified { background:#e2e3e5; color:#383d41; }
|
.info-card-header h3 { font-size: 0.9rem; font-weight: 700; color: #111827; margin: 0; }
|
||||||
.breadcrumb { background:transparent; padding:0; margin-bottom:10px; }
|
.info-card-header p { font-size: 0.75rem; color: #6b7280; margin: 0; }
|
||||||
.breadcrumb-item a { color:#28a745; text-decoration:none; }
|
|
||||||
.back-button {
|
.info-card-body { padding: 20px; }
|
||||||
position:fixed; top:20px; right:20px; z-index:1100;
|
|
||||||
background:linear-gradient(45deg,#dc3545,#c82333);
|
/* ===== DETAIL ROW ===== */
|
||||||
color:white; border:none; padding:12px 20px;
|
.detail-row {
|
||||||
border-radius:25px; font-weight:600; text-decoration:none; transition:all 0.3s;
|
display: flex;
|
||||||
|
padding: 8px 0;
|
||||||
|
border-bottom: 1px solid #f9fafb;
|
||||||
|
font-size: 0.84rem;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-row:last-child { border-bottom: none; }
|
||||||
|
|
||||||
|
.detail-label {
|
||||||
|
width: 140px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
color: #6b7280;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-value { color: #111827; flex: 1; }
|
||||||
|
|
||||||
|
/* ===== BADGES ===== */
|
||||||
|
.badge-status {
|
||||||
|
padding: 4px 10px;
|
||||||
|
border-radius: 20px;
|
||||||
|
font-size: 0.72rem;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-admin { background: #dbeafe; color: #1e40af; }
|
||||||
|
.badge-user { background: #dcfce7; color: #14532d; }
|
||||||
|
.badge-verified { background: #dcfce7; color: #14532d; }
|
||||||
|
.badge-unverified { background: #f3f4f6; color: #6b7280; }
|
||||||
|
|
||||||
|
/* ===== AVATAR ===== */
|
||||||
|
.avatar-lg {
|
||||||
|
width: 72px; height: 72px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: linear-gradient(135deg, var(--green-main), var(--green-dark));
|
||||||
|
display: flex; align-items: center; justify-content: center;
|
||||||
|
font-size: 1.75rem; color: white; font-weight: 700;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== FADE IN ===== */
|
||||||
|
.fade-in { animation: fadeIn 0.3s ease; }
|
||||||
|
|
||||||
|
@keyframes fadeIn {
|
||||||
|
from { opacity: 0; transform: translateY(8px); }
|
||||||
|
to { opacity: 1; transform: translateY(0); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== RESPONSIVE ===== */
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.sidebar { transform: translateX(-100%); }
|
||||||
|
.sidebar.open { transform: translateX(0); box-shadow: 4px 0 24px rgba(0,0,0,0.2); }
|
||||||
|
.main-content { margin-left: 0; }
|
||||||
|
.hamburger-btn { display: flex; align-items: center; justify-content: center; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
.content-area { padding: 14px 14px 24px; }
|
||||||
|
.topbar { padding: 0 14px; height: auto; min-height: 58px; flex-wrap: wrap; gap: 8px; padding-top: 10px; padding-bottom: 10px; }
|
||||||
|
.topbar-actions .btn-topbar span { display: none; }
|
||||||
|
.topbar-actions .btn-topbar { padding: 8px 10px; }
|
||||||
|
.detail-label { width: 110px; }
|
||||||
}
|
}
|
||||||
.back-button:hover { transform:translateY(-2px); color:white; }
|
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<a href="{{ route('home') }}" class="back-button">
|
<div class="sidebar-overlay" id="sidebarOverlay" onclick="closeSidebar()"></div>
|
||||||
<i class="fas fa-arrow-left me-2"></i>Kembali ke Website
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div class="admin-container">
|
<!-- ===== SIDEBAR ===== -->
|
||||||
<nav class="sidebar">
|
<nav class="sidebar" id="sidebar">
|
||||||
<div class="sidebar-header">
|
<div class="sidebar-header">
|
||||||
<h3>🌱 Bibit Cabai</h3>
|
<span class="brand-icon">🌱</span>
|
||||||
<p>Admin Dashboard</p>
|
<h3>Bibit Cabai</h3>
|
||||||
<small class="text-light">{{ Auth::user()->name ?? 'Admin' }}</small>
|
<p class="subtitle">Admin Dashboard</p>
|
||||||
|
<span class="admin-name">{{ Auth::user()->name ?? 'Admin User' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="sidebar-menu">
|
<div class="sidebar-menu">
|
||||||
<a href="{{ route('admin.dashboard') }}" class="menu-item"><i class="fas fa-tachometer-alt"></i>Dashboard</a>
|
<div class="menu-section-label">Menu Utama</div>
|
||||||
<a href="{{ route('admin.products.index') }}" class="menu-item"><i class="fas fa-seedling"></i>Kelola Produk</a>
|
<a href="{{ route('admin.dashboard') }}" class="menu-item">
|
||||||
<a href="{{ route('admin.orders') }}" class="menu-item"><i class="fas fa-shopping-cart"></i>Pesanan</a>
|
<i class="fas fa-tachometer-alt"></i><span>Dashboard</span>
|
||||||
<a href="{{ route('admin.users') }}" class="menu-item active"><i class="fas fa-users"></i>Pengguna</a>
|
</a>
|
||||||
<a href="{{ route('admin.reports') }}" class="menu-item"><i class="fas fa-chart-line"></i>Laporan</a>
|
<a href="{{ route('admin.products.index') }}" class="menu-item">
|
||||||
<!-- <a href="{{ route('admin.settings') }}" class="menu-item"><i class="fas fa-cog"></i>Pengaturan</a> -->
|
<i class="fas fa-seedling"></i><span>Kelola Produk</span>
|
||||||
<div class="mt-4 px-3">
|
</a>
|
||||||
|
<a href="{{ route('admin.orders') }}" class="menu-item">
|
||||||
|
<i class="fas fa-shopping-cart"></i><span>Pesanan</span>
|
||||||
|
</a>
|
||||||
|
<a href="{{ route('admin.cancellations') }}" class="menu-item">
|
||||||
|
<i class="fas fa-times-circle"></i><span>Pengajuan Batal</span>
|
||||||
|
</a>
|
||||||
|
<a href="{{ route('admin.users') }}" class="menu-item active">
|
||||||
|
<i class="fas fa-users"></i><span>Pengguna</span>
|
||||||
|
</a>
|
||||||
|
<a href="{{ route('admin.laporan') }}" class="menu-item">
|
||||||
|
<i class="fas fa-chart-line"></i><span>Laporan</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="sidebar-footer">
|
||||||
<form method="POST" action="{{ route('admin.logout') }}">
|
<form method="POST" action="{{ route('admin.logout') }}">
|
||||||
@csrf
|
@csrf
|
||||||
<button type="submit" class="btn btn-outline-light btn-sm w-100">
|
<button type="submit" class="btn-logout">
|
||||||
<i class="fas fa-sign-out-alt me-2"></i>Logout
|
<i class="fas fa-sign-out-alt"></i><span>Logout</span>
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
<!-- ===== MAIN ===== -->
|
||||||
<div class="main-content">
|
<div class="main-content">
|
||||||
<div class="admin-header">
|
|
||||||
<nav aria-label="breadcrumb">
|
<!-- Topbar -->
|
||||||
<ol class="breadcrumb">
|
<header class="topbar">
|
||||||
<li class="breadcrumb-item"><a href="{{ route('admin.dashboard') }}"><i class="fas fa-home"></i> Dashboard</a></li>
|
<div class="topbar-left">
|
||||||
<li class="breadcrumb-item"><a href="{{ route('admin.users') }}">Pengguna</a></li>
|
<button class="hamburger-btn" onclick="toggleSidebar()">
|
||||||
<li class="breadcrumb-item active">Detail Pengguna</li>
|
<i class="fas fa-bars"></i>
|
||||||
</ol>
|
</button>
|
||||||
</nav>
|
<div class="topbar-title">
|
||||||
|
<div class="topbar-breadcrumb">
|
||||||
|
<a href="{{ route('admin.dashboard') }}"><i class="fas fa-home"></i> Dashboard</a>
|
||||||
|
/ <a href="{{ route('admin.users') }}">Pengguna</a>
|
||||||
|
/ {{ $user->name }}
|
||||||
|
</div>
|
||||||
<h2>Detail Pengguna</h2>
|
<h2>Detail Pengguna</h2>
|
||||||
<p class="mb-0">Informasi lengkap pengguna.</p>
|
<p>{{ $user->name }}</p>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="content-area">
|
|
||||||
<div class="detail-card">
|
|
||||||
|
|
||||||
{{-- Avatar & Nama --}}
|
|
||||||
<div class="text-center mb-4">
|
|
||||||
<div class="avatar-circle mx-auto">
|
|
||||||
{{ strtoupper(substr($user->name, 0, 1)) }}
|
|
||||||
</div>
|
|
||||||
<h4 class="mb-1">{{ $user->name }}</h4>
|
|
||||||
@if($user->is_admin)
|
|
||||||
<span class="badge-role badge-admin"><i class="fas fa-shield-alt me-1"></i>Admin</span>
|
|
||||||
@else
|
|
||||||
<span class="badge-role badge-user"><i class="fas fa-user me-1"></i>User</span>
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{-- Info Detail --}}
|
|
||||||
<div class="info-row">
|
|
||||||
<div class="info-label"><i class="fas fa-hashtag me-2 text-muted"></i>ID</div>
|
|
||||||
<div class="info-value">#{{ $user->id }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="info-row">
|
|
||||||
<div class="info-label"><i class="fas fa-envelope me-2 text-muted"></i>Email</div>
|
|
||||||
<div class="info-value">{{ $user->email }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="info-row">
|
|
||||||
<div class="info-label"><i class="fas fa-check-circle me-2 text-muted"></i>Verifikasi</div>
|
|
||||||
<div class="info-value">
|
|
||||||
@if($user->email_verified_at)
|
|
||||||
<span class="badge-role badge-verified">
|
|
||||||
<i class="fas fa-check me-1"></i>Terverifikasi
|
|
||||||
</span>
|
|
||||||
<small class="text-muted ms-2">{{ $user->email_verified_at->format('d M Y') }}</small>
|
|
||||||
@else
|
|
||||||
<span class="badge-role badge-unverified">Belum Verifikasi</span>
|
|
||||||
@endif
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="info-row">
|
<div class="topbar-actions">
|
||||||
<div class="info-label"><i class="fas fa-phone me-2 text-muted"></i>Telepon</div>
|
<a href="{{ route('admin.users') }}" class="btn-topbar btn-topbar-back">
|
||||||
<div class="info-value">{{ $user->phone ?? '-' }}</div>
|
<i class="fas fa-arrow-left"></i>
|
||||||
</div>
|
<span>Kembali</span>
|
||||||
<div class="info-row">
|
|
||||||
<div class="info-label"><i class="fas fa-map-marker-alt me-2 text-muted"></i>Alamat</div>
|
|
||||||
<div class="info-value">{{ $user->address ?? '-' }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="info-row">
|
|
||||||
<div class="info-label"><i class="fas fa-calendar me-2 text-muted"></i>Bergabung</div>
|
|
||||||
<div class="info-value">{{ $user->created_at->format('d M Y, H:i') }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="info-row">
|
|
||||||
<div class="info-label"><i class="fas fa-sync me-2 text-muted"></i>Diperbarui</div>
|
|
||||||
<div class="info-value">{{ $user->updated_at->format('d M Y, H:i') }}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{-- Action Buttons --}}
|
|
||||||
<div class="d-flex gap-2 mt-4">
|
|
||||||
<a href="{{ route('admin.users.edit', $user) }}" class="btn btn-warning">
|
|
||||||
<i class="fas fa-edit me-2"></i>Edit Pengguna
|
|
||||||
</a>
|
</a>
|
||||||
<a href="{{ route('admin.users') }}" class="btn btn-outline-secondary">
|
<a href="{{ route('admin.users.edit', $user) }}" class="btn-topbar btn-topbar-edit">
|
||||||
<i class="fas fa-arrow-left me-2"></i>Kembali
|
<i class="fas fa-edit"></i>
|
||||||
|
<span>Edit</span>
|
||||||
</a>
|
</a>
|
||||||
@if($user->id !== auth()->id())
|
@if($user->id !== auth()->id())
|
||||||
<form method="POST" action="{{ route('admin.users.destroy', $user) }}"
|
<button type="button" class="btn-topbar btn-topbar-delete"
|
||||||
class="ms-auto" onsubmit="return confirm('Yakin ingin menghapus pengguna ini?')">
|
data-bs-toggle="modal" data-bs-target="#deleteModal">
|
||||||
@csrf @method('DELETE')
|
<i class="fas fa-trash"></i>
|
||||||
<button type="submit" class="btn btn-danger">
|
<span>Hapus</span>
|
||||||
<i class="fas fa-trash me-2"></i>Hapus
|
|
||||||
</button>
|
</button>
|
||||||
</form>
|
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<!-- Content -->
|
||||||
|
<div class="content-area fade-in">
|
||||||
|
|
||||||
|
@if(session('success'))
|
||||||
|
<div class="alert alert-success alert-dismissible fade show mb-4" role="alert">
|
||||||
|
<i class="fas fa-check-circle me-2"></i>{{ session('success') }}
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<div class="row g-3">
|
||||||
|
|
||||||
|
<!-- ===== KOLOM KIRI (8/12) ===== -->
|
||||||
|
<div class="col-lg-8">
|
||||||
|
|
||||||
|
<!-- Profil & Info Dasar -->
|
||||||
|
<div class="info-card">
|
||||||
|
<div class="info-card-header">
|
||||||
|
<div class="info-card-icon icon-blue">
|
||||||
|
<i class="fas fa-user"></i>
|
||||||
|
</div>
|
||||||
|
<div style="flex:1;">
|
||||||
|
<h3>Informasi Pengguna</h3>
|
||||||
|
<p>Detail akun & status</p>
|
||||||
|
</div>
|
||||||
|
<span class="badge-status {{ $user->is_admin ? 'badge-admin' : 'badge-user' }}">
|
||||||
|
<i class="fas {{ $user->is_admin ? 'fa-shield-alt' : 'fa-user' }} me-1"></i>
|
||||||
|
{{ $user->is_admin ? 'Admin' : 'User' }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-card-body">
|
||||||
|
<!-- Avatar + nama -->
|
||||||
|
<div style="display:flex;align-items:center;gap:16px;margin-bottom:20px;
|
||||||
|
padding-bottom:16px;border-bottom:1px solid #f3f4f6;">
|
||||||
|
<div class="avatar-lg">{{ strtoupper(substr($user->name, 0, 1)) }}</div>
|
||||||
|
<div>
|
||||||
|
<div style="font-size:1.05rem;font-weight:700;color:#111827;">{{ $user->name }}</div>
|
||||||
|
<div style="font-size:0.82rem;color:#6b7280;margin-top:2px;">{{ $user->email }}</div>
|
||||||
|
<div style="margin-top:8px;">
|
||||||
|
@if($user->email_verified_at)
|
||||||
|
<span class="badge-status badge-verified">
|
||||||
|
<i class="fas fa-check me-1"></i>Email Terverifikasi
|
||||||
|
</span>
|
||||||
|
@else
|
||||||
|
<span class="badge-status badge-unverified">
|
||||||
|
<i class="fas fa-clock me-1"></i>Belum Verifikasi
|
||||||
|
</span>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row g-4">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div style="font-size:0.72rem;font-weight:700;letter-spacing:0.08em;text-transform:uppercase;color:#9ca3af;padding-bottom:10px;border-bottom:1px solid #f3f4f6;margin-bottom:16px;">Akun</div>
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="detail-label"><i class="fas fa-hashtag me-1" style="font-size:0.7rem;"></i> ID</span>
|
||||||
|
<span class="detail-value"><strong>#{{ $user->id }}</strong></span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="detail-label"><i class="fas fa-envelope me-1" style="font-size:0.7rem;"></i> Email</span>
|
||||||
|
<span class="detail-value">{{ $user->email }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="detail-label"><i class="fas fa-check-circle me-1" style="font-size:0.7rem;"></i> Verifikasi</span>
|
||||||
|
<span class="detail-value">
|
||||||
|
@if($user->email_verified_at)
|
||||||
|
<span style="color:#16a34a;font-size:0.8rem;">{{ $user->email_verified_at->format('d M Y') }}</span>
|
||||||
|
@else
|
||||||
|
<span style="color:#9ca3af;font-size:0.8rem;">Belum verifikasi</span>
|
||||||
|
@endif
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="detail-label"><i class="fas fa-shield-alt me-1" style="font-size:0.7rem;"></i> Role</span>
|
||||||
|
<span class="detail-value">
|
||||||
|
<span class="badge-status {{ $user->is_admin ? 'badge-admin' : 'badge-user' }}">
|
||||||
|
{{ $user->is_admin ? 'Admin' : 'User' }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div style="font-size:0.72rem;font-weight:700;letter-spacing:0.08em;text-transform:uppercase;color:#9ca3af;padding-bottom:10px;border-bottom:1px solid #f3f4f6;margin-bottom:16px;">Waktu</div>
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="detail-label"><i class="fas fa-calendar me-1" style="font-size:0.7rem;"></i> Bergabung</span>
|
||||||
|
<span class="detail-value">{{ $user->created_at->format('d M Y, H:i') }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="detail-label"><i class="fas fa-sync me-1" style="font-size:0.7rem;"></i> Diperbarui</span>
|
||||||
|
<span class="detail-value">{{ $user->updated_at->format('d M Y, H:i') }}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Informasi Kontak -->
|
||||||
|
<div class="info-card">
|
||||||
|
<div class="info-card-header">
|
||||||
|
<div class="info-card-icon icon-orange">
|
||||||
|
<i class="fas fa-address-card"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3>Kontak & Alamat</h3>
|
||||||
|
<p>Telepon dan alamat pengguna</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-card-body">
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="detail-label"><i class="fas fa-phone me-1" style="font-size:0.7rem;color:var(--green-main)"></i> Telepon</span>
|
||||||
|
<span class="detail-value">{{ $user->phone ?? '-' }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="detail-label"><i class="fas fa-map-marker-alt me-1" style="font-size:0.7rem;color:var(--green-main)"></i> Alamat</span>
|
||||||
|
<span class="detail-value" style="line-height:1.6;">{{ $user->address ?? '-' }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!-- Akhir col-lg-8 -->
|
||||||
|
|
||||||
|
<!-- ===== KOLOM KANAN (4/12) ===== -->
|
||||||
|
<div class="col-lg-4">
|
||||||
|
|
||||||
|
<!-- Quick Actions -->
|
||||||
|
<div class="info-card">
|
||||||
|
<div class="info-card-header">
|
||||||
|
<div class="info-card-icon icon-yellow">
|
||||||
|
<i class="fas fa-bolt"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3>Aksi Cepat</h3>
|
||||||
|
<p>Kelola pengguna ini</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-card-body" style="display:flex;flex-direction:column;gap:10px;">
|
||||||
|
<a href="{{ route('admin.users.edit', $user) }}"
|
||||||
|
style="width:100%;padding:10px 16px;border-radius:9px;border:none;
|
||||||
|
background:linear-gradient(135deg,#ca8a04,#a16207);
|
||||||
|
color:white;font-weight:700;font-size:0.875rem;
|
||||||
|
display:flex;align-items:center;justify-content:center;gap:8px;
|
||||||
|
text-decoration:none;transition:all 0.2s;">
|
||||||
|
<i class="fas fa-edit"></i> Edit Pengguna
|
||||||
|
</a>
|
||||||
|
<a href="{{ route('admin.users') }}"
|
||||||
|
style="width:100%;padding:10px 16px;border-radius:9px;
|
||||||
|
border:1.5px solid #e5e7eb;background:#f9fafb;
|
||||||
|
color:#374151;font-weight:600;font-size:0.875rem;
|
||||||
|
display:flex;align-items:center;justify-content:center;gap:8px;
|
||||||
|
text-decoration:none;transition:all 0.2s;">
|
||||||
|
<i class="fas fa-arrow-left"></i> Kembali ke Daftar
|
||||||
|
</a>
|
||||||
|
@if($user->id !== auth()->id())
|
||||||
|
<button type="button"
|
||||||
|
data-bs-toggle="modal" data-bs-target="#deleteModal"
|
||||||
|
style="width:100%;padding:10px 16px;border-radius:9px;
|
||||||
|
border:1.5px solid #fecaca;background:#fef2f2;
|
||||||
|
color:#dc2626;font-weight:600;font-size:0.875rem;
|
||||||
|
display:flex;align-items:center;justify-content:center;gap:8px;
|
||||||
|
cursor:pointer;transition:all 0.2s;">
|
||||||
|
<i class="fas fa-trash"></i> Hapus Pengguna
|
||||||
|
</button>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Status Summary -->
|
||||||
|
<div class="info-card">
|
||||||
|
<div class="info-card-header">
|
||||||
|
<div class="info-card-icon icon-purple">
|
||||||
|
<i class="fas fa-info-circle"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3>Ringkasan Status</h3>
|
||||||
|
<p>Status akun pengguna</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-card-body">
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="detail-label">Role</span>
|
||||||
|
<span class="detail-value">
|
||||||
|
<span class="badge-status {{ $user->is_admin ? 'badge-admin' : 'badge-user' }}">
|
||||||
|
{{ $user->is_admin ? 'Admin' : 'User' }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="detail-label">Email</span>
|
||||||
|
<span class="detail-value">
|
||||||
|
@if($user->email_verified_at)
|
||||||
|
<span class="badge-status badge-verified">Terverifikasi</span>
|
||||||
|
@else
|
||||||
|
<span class="badge-status badge-unverified">Belum Verifikasi</span>
|
||||||
|
@endif
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="detail-label">ID Pengguna</span>
|
||||||
|
<span class="detail-value"><code style="background:#f3f4f6;padding:2px 6px;border-radius:4px;font-size:0.8rem;">#{{ $user->id }}</code></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!-- Akhir col-lg-4 -->
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ===== DELETE MODAL ===== -->
|
||||||
|
@if($user->id !== auth()->id())
|
||||||
|
<div class="modal fade" id="deleteModal" tabindex="-1" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-dialog-centered">
|
||||||
|
<div class="modal-content" style="border:none;border-radius:14px;overflow:hidden;">
|
||||||
|
<div class="modal-header" style="background:#dc2626;color:white;border:none;">
|
||||||
|
<h5 class="modal-title">
|
||||||
|
<i class="fas fa-exclamation-triangle me-2"></i>Konfirmasi Hapus
|
||||||
|
</h5>
|
||||||
|
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body" style="padding:24px;">
|
||||||
|
<p style="color:#374151;margin-bottom:8px;">Apakah Anda yakin ingin menghapus pengguna ini?</p>
|
||||||
|
<p style="font-weight:700;color:#111827;margin-bottom:12px;">{{ $user->name }} ({{ $user->email }})</p>
|
||||||
|
<p style="color:#dc2626;font-size:0.84rem;margin:0;">
|
||||||
|
<i class="fas fa-exclamation-triangle me-1"></i> Tindakan ini tidak dapat dibatalkan!
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer" style="border:none;padding:16px 24px;">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Batal</button>
|
||||||
|
<form action="{{ route('admin.users.destroy', $user) }}" method="POST" class="d-inline">
|
||||||
|
@csrf
|
||||||
|
@method('DELETE')
|
||||||
|
<button type="submit" class="btn btn-danger">
|
||||||
|
<i class="fas fa-trash me-1"></i> Hapus Pengguna
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
<script>
|
||||||
|
function toggleSidebar() {
|
||||||
|
document.getElementById('sidebar').classList.toggle('open');
|
||||||
|
document.getElementById('sidebarOverlay').classList.toggle('show');
|
||||||
|
}
|
||||||
|
function closeSidebar() {
|
||||||
|
document.getElementById('sidebar').classList.remove('open');
|
||||||
|
document.getElementById('sidebarOverlay').classList.remove('show');
|
||||||
|
}
|
||||||
|
window.addEventListener('resize', function() {
|
||||||
|
if (window.innerWidth > 900) closeSidebar();
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
document.querySelectorAll('.alert').forEach(function(alert) {
|
||||||
|
setTimeout(function() {
|
||||||
|
const a = bootstrap.Alert.getOrCreateInstance(alert);
|
||||||
|
if (a) a.close();
|
||||||
|
}, 5000);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
@ -40,7 +40,6 @@
|
||||||
border-color: #11998e;
|
border-color: #11998e;
|
||||||
box-shadow: 0 0 0 0.2rem rgba(17, 153, 142, 0.25);
|
box-shadow: 0 0 0 0.2rem rgba(17, 153, 142, 0.25);
|
||||||
}
|
}
|
||||||
|
|
||||||
.step-wrapper {
|
.step-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -64,8 +63,6 @@
|
||||||
.step-line { height: 2px; width: 36px; margin: 0 6px 18px; }
|
.step-line { height: 2px; width: 36px; margin: 0 6px 18px; }
|
||||||
.step-line.done { background: #11998e; }
|
.step-line.done { background: #11998e; }
|
||||||
.step-line.idle { background: #dee2e6; }
|
.step-line.idle { background: #dee2e6; }
|
||||||
|
|
||||||
/* OTP Boxes */
|
|
||||||
.otp-box {
|
.otp-box {
|
||||||
width: 46px !important;
|
width: 46px !important;
|
||||||
height: 54px !important;
|
height: 54px !important;
|
||||||
|
|
@ -86,7 +83,13 @@
|
||||||
border-color: #11998e !important;
|
border-color: #11998e !important;
|
||||||
background-color: #f0fff4 !important;
|
background-color: #f0fff4 !important;
|
||||||
}
|
}
|
||||||
|
/* Kotak OTP saat expired */
|
||||||
|
.otp-box:disabled {
|
||||||
|
background-color: #f8f9fa !important;
|
||||||
|
border-color: #dee2e6 !important;
|
||||||
|
color: #adb5bd !important;
|
||||||
|
cursor: not-allowed !important;
|
||||||
|
}
|
||||||
.email-badge {
|
.email-badge {
|
||||||
background: #f0fff4;
|
background: #f0fff4;
|
||||||
border: 1px solid #11998e33;
|
border: 1px solid #11998e33;
|
||||||
|
|
@ -94,7 +97,6 @@
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 10px 14px;
|
padding: 10px 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-box {
|
.icon-box {
|
||||||
width: 64px; height: 64px;
|
width: 64px; height: 64px;
|
||||||
background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%);
|
background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%);
|
||||||
|
|
@ -160,6 +162,9 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{-- =============================================
|
||||||
|
FORM OTP — disabled seluruhnya saat expired
|
||||||
|
============================================= --}}
|
||||||
<form method="POST" action="{{ route('admin.password.verify-otp') }}" id="otpForm" novalidate>
|
<form method="POST" action="{{ route('admin.password.verify-otp') }}" id="otpForm" novalidate>
|
||||||
@csrf
|
@csrf
|
||||||
|
|
||||||
|
|
@ -170,12 +175,18 @@
|
||||||
|
|
||||||
{{-- OTP Boxes --}}
|
{{-- OTP Boxes --}}
|
||||||
<div class="d-flex justify-content-center gap-2 mb-2" id="otpBoxes">
|
<div class="d-flex justify-content-center gap-2 mb-2" id="otpBoxes">
|
||||||
<input type="text" class="otp-box form-control" maxlength="1" inputmode="numeric" pattern="[0-9]" autocomplete="off">
|
{{-- disabled langsung dari PHP jika backend bilang expired --}}
|
||||||
<input type="text" class="otp-box form-control" maxlength="1" inputmode="numeric" pattern="[0-9]" autocomplete="off">
|
@php $isExpiredFromServer = session('otp_expired', false); @endphp
|
||||||
<input type="text" class="otp-box form-control" maxlength="1" inputmode="numeric" pattern="[0-9]" autocomplete="off">
|
|
||||||
<input type="text" class="otp-box form-control" maxlength="1" inputmode="numeric" pattern="[0-9]" autocomplete="off">
|
@for ($i = 0; $i < 6; $i++)
|
||||||
<input type="text" class="otp-box form-control" maxlength="1" inputmode="numeric" pattern="[0-9]" autocomplete="off">
|
<input type="text"
|
||||||
<input type="text" class="otp-box form-control" maxlength="1" inputmode="numeric" pattern="[0-9]" autocomplete="off">
|
class="otp-box form-control"
|
||||||
|
maxlength="1"
|
||||||
|
inputmode="numeric"
|
||||||
|
pattern="[0-9]"
|
||||||
|
autocomplete="off"
|
||||||
|
{{ $isExpiredFromServer ? 'disabled' : '' }}>
|
||||||
|
@endfor
|
||||||
</div>
|
</div>
|
||||||
<input type="hidden" name="otp" id="otpHidden">
|
<input type="hidden" name="otp" id="otpHidden">
|
||||||
|
|
||||||
|
|
@ -186,32 +197,44 @@
|
||||||
|
|
||||||
{{-- Countdown Timer --}}
|
{{-- Countdown Timer --}}
|
||||||
<div class="text-center mb-4">
|
<div class="text-center mb-4">
|
||||||
<div id="timerWrapper">
|
<div id="timerWrapper" {{ $isExpiredFromServer ? 'style=display:none;' : '' }}>
|
||||||
<p class="text-muted small mb-1">Kode berlaku selama:</p>
|
<p class="text-muted small mb-1">Kode berlaku selama:</p>
|
||||||
<span id="countdown" class="badge fs-6 px-3 py-2" style="background:#11998e;">10:00</span>
|
<span id="countdown" class="badge fs-6 px-3 py-2" style="background:#11998e;">03:00</span>
|
||||||
</div>
|
</div>
|
||||||
<div id="expiredWrapper" style="display:none;">
|
<div id="expiredWrapper" {{ $isExpiredFromServer ? '' : 'style=display:none;' }}>
|
||||||
<span class="badge bg-danger fs-6 px-3 py-2">
|
<span class="badge bg-danger fs-6 px-3 py-2">
|
||||||
❌ Kode sudah kadaluarsa
|
❌ Kode sudah kadaluarsa
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{-- Tombol Verifikasi --}}
|
||||||
|
{{-- disabled dari server jika expired, dari JS jika OTP belum 6 digit --}}
|
||||||
<div class="d-grid mb-3">
|
<div class="d-grid mb-3">
|
||||||
<button type="submit" class="btn btn-primary-custom py-2 fw-bold" id="submitBtn" disabled>
|
<button type="submit"
|
||||||
|
class="btn btn-primary-custom py-2 fw-bold"
|
||||||
|
id="submitBtn"
|
||||||
|
{{ $isExpiredFromServer ? 'disabled' : 'disabled' }}>
|
||||||
|
@if($isExpiredFromServer)
|
||||||
|
⛔ Waktu Habis
|
||||||
|
@else
|
||||||
✅ Verifikasi Kode
|
✅ Verifikasi Kode
|
||||||
|
@endif
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<hr class="my-3">
|
<hr class="my-3">
|
||||||
|
|
||||||
{{-- Resend --}}
|
{{-- Resend — hanya aktif saat expired --}}
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<p class="text-muted small mb-2">Tidak menerima kode?</p>
|
<p class="text-muted small mb-2">Tidak menerima kode?</p>
|
||||||
<form method="POST" action="{{ route('admin.password.resend-otp') }}">
|
<form method="POST" action="{{ route('admin.password.resend-otp') }}" id="resendForm">
|
||||||
@csrf
|
@csrf
|
||||||
<button type="submit" class="btn btn-outline-secondary btn-sm" id="resendBtn" disabled>
|
<button type="submit"
|
||||||
|
class="btn btn-outline-secondary btn-sm"
|
||||||
|
id="resendBtn"
|
||||||
|
{{ $isExpiredFromServer ? '' : 'disabled' }}>
|
||||||
🔄 Kirim Ulang Kode
|
🔄 Kirim Ulang Kode
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
@ -231,15 +254,29 @@
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded', function () {
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
|
||||||
|
// ── Variabel elemen ──────────────────────────────────────
|
||||||
const boxes = document.querySelectorAll('.otp-box');
|
const boxes = document.querySelectorAll('.otp-box');
|
||||||
const otpHidden = document.getElementById('otpHidden');
|
const otpHidden = document.getElementById('otpHidden');
|
||||||
const submitBtn = document.getElementById('submitBtn');
|
const submitBtn = document.getElementById('submitBtn');
|
||||||
const resendBtn = document.getElementById('resendBtn');
|
const resendBtn = document.getElementById('resendBtn');
|
||||||
|
const resendForm = document.getElementById('resendForm');
|
||||||
const countdown = document.getElementById('countdown');
|
const countdown = document.getElementById('countdown');
|
||||||
const timerWrap = document.getElementById('timerWrapper');
|
const timerWrap = document.getElementById('timerWrapper');
|
||||||
const expiredWrap = document.getElementById('expiredWrapper');
|
const expiredWrap = document.getElementById('expiredWrapper');
|
||||||
|
|
||||||
// ---- OTP input logic ----
|
// ── Flag dari backend (PHP → JS) ─────────────────────────
|
||||||
|
// true = backend sudah konfirmasi OTP expired (record dihapus)
|
||||||
|
// false = backend belum, timer frontend yang jalan
|
||||||
|
const isExpiredFromServer = {{ $isExpiredFromServer ? 'true' : 'false' }};
|
||||||
|
|
||||||
|
// ── Jika sudah expired dari server → langsung lock ───────
|
||||||
|
if (isExpiredFromServer) {
|
||||||
|
lockExpired();
|
||||||
|
return; // stop, tidak perlu jalankan timer
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── OTP input logic ──────────────────────────────────────
|
||||||
boxes.forEach((box, i) => {
|
boxes.forEach((box, i) => {
|
||||||
box.addEventListener('input', function () {
|
box.addEventListener('input', function () {
|
||||||
this.value = this.value.replace(/[^0-9]/g, '');
|
this.value = this.value.replace(/[^0-9]/g, '');
|
||||||
|
|
@ -263,9 +300,13 @@
|
||||||
|
|
||||||
box.addEventListener('paste', function (e) {
|
box.addEventListener('paste', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const pasted = (e.clipboardData || window.clipboardData).getData('text').replace(/\D/g, '');
|
const pasted = (e.clipboardData || window.clipboardData)
|
||||||
|
.getData('text').replace(/\D/g, '');
|
||||||
pasted.split('').slice(0, 6).forEach((ch, idx) => {
|
pasted.split('').slice(0, 6).forEach((ch, idx) => {
|
||||||
if (boxes[idx]) { boxes[idx].value = ch; boxes[idx].classList.add('filled'); }
|
if (boxes[idx]) {
|
||||||
|
boxes[idx].value = ch;
|
||||||
|
boxes[idx].classList.add('filled');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
updateHidden();
|
updateHidden();
|
||||||
boxes[Math.min(pasted.length, 5)].focus();
|
boxes[Math.min(pasted.length, 5)].focus();
|
||||||
|
|
@ -275,29 +316,91 @@
|
||||||
function updateHidden() {
|
function updateHidden() {
|
||||||
const otp = Array.from(boxes).map(b => b.value).join('');
|
const otp = Array.from(boxes).map(b => b.value).join('');
|
||||||
otpHidden.value = otp;
|
otpHidden.value = otp;
|
||||||
submitBtn.disabled = otp.length !== 6;
|
// Tombol verify aktif hanya jika 6 digit DAN belum expired
|
||||||
|
submitBtn.disabled = (otp.length !== 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Countdown 10 min ----
|
// ── Countdown — pakai sessionStorage agar refresh tidak reset ──
|
||||||
let secs = 10 * 60;
|
// Key unik per email agar tidak bentrok jika beda sesi
|
||||||
const timer = setInterval(() => {
|
const STORAGE_KEY = 'otp_timer_{{ md5(session("admin_reset_email", "x")) }}';
|
||||||
secs--;
|
const PENALTY_KEY = 'otp_penalty_{{ md5(session("admin_reset_email", "x")) }}';
|
||||||
const m = String(Math.floor(secs / 60)).padStart(2, '0');
|
const DURATION = 3 * 60; // 180 detik (3 menit)
|
||||||
const s = String(secs % 60).padStart(2, '0');
|
const WRONG_PENALTY = 30; // pengurangan waktu saat salah OTP (detik)
|
||||||
countdown.textContent = `${m}:${s}`;
|
|
||||||
|
|
||||||
if (secs <= 60) { countdown.style.background = '#ffc107'; countdown.style.color = '#000'; }
|
let startTime = parseInt(sessionStorage.getItem(STORAGE_KEY) || '0');
|
||||||
if (secs <= 0) {
|
if (!startTime || isNaN(startTime)) {
|
||||||
clearInterval(timer);
|
startTime = Date.now();
|
||||||
timerWrap.style.display = 'none';
|
sessionStorage.setItem(STORAGE_KEY, startTime);
|
||||||
expiredWrap.style.display = 'block';
|
}
|
||||||
|
|
||||||
|
// ── Terapkan penalty jika backend bilang OTP salah ────────
|
||||||
|
// Backend set session 'otp_wrong' = true saat Hash::check gagal
|
||||||
|
const wrongFromServer = {{ session('otp_wrong') ? 'true' : 'false' }};
|
||||||
|
if (wrongFromServer) {
|
||||||
|
// Tambah penalty ke startTime (maju ke masa lalu = sisa waktu berkurang)
|
||||||
|
startTime -= (WRONG_PENALTY * 1000);
|
||||||
|
sessionStorage.setItem(STORAGE_KEY, startTime);
|
||||||
|
sessionStorage.removeItem(PENALTY_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
const timerInterval = setInterval(() => {
|
||||||
|
const elapsed = Math.floor((Date.now() - startTime) / 1000);
|
||||||
|
const remaining = DURATION - elapsed;
|
||||||
|
|
||||||
|
if (remaining <= 0) {
|
||||||
|
clearInterval(timerInterval);
|
||||||
|
sessionStorage.removeItem(STORAGE_KEY);
|
||||||
|
lockExpired();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warna kuning saat sisa ≤ 30 detik
|
||||||
|
if (remaining <= 30) {
|
||||||
|
countdown.style.background = '#dc3545';
|
||||||
|
countdown.style.color = '#fff';
|
||||||
|
} else if (remaining <= 60) {
|
||||||
|
countdown.style.background = '#ffc107';
|
||||||
|
countdown.style.color = '#000';
|
||||||
|
}
|
||||||
|
|
||||||
|
const m = String(Math.floor(remaining / 60)).padStart(2, '0');
|
||||||
|
const s = String(remaining % 60).padStart(2, '0');
|
||||||
|
countdown.textContent = `${m}:${s}`;
|
||||||
|
}, 500);
|
||||||
|
|
||||||
|
// ── Fungsi lock saat expired ─────────────────────────────
|
||||||
|
function lockExpired() {
|
||||||
|
// Sembunyikan timer, tampilkan badge expired
|
||||||
|
if (timerWrap) timerWrap.style.display = 'none';
|
||||||
|
if (expiredWrap) expiredWrap.style.display = 'block';
|
||||||
|
|
||||||
|
// Disable & ubah teks tombol verifikasi
|
||||||
submitBtn.disabled = true;
|
submitBtn.disabled = true;
|
||||||
|
submitBtn.textContent = '⛔ Waktu Habis';
|
||||||
|
submitBtn.style.background = '#adb5bd';
|
||||||
|
|
||||||
|
// Blokir submit form meski tombol diklik paksa (inject JS / inspect)
|
||||||
|
document.getElementById('otpForm').addEventListener('submit', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Disable semua kotak OTP
|
||||||
|
boxes.forEach(b => {
|
||||||
|
b.disabled = true;
|
||||||
|
b.value = '';
|
||||||
|
b.classList.remove('filled');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Aktifkan tombol kirim ulang
|
||||||
resendBtn.disabled = false;
|
resendBtn.disabled = false;
|
||||||
}
|
}
|
||||||
}, 1000);
|
|
||||||
|
|
||||||
// Enable resend after 60s
|
// ── Bersihkan sessionStorage saat resend dikirim ─────────
|
||||||
setTimeout(() => { resendBtn.disabled = false; }, 60000);
|
resendForm.addEventListener('submit', function () {
|
||||||
|
sessionStorage.removeItem(STORAGE_KEY);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
|
|
@ -4,26 +4,73 @@
|
||||||
|
|
||||||
@section('styles')
|
@section('styles')
|
||||||
<style>
|
<style>
|
||||||
|
/* ── Hero Section ───────────────────────────── */
|
||||||
|
.hero-image {
|
||||||
|
max-height: 400px;
|
||||||
|
object-fit: cover;
|
||||||
|
border-radius: 15px;
|
||||||
|
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mobile: gambar naik ke atas, teks di bawah */
|
||||||
|
@media (max-width: 767.98px) {
|
||||||
|
.hero-section {
|
||||||
|
text-align: center;
|
||||||
|
padding-top: 30px !important;
|
||||||
|
padding-bottom: 30px !important;
|
||||||
|
}
|
||||||
|
.hero-img-col {
|
||||||
|
order: -1;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.hero-image {
|
||||||
|
max-height: 200px;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
.hero-section h1 {
|
||||||
|
font-size: 1.8rem !important;
|
||||||
|
}
|
||||||
|
.hero-section p.lead {
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
.hero-section .btn {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 300px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Product Card ───────────────────────────── */
|
||||||
.product-card {
|
.product-card {
|
||||||
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||||
border: none;
|
border: none;
|
||||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.product-card:hover {
|
.product-card:hover {
|
||||||
transform: translateY(-5px);
|
transform: translateY(-5px);
|
||||||
box-shadow: 0 5px 25px rgba(0,0,0,0.15);
|
box-shadow: 0 5px 25px rgba(0,0,0,0.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
.product-image {
|
.product-image {
|
||||||
height: 250px;
|
height: 250px;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
transition: transform 0.3s ease;
|
transition: transform 0.3s ease;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.product-card:hover .product-image {
|
.product-card:hover .product-image {
|
||||||
transform: scale(1.05);
|
transform: scale(1.05);
|
||||||
}
|
}
|
||||||
|
@media (max-width: 575.98px) {
|
||||||
|
.product-image {
|
||||||
|
height: 150px;
|
||||||
|
}
|
||||||
|
.card-body {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
.card-title {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
margin-bottom: 4px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.badge-bestseller {
|
.badge-bestseller {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
@ -44,12 +91,22 @@
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #28a745;
|
color: #28a745;
|
||||||
}
|
}
|
||||||
|
@media (max-width: 575.98px) {
|
||||||
.hero-image {
|
.price-text {
|
||||||
max-height: 400px;
|
font-size: 0.95rem;
|
||||||
object-fit: cover;
|
margin-bottom: 6px !important;
|
||||||
border-radius: 15px;
|
}
|
||||||
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
|
/* Sembunyikan teks "Terjual" di mobile agar tidak penuh */
|
||||||
|
.sold-label { display: none; }
|
||||||
|
/* Quantity input lebih kecil */
|
||||||
|
.quantity-input { width: 40px !important; font-size: 0.85rem; }
|
||||||
|
.input-group .btn { padding: 4px 8px; font-size: 0.8rem; }
|
||||||
|
.btn { font-size: 0.8rem; }
|
||||||
|
/* Section title */
|
||||||
|
.display-5 { font-size: 1.4rem !important; }
|
||||||
|
/* Feature icon lebih kecil */
|
||||||
|
.feature-icon-circle { width: 56px !important; height: 56px !important; }
|
||||||
|
.feature-icon-circle .fa-2x { font-size: 1.2rem !important; }
|
||||||
}
|
}
|
||||||
|
|
||||||
.quantity-input {
|
.quantity-input {
|
||||||
|
|
@ -62,17 +119,17 @@
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="container-fluid p-0">
|
<div class="container-fluid p-0">
|
||||||
<!-- Hero Section -->
|
<!-- Hero Section -->
|
||||||
<section class="bg-success text-white py-5">
|
<section class="bg-success text-white py-5 hero-section">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row align-items-center">
|
<div class="row align-items-center">
|
||||||
<div class="col-lg-6">
|
<div class="col-lg-6 col-md-6 col-12">
|
||||||
<h1 class="display-4 fw-bold mb-4">Bibit Cabai Berkualitas</h1>
|
<h1 class="display-4 fw-bold mb-4">Bibit Cabai Berkualitas</h1>
|
||||||
<p class="lead mb-4">Dapatkan bibit cabai terbaik dari Bondowoso untuk hasil panen yang optimal.</p>
|
<p class="lead mb-4">Dapatkan bibit cabai terbaik dari Bondowoso untuk hasil panen yang optimal.</p>
|
||||||
<a href="{{ route('products.best-selling') }}" class="btn btn-light btn-lg">
|
<a href="{{ route('products.best-selling') }}" class="btn btn-light btn-lg">
|
||||||
<i class="fas fa-fire me-2"></i>Lihat Produk Terlaris
|
<i class="fas fa-fire me-2"></i>Lihat Produk Terlaris
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-6 text-center">
|
<div class="col-lg-6 col-md-6 col-12 text-center hero-img-col">
|
||||||
<img src="{{ asset('images/bara f1.jpeg') }}"
|
<img src="{{ asset('images/bara f1.jpeg') }}"
|
||||||
alt="Bibit Cabai"
|
alt="Bibit Cabai"
|
||||||
class="img-fluid hero-image"
|
class="img-fluid hero-image"
|
||||||
|
|
@ -93,7 +150,7 @@ class="img-fluid hero-image"
|
||||||
@if($featuredProducts->count() > 0)
|
@if($featuredProducts->count() > 0)
|
||||||
<div class="row g-4">
|
<div class="row g-4">
|
||||||
@foreach($featuredProducts as $product)
|
@foreach($featuredProducts as $product)
|
||||||
<div class="col-lg-4 col-md-6">
|
<div class="col-lg-4 col-md-6 col-6">
|
||||||
<div class="card product-card h-100 position-relative">
|
<div class="card product-card h-100 position-relative">
|
||||||
@if($product->total_sold > 0)
|
@if($product->total_sold > 0)
|
||||||
<div class="badge-bestseller">
|
<div class="badge-bestseller">
|
||||||
|
|
@ -114,7 +171,7 @@ class="card-img-top product-image"
|
||||||
<div class="price-text mb-3">Rp {{ number_format($product->price, 0, ',', '.') }}</div>
|
<div class="price-text mb-3">Rp {{ number_format($product->price, 0, ',', '.') }}</div>
|
||||||
|
|
||||||
@if($product->total_sold > 0)
|
@if($product->total_sold > 0)
|
||||||
<small class="text-muted mb-3">
|
<small class="text-muted mb-3 sold-label">
|
||||||
<i class="fas fa-chart-line me-1"></i>
|
<i class="fas fa-chart-line me-1"></i>
|
||||||
Terjual: {{ number_format($product->total_sold) }} bibit
|
Terjual: {{ number_format($product->total_sold) }} bibit
|
||||||
</small>
|
</small>
|
||||||
|
|
@ -198,6 +255,7 @@ class="card-img-top product-image"
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Semua Produk Section -->
|
<!-- Semua Produk Section -->
|
||||||
<section class="py-5 bg-white">
|
<section class="py-5 bg-white">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
|
@ -208,7 +266,7 @@ class="card-img-top product-image"
|
||||||
|
|
||||||
<div class="row g-4">
|
<div class="row g-4">
|
||||||
@foreach($allProducts as $product)
|
@foreach($allProducts as $product)
|
||||||
<div class="col-lg-4 col-md-6">
|
<div class="col-lg-4 col-md-6 col-6">
|
||||||
<div class="card product-card h-100 position-relative">
|
<div class="card product-card h-100 position-relative">
|
||||||
<div class="overflow-hidden">
|
<div class="overflow-hidden">
|
||||||
<img src="{{ $product->image ? asset('storage/' . $product->image) : 'https://via.placeholder.com/300x250/28a745/ffffff?text=' . urlencode($product->name) }}"
|
<img src="{{ $product->image ? asset('storage/' . $product->image) : 'https://via.placeholder.com/300x250/28a745/ffffff?text=' . urlencode($product->name) }}"
|
||||||
|
|
@ -268,41 +326,31 @@ class="card-img-top product-image"
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Features Section -->
|
|
||||||
<!-- Features Section -->
|
<!-- Features Section -->
|
||||||
<section class="py-5 bg-white">
|
<section class="py-5 bg-white">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row g-4">
|
<div class="row g-4">
|
||||||
<div class="col-lg-3 col-md-6">
|
<div class="col-lg-3 col-md-6 col-6">
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<div class="bg-success text-white rounded-circle mx-auto mb-3 d-flex align-items-center justify-content-center" style="width: 80px; height: 80px;">
|
<div class="bg-success text-white rounded-circle mx-auto mb-3 d-flex align-items-center justify-content-center feature-icon-circle" style="width: 80px; height: 80px;">
|
||||||
<i class="fas fa-seedling fa-2x"></i>
|
<i class="fas fa-seedling fa-2x"></i>
|
||||||
</div>
|
</div>
|
||||||
<h5>Bibit Berkualitas</h5>
|
<h5>Bibit Berkualitas</h5>
|
||||||
<p class="text-muted">Bibit pilihan dengan kualitas terjamin dan hasil optimal.</p>
|
<p class="text-muted">Bibit pilihan dengan kualitas terjamin dan hasil optimal.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-3 col-md-6">
|
<div class="col-lg-3 col-md-6 col-6">
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<div class="bg-success text-white rounded-circle mx-auto mb-3 d-flex align-items-center justify-content-center" style="width: 80px; height: 80px;">
|
<div class="bg-success text-white rounded-circle mx-auto mb-3 d-flex align-items-center justify-content-center feature-icon-circle" style="width: 80px; height: 80px;">
|
||||||
<i class="fas fa-truck fa-2x"></i>
|
<i class="fas fa-truck fa-2x"></i>
|
||||||
</div>
|
</div>
|
||||||
<h5>Pengiriman Cepat</h5>
|
<h5>Pengiriman Cepat</h5>
|
||||||
<p class="text-muted">Pengiriman ke seluruh kabupaten Bondowoso dengan packaging aman.</p>
|
<p class="text-muted">Pengiriman ke seluruh kabupaten Bondowoso dengan packaging aman.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- <div class="col-lg-3 col-md-6">
|
<div class="col-lg-3 col-md-6 col-6">
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<div class="bg-success text-white rounded-circle mx-auto mb-3 d-flex align-items-center justify-content-center" style="width: 80px; height: 80px;">
|
<div class="bg-success text-white rounded-circle mx-auto mb-3 d-flex align-items-center justify-content-center feature-icon-circle" style="width: 80px; height: 80px;">
|
||||||
<i class="fas fa-medal fa-2x"></i>
|
|
||||||
</div>
|
|
||||||
<h5>Garansi Tumbuh</h5>
|
|
||||||
<p class="text-muted">Garansi bibit tumbuh atau uang kembali 100%.</p>
|
|
||||||
</div>
|
|
||||||
</div> -->
|
|
||||||
<div class="col-lg-3 col-md-6">
|
|
||||||
<div class="text-center">
|
|
||||||
<div class="bg-success text-white rounded-circle mx-auto mb-3 d-flex align-items-center justify-content-center" style="width: 80px; height: 80px;">
|
|
||||||
<i class="fas fa-headset fa-2x"></i>
|
<i class="fas fa-headset fa-2x"></i>
|
||||||
</div>
|
</div>
|
||||||
<h5>Support 24/7</h5>
|
<h5>Support 24/7</h5>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue