Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
026744b461 | ||
|
|
6859a96e73 | ||
|
|
9748568c17 |
127
admin/index.php
Normal file
127
admin/index.php
Normal file
@ -0,0 +1,127 @@
|
||||
<?php include 'partials/header.php'; ?>
|
||||
|
||||
<!-- Page Content Wrapper -->
|
||||
<div id="page-content-wrapper">
|
||||
<?php include 'partials/sidebar.php'; ?>
|
||||
|
||||
<div class="container-fluid px-4">
|
||||
<div class="row my-5">
|
||||
<h3 class="fs-4 mb-3">Dashboard</h3>
|
||||
<div class="col">
|
||||
<div class="row">
|
||||
<!-- KPI Card 1 -->
|
||||
<div class="col-lg-3 col-md-6 mb-4">
|
||||
<div class="card-kpi">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<p class="mb-0 text-secondary">Total Users</p>
|
||||
<h4 class="mb-0">1,250</h4>
|
||||
</div>
|
||||
<div class="icon-circle bg-primary text-white">
|
||||
<i class="bi bi-people"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- KPI Card 2 -->
|
||||
<div class="col-lg-3 col-md-6 mb-4">
|
||||
<div class="card-kpi">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<p class="mb-0 text-secondary">Total Orders</p>
|
||||
<h4 class="mb-0">350</h4>
|
||||
</div>
|
||||
<div class="icon-circle bg-success text-white">
|
||||
<i class="bi bi-receipt"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- KPI Card 3 -->
|
||||
<div class="col-lg-3 col-md-6 mb-4">
|
||||
<div class="card-kpi">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<p class="mb-0 text-secondary">Pending Payment</p>
|
||||
<h4 class="mb-0">15</h4>
|
||||
</div>
|
||||
<div class="icon-circle bg-warning text-white">
|
||||
<i class="bi bi-hourglass-split"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- KPI Card 4 -->
|
||||
<div class="col-lg-3 col-md-6 mb-4">
|
||||
<div class="card-kpi">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<p class="mb-0 text-secondary">Website Aktif</p>
|
||||
<h4 class="mb-0">320</h4>
|
||||
</div>
|
||||
<div class="icon-circle bg-info text-white">
|
||||
<i class="bi bi-globe"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-8 mb-4">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header">
|
||||
<i class="bi bi-bar-chart-line me-1"></i>
|
||||
Statistik Order Bulanan
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<canvas id="orderChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4 mb-4">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header">
|
||||
<i class="bi bi-bell me-1"></i>
|
||||
Aktivitas Terbaru
|
||||
</div>
|
||||
<div class="list-group list-group-flush">
|
||||
<a href="#" class="list-group-item list-group-item-action">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h6 class="mb-1">Order Baru #1234</h6>
|
||||
<small>5 menit lalu</small>
|
||||
</div>
|
||||
<p class="mb-1">Paket Website UKM oleh Budi.</p>
|
||||
</a>
|
||||
<a href="#" class="list-group-item list-group-item-action">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h6 class="mb-1">User Baru</h6>
|
||||
<small>15 menit lalu</small>
|
||||
</div>
|
||||
<p class="mb-1">Siti mendaftar.</p>
|
||||
</a>
|
||||
<a href="#" class="list-group-item list-group-item-action">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h6 class="mb-1">Pembayaran Diterima #1233</h6>
|
||||
<small>1 jam lalu</small>
|
||||
</div>
|
||||
<p class="mb-1">Pembayaran dari Ahmad dikonfirmasi.</p>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include 'partials/footer.php'; ?>
|
||||
94
admin/order_detail.php
Normal file
94
admin/order_detail.php
Normal file
@ -0,0 +1,94 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../db/config.php';
|
||||
require_once __DIR__ . '/partials/header.php';
|
||||
|
||||
if (!isset($_GET['id']) || empty($_GET['id'])) {
|
||||
header('Location: orders.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$order_id = $_GET['id'];
|
||||
$pdo = db();
|
||||
|
||||
// Fetch order details
|
||||
$stmt = $pdo->prepare('SELECT * FROM orders WHERE id = ?');
|
||||
$stmt->execute([$order_id]);
|
||||
$order = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$order) {
|
||||
die('Order not found.');
|
||||
}
|
||||
|
||||
// Fetch order items
|
||||
$stmt = $pdo->prepare('SELECT oi.quantity, oi.price, p.name FROM order_items oi JOIN products p ON oi.product_id = p.id WHERE oi.order_id = ?');
|
||||
$stmt->execute([$order_id]);
|
||||
$items = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
?>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<?php require_once __DIR__ . '/partials/sidebar.php'; ?>
|
||||
|
||||
<main class="col-md-9 ms-sm-auto col-lg-10 px-md-4">
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||
<h1 class="h2">Detail Pesanan #<?php echo htmlspecialchars($order['id']); ?></h1>
|
||||
<a href="orders.php" class="btn btn-secondary">Kembali ke Daftar Pesanan</a>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h4>Informasi Pelanggan</h4>
|
||||
<p><strong>Nama:</strong> <?php echo htmlspecialchars($order['customer_name']); ?></p>
|
||||
<p><strong>Email:</strong> <?php echo htmlspecialchars($order['customer_email']); ?></p>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h4>Informasi Pesanan</h4>
|
||||
<p><strong>Total:</strong> Rp <?php echo number_format($order['total_amount'], 2, ',', '.'); ?></p>
|
||||
<p><strong>Status:</strong> <span class="badge bg-info"><?php echo htmlspecialchars($order['status']); ?></span></p>
|
||||
<p><strong>Tanggal:</strong> <?php echo date('d M Y, H:i', strtotime($order['created_at'])); ?></p>
|
||||
|
||||
<form action="order_update_status.php" method="POST" class="mt-3">
|
||||
<input type="hidden" name="order_id" value="<?php echo $order['id']; ?>">
|
||||
<div class="input-group">
|
||||
<select name="status" class="form-select">
|
||||
<option value="Pending" <?php echo ($order['status'] == 'Pending') ? 'selected' : ''; ?>>Pending</option>
|
||||
<option value="Processing" <?php echo ($order['status'] == 'Processing') ? 'selected' : ''; ?>>Processing</option>
|
||||
<option value="Shipped" <?php echo ($order['status'] == 'Shipped') ? 'selected' : ''; ?>>Shipped</option>
|
||||
<option value="Completed" <?php echo ($order['status'] == 'Completed') ? 'selected' : ''; ?>>Completed</option>
|
||||
<option value="Cancelled" <?php echo ($order['status'] == 'Cancelled') ? 'selected' : ''; ?>>Cancelled</option>
|
||||
</select>
|
||||
<button type="submit" class="btn btn-success">Update Status</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4 class="mt-4">Item Pesanan</h4>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Produk</th>
|
||||
<th>Jumlah</th>
|
||||
<th>Harga</th>
|
||||
<th>Subtotal</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($items as $item): ?>
|
||||
<tr>
|
||||
<td><?php echo htmlspecialchars($item['name']); ?></td>
|
||||
<td><?php echo htmlspecialchars($item['quantity']); ?></td>
|
||||
<td>Rp <?php echo number_format($item['price'], 2, ',', '.'); ?></td>
|
||||
<td>Rp <?php echo number_format($item['price'] * $item['quantity'], 2, ',', '.'); ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php require_once __DIR__ . '/partials/footer.php'; ?>
|
||||
31
admin/order_update_status.php
Normal file
31
admin/order_update_status.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../db/config.php';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$order_id = $_POST['order_id'];
|
||||
$status = $_POST['status'];
|
||||
|
||||
if (empty($order_id) || empty($status)) {
|
||||
header('Location: orders.php'); // Redirect if data is missing
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare('UPDATE orders SET status = ? WHERE id = ?');
|
||||
$stmt->execute([$status, $order_id]);
|
||||
|
||||
// Redirect back to the order detail page with a success message
|
||||
header('Location: order_detail.php?id=' . $order_id . '&status=updated');
|
||||
exit;
|
||||
} catch (PDOException $e) {
|
||||
// On error, redirect with an error message
|
||||
header('Location: order_detail.php?id=' . $order_id . '&status=error');
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
// If not a POST request, just redirect to the main orders page
|
||||
header('Location: orders.php');
|
||||
exit;
|
||||
?>
|
||||
61
admin/orders.php
Normal file
61
admin/orders.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../db/config.php';
|
||||
require_once __DIR__ . '/partials/header.php';
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->query('SELECT id, customer_name, total_amount, status, created_at FROM orders ORDER BY created_at DESC');
|
||||
$orders = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
} catch (PDOException $e) {
|
||||
die("Could not connect to the database: " . $e->getMessage());
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<?php require_once __DIR__ . '/partials/sidebar.php'; ?>
|
||||
|
||||
<main class="col-md-9 ms-sm-auto col-lg-10 px-md-4">
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||
<h1 class="h2">Manajemen Pesanan</h1>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID Pesanan</th>
|
||||
<th>Nama Pelanggan</th>
|
||||
<th>Total</th>
|
||||
<th>Status</th>
|
||||
<th>Tanggal</th>
|
||||
<th>Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($orders)): ?>
|
||||
<tr>
|
||||
<td colspan="6" class="text-center">Belum ada pesanan.</td>
|
||||
</tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($orders as $order): ?>
|
||||
<tr>
|
||||
<td>#<?php echo htmlspecialchars($order['id']); ?></td>
|
||||
<td><?php echo htmlspecialchars($order['customer_name']); ?></td>
|
||||
<td>Rp <?php echo number_format($order['total_amount'], 2, ',', '.'); ?></td>
|
||||
<td><span class="badge bg-info"><?php echo htmlspecialchars($order['status']); ?></span></td>
|
||||
<td><?php echo date('d M Y, H:i', strtotime($order['created_at'])); ?></td>
|
||||
<td>
|
||||
<a href="order_detail.php?id=<?php echo $order['id']; ?>" class="btn btn-sm btn-primary">Detail</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php require_once __DIR__ . '/partials/footer.php'; ?>
|
||||
11
admin/partials/footer.php
Normal file
11
admin/partials/footer.php
Normal file
@ -0,0 +1,11 @@
|
||||
</div>
|
||||
<!-- /#wrapper -->
|
||||
|
||||
<!-- Bootstrap Bundle with Popper -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<!-- Chart.js -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.2/dist/chart.umd.min.js"></script>
|
||||
<!-- Custom JS -->
|
||||
<script src="../assets/js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
19
admin/partials/header.php
Normal file
19
admin/partials/header.php
Normal file
@ -0,0 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Admin Panel</title>
|
||||
<!-- Bootstrap CSS -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- Bootstrap Icons -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css" rel="stylesheet">
|
||||
<!-- Google Fonts (Poppins) -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<!-- Custom CSS -->
|
||||
<link rel="stylesheet" href="../assets/css/custom.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="d-flex" id="wrapper">
|
||||
30
admin/partials/sidebar.php
Normal file
30
admin/partials/sidebar.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
$current_page = basename($_SERVER['REQUEST_URI']);
|
||||
?>
|
||||
<!-- Sidebar -->
|
||||
<div class="bg-white" id="sidebar-wrapper">
|
||||
<div class="sidebar-heading text-center py-4 fs-4 fw-bold text-uppercase border-bottom">
|
||||
<i class="bi bi-shield-lock me-2"></i>Admin Panel
|
||||
</div>
|
||||
<div class="list-group list-group-flush my-3">
|
||||
<a href="/admin/" class="list-group-item list-group-item-action <?php echo ($current_page == 'admin' || $current_page == 'index.php') ? 'active' : ''; ?>">
|
||||
<i class="bi bi-speedometer2 me-2"></i>Dashboard
|
||||
</a>
|
||||
<a href="users.php" class="list-group-item list-group-item-action <?php echo ($current_page == 'users.php') ? 'active' : ''; ?>">
|
||||
<i class="bi bi-people me-2"></i>Manajemen User
|
||||
</a>
|
||||
<a href="products.php" class="list-group-item list-group-item-action <?php echo ($current_page == 'products.php') ? 'active' : ''; ?>">
|
||||
<i class="bi bi-box-seam me-2"></i>Manajemen Produk
|
||||
</a>
|
||||
<a href="orders.php" class="list-group-item list-group-item-action <?php echo ($current_page == 'orders.php') ? 'active' : ''; ?>">
|
||||
<i class="bi bi-receipt me-2"></i>Manajemen Order
|
||||
</a>
|
||||
<a href="settings.php" class="list-group-item list-group-item-action <?php echo ($current_page == 'settings.php') ? 'active' : ''; ?>">
|
||||
<i class="bi bi-gear me-2"></i>Pengaturan
|
||||
</a>
|
||||
<a href="/" class="list-group-item list-group-item-action bg-light">
|
||||
<i class="bi bi-box-arrow-left me-2"></i>Kembali ke Situs
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /#sidebar-wrapper -->
|
||||
62
admin/product_add.php
Normal file
62
admin/product_add.php
Normal file
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
// This page contains the form to add a new product.
|
||||
|
||||
// Include header
|
||||
include 'partials/header.php';
|
||||
?>
|
||||
|
||||
<div id="page-content-wrapper">
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-transparent py-4 px-4">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="bi bi-list fs-4 me-3" id="menu-toggle"></i>
|
||||
<h2 class="fs-2 m-0">Tambah Produk Baru</h2>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container-fluid px-4">
|
||||
<div class="row my-5">
|
||||
<div class="col">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<form action="product_create.php" method="POST" enctype="multipart/form-data">
|
||||
<div class="mb-3">
|
||||
<label for="name" class="form-label">Nama Produk</label>
|
||||
<input type="text" class="form-control" id="name" name="name" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="price" class="form-label">Harga</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">Rp</span>
|
||||
<input type="number" class="form-control" id="price" name="price" min="0" step="any" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="duration" class="form-label">Durasi Pengerjaan</label>
|
||||
<input type="text" class="form-control" id="duration" name="duration" placeholder="Contoh: 3-5 hari kerja" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="description" class="form-label">Deskripsi Singkat</label>
|
||||
<textarea class="form-control" id="description" name="description" rows="3" required></textarea>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="features" class="form-label">Fitur-fitur (pisahkan dengan koma)</label>
|
||||
<textarea class="form-control" id="features" name="features" rows="3" placeholder="Contoh: Domain .com, Hosting 2GB, SSL Gratis"></textarea>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="thumbnail" class="form-label">Thumbnail</label>
|
||||
<input class="form-control" type="file" id="thumbnail" name="thumbnail" accept="image/png, image/jpeg, image/gif">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Simpan Produk</button>
|
||||
<a href="products.php" class="btn btn-secondary">Batal</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
// Include footer
|
||||
include 'partials/footer.php';
|
||||
?>
|
||||
61
admin/product_create.php
Normal file
61
admin/product_create.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
require_once '../db/config.php';
|
||||
|
||||
// Check if the form was submitted
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||
// --- Basic Form Data ---
|
||||
$name = trim($_POST['name']);
|
||||
$price = trim($_POST['price']);
|
||||
$duration = trim($_POST['duration']);
|
||||
$description = trim($_POST['description']);
|
||||
$features = trim($_POST['features']);
|
||||
$thumbnail_url = null; // Default to null
|
||||
|
||||
// --- Thumbnail Upload Handling ---
|
||||
if (isset($_FILES['thumbnail']) && $_FILES['thumbnail']['error'] == UPLOAD_ERR_OK) {
|
||||
$upload_dir = '../assets/uploads/products/';
|
||||
// Create directory if it doesn't exist
|
||||
if (!is_dir($upload_dir)) {
|
||||
mkdir($upload_dir, 0777, true);
|
||||
}
|
||||
|
||||
$file_info = pathinfo($_FILES['thumbnail']['name']);
|
||||
$file_ext = $file_info['extension'];
|
||||
$safe_filename = uniqid('product_', true) . '.' . $file_ext;
|
||||
$target_path = $upload_dir . $safe_filename;
|
||||
|
||||
// Move the file
|
||||
if (move_uploaded_file($_FILES['thumbnail']['tmp_name'], $target_path)) {
|
||||
// Store relative path for DB
|
||||
$thumbnail_url = 'assets/uploads/products/' . $safe_filename;
|
||||
} else {
|
||||
// Optional: Handle file move error
|
||||
header("Location: products.php?status=error&message=Gagal memindahkan file thumbnail.");
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
// --- Database Insertion ---
|
||||
try {
|
||||
$pdo = db();
|
||||
$sql = "INSERT INTO products (name, price, duration, description, features, thumbnail_url) VALUES (?, ?, ?, ?, ?, ?)";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
|
||||
// Bind parameters and execute
|
||||
$stmt->execute([$name, $price, $duration, $description, $features, $thumbnail_url]);
|
||||
|
||||
// Redirect with success message
|
||||
header("Location: products.php?status=success&message=Produk berhasil ditambahkan.");
|
||||
exit;
|
||||
|
||||
} catch (PDOException $e) {
|
||||
// Redirect with error message
|
||||
// For development, you might want to log the error: error_log($e->getMessage());
|
||||
header("Location: products.php?status=error&message=Database error: " . urlencode($e->getMessage()));
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
// If not a POST request, redirect to the add form
|
||||
header("Location: product_add.php");
|
||||
exit;
|
||||
}
|
||||
38
admin/product_delete.php
Normal file
38
admin/product_delete.php
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
require_once '../db/config.php';
|
||||
|
||||
// Check if ID is provided
|
||||
if (!isset($_GET['id']) || empty($_GET['id'])) {
|
||||
header('Location: products.php?status=error&message=ID Produk tidak valid.');
|
||||
exit;
|
||||
}
|
||||
|
||||
$product_id = $_GET['id'];
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
|
||||
// First, get the thumbnail path to delete the file
|
||||
$stmt = $pdo->prepare("SELECT thumbnail_url FROM products WHERE id = ?");
|
||||
$stmt->execute([$product_id]);
|
||||
$thumbnail_url = $stmt->fetchColumn();
|
||||
|
||||
// Delete the product from the database
|
||||
$stmt = $pdo->prepare("DELETE FROM products WHERE id = ?");
|
||||
|
||||
if ($stmt->execute([$product_id])) {
|
||||
// If deletion from DB is successful, delete the thumbnail file
|
||||
if ($thumbnail_url && file_exists('../' . $thumbnail_url)) {
|
||||
unlink('../' . $thumbnail_url);
|
||||
}
|
||||
header('Location: products.php?status=success&message=Produk berhasil dihapus.');
|
||||
} else {
|
||||
throw new Exception("Gagal menghapus produk dari database.");
|
||||
}
|
||||
|
||||
} catch (PDOException $e) {
|
||||
header('Location: products.php?status=error&message=Database error: ' . $e->getMessage());
|
||||
} catch (Exception $e) {
|
||||
header('Location: products.php?status=error&message=' . $e->getMessage());
|
||||
}
|
||||
exit;
|
||||
98
admin/product_edit.php
Normal file
98
admin/product_edit.php
Normal file
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
require_once '../db/config.php';
|
||||
|
||||
// Check if ID is provided
|
||||
if (!isset($_GET['id']) || empty($_GET['id'])) {
|
||||
header('Location: products.php?status=error&message=ID Produk tidak valid.');
|
||||
exit;
|
||||
}
|
||||
|
||||
$product_id = $_GET['id'];
|
||||
$product = null;
|
||||
$error_message = '';
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare("SELECT * FROM products WHERE id = ?");
|
||||
$stmt->execute([$product_id]);
|
||||
$product = $stmt->fetch();
|
||||
|
||||
if (!$product) {
|
||||
throw new Exception("Produk tidak ditemukan.");
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$error_message = "Error fetching product: " . $e->getMessage();
|
||||
} catch (Exception $e) {
|
||||
$error_message = $e->getMessage();
|
||||
}
|
||||
|
||||
// Include header
|
||||
include 'partials/header.php';
|
||||
?>
|
||||
|
||||
<div id="page-content-wrapper">
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-transparent py-4 px-4">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="bi bi-list fs-4 me-3" id="menu-toggle"></i>
|
||||
<h2 class="fs-2 m-0">Edit Produk</h2>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container-fluid px-4">
|
||||
<?php if ($error_message): ?>
|
||||
<div class="alert alert-danger"><?php echo $error_message; ?></div>
|
||||
<?php elseif ($product): ?>
|
||||
<div class="row my-5">
|
||||
<div class="col">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<form action="product_update.php" method="POST" enctype="multipart/form-data">
|
||||
<input type="hidden" name="id" value="<?php echo htmlspecialchars($product['id']); ?>">
|
||||
<div class="mb-3">
|
||||
<label for="name" class="form-label">Nama Produk</label>
|
||||
<input type="text" class="form-control" id="name" name="name" value="<?php echo htmlspecialchars($product['name']); ?>" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="price" class="form-label">Harga</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">Rp</span>
|
||||
<input type="number" class="form-control" id="price" name="price" min="0" step="any" value="<?php echo htmlspecialchars($product['price']); ?>" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="duration" class="form-label">Durasi Pengerjaan</label>
|
||||
<input type="text" class="form-control" id="duration" name="duration" placeholder="Contoh: 3-5 hari kerja" value="<?php echo htmlspecialchars($product['duration']); ?>" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="description" class="form-label">Deskripsi Singkat</label>
|
||||
<textarea class="form-control" id="description" name="description" rows="3" required><?php echo htmlspecialchars($product['description']); ?></textarea>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="features" class="form-label">Fitur-fitur (pisahkan dengan koma)</label>
|
||||
<textarea class="form-control" id="features" name="features" rows="3" placeholder="Contoh: Domain .com, Hosting 2GB, SSL Gratis"><?php echo htmlspecialchars($product['features']); ?></textarea>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="thumbnail" class="form-label">Thumbnail</label>
|
||||
<input class="form-control" type="file" id="thumbnail" name="thumbnail" accept="image/png, image/jpeg, image/gif">
|
||||
<?php if ($product['thumbnail_url']): ?>
|
||||
<div class="mt-2">
|
||||
<small>Thumbnail saat ini:</small><br>
|
||||
<img src="../<?php echo htmlspecialchars($product['thumbnail_url']); ?>" alt="<?php echo htmlspecialchars($product['name']); ?>" width="150">
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Simpan Perubahan</button>
|
||||
<a href="products.php" class="btn btn-secondary">Batal</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
// Include footer
|
||||
include 'partials/footer.php';
|
||||
?>
|
||||
88
admin/product_update.php
Normal file
88
admin/product_update.php
Normal file
@ -0,0 +1,88 @@
|
||||
<?php
|
||||
require_once '../db/config.php';
|
||||
|
||||
// Check if it's a POST request
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
header('Location: products.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
// Basic validation
|
||||
$required_fields = ['id', 'name', 'price', 'duration', 'description'];
|
||||
foreach ($required_fields as $field) {
|
||||
if (empty($_POST[$field])) {
|
||||
header('Location: product_edit.php?id=' . $_POST['id'] . '&status=error&message=Semua field wajib diisi.');
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
$product_id = $_POST['id'];
|
||||
$name = $_POST['name'];
|
||||
$price = $_POST['price'];
|
||||
$duration = $_POST['duration'];
|
||||
$description = $_POST['description'];
|
||||
$features = $_POST['features'] ?? '';
|
||||
$thumbnail_path = null;
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
|
||||
// First, get the current thumbnail path
|
||||
$stmt = $pdo->prepare("SELECT thumbnail_url FROM products WHERE id = ?");
|
||||
$stmt->execute([$product_id]);
|
||||
$current_thumbnail = $stmt->fetchColumn();
|
||||
|
||||
// Handle file upload
|
||||
if (isset($_FILES['thumbnail']) && $_FILES['thumbnail']['error'] == UPLOAD_ERR_OK) {
|
||||
$upload_dir = '../assets/uploads/';
|
||||
if (!is_dir($upload_dir)) {
|
||||
mkdir($upload_dir, 0777, true);
|
||||
}
|
||||
|
||||
$filename = uniqid() . '-' . basename($_FILES['thumbnail']['name']);
|
||||
$target_file = $upload_dir . $filename;
|
||||
$imageFileType = strtolower(pathinfo($target_file, PATHINFO_EXTENSION));
|
||||
|
||||
// Basic validation for image
|
||||
$check = getimagesize($_FILES['thumbnail']['tmp_name']);
|
||||
if ($check === false) {
|
||||
header('Location: product_edit.php?id=' . $product_id . '&status=error&message=File bukan gambar.');
|
||||
exit;
|
||||
}
|
||||
if (!in_array($imageFileType, ['jpg', 'png', 'jpeg', 'gif'])) {
|
||||
header('Location: product_edit.php?id=' . $product_id . '&status=error&message=Hanya format JPG, JPEG, PNG & GIF yang diperbolehkan.');
|
||||
exit;
|
||||
}
|
||||
|
||||
if (move_uploaded_file($_FILES['thumbnail']['tmp_name'], $target_file)) {
|
||||
$thumbnail_path = 'assets/uploads/' . $filename;
|
||||
// Delete the old thumbnail if a new one is uploaded
|
||||
if ($current_thumbnail && file_exists('../' . $current_thumbnail)) {
|
||||
unlink('../' . $current_thumbnail);
|
||||
}
|
||||
} else {
|
||||
header('Location: product_edit.php?id=' . $product_id . '&status=error&message=Gagal mengunggah thumbnail.');
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
// Keep the old thumbnail if no new one is uploaded
|
||||
$thumbnail_path = $current_thumbnail;
|
||||
}
|
||||
|
||||
// Update data in the database
|
||||
$sql = "UPDATE products SET name = ?, price = ?, duration = ?, description = ?, features = ?, thumbnail_url = ? WHERE id = ?";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
|
||||
if ($stmt->execute([$name, $price, $duration, $description, $features, $thumbnail_path, $product_id])) {
|
||||
header('Location: products.php?status=success&message=Produk berhasil diperbarui.');
|
||||
} else {
|
||||
throw new Exception("Gagal memperbarui produk di database.");
|
||||
}
|
||||
|
||||
} catch (PDOException $e) {
|
||||
// Redirect with a generic error
|
||||
header('Location: product_edit.php?id=' . $product_id . '&status=error&message=Database error: ' . $e->getMessage());
|
||||
} catch (Exception $e) {
|
||||
header('Location: product_edit.php?id=' . $product_id . '&status=error&message=' . $e->getMessage());
|
||||
}
|
||||
exit;
|
||||
1
admin/products.php
Normal file
1
admin/products.php
Normal file
@ -0,0 +1 @@
|
||||
<?php\nrequire_once \'../db/config.php\';\n\n// Fetch all products from the database\ntry {\n $pdo = db();\n $stmt = $pdo->query(\"SELECT * FROM products ORDER BY created_at DESC\");\n $products = $stmt->fetchAll();\n} catch (PDOException $e) {\n // For now, just display a generic error\n // In a real app, you\'d want to log this error\n $products = [];\n $db_error = \"Error fetching products: \" . $e->getMessage();\n}\n\n// Include header\ninclude \'partials/header.php\';\n?>\n\n<div id=\"page-content-wrapper\">\n <nav class=\"navbar navbar-expand-lg navbar-light bg-transparent py-4 px-4\">\n <div class=\"d-flex align-items-center\">\n <i class=\"bi bi-list fs-4 me-3\" id=\"menu-toggle\"></i>\n <h2 class=\"fs-2 m-0\">Manajemen Produk</h2>\n </div>\n </nav>\n\n <div class=\"container-fluid px-4\">\n\n <?php if (isset($_GET[\'status\'])):\ ?>\n <div class=\"alert alert-<?php echo $_GET[\'status\'] == \'success\' ? \'success\' : \'danger\'; ?> alert-dismissible fade show\" role=\"alert\">\n <?php echo htmlspecialchars($_GET[\'message\']); ?>\n <button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"alert\" aria-label=\"Close\"></button>\n </div>\n <?php endif; ?>\n\n <?php if (isset($db_error)): ?>\n <div class=\"alert alert-danger\"> <?php echo $db_error; ?></div>\n <?php endif; ?>\n\n <div class=\"row my-5\">\n <div class=\"col\">\n <a href=\"product_add.php\" class=\"btn btn-primary mb-3\"><i class=\"bi bi-plus-lg\"></i> Tambah Produk</a>\n <div class=\"card shadow-sm\">\n <div class=\"card-body\">\n <h3 class=\"fs-4 mb-3\">Daftar Produk</h3>\n <div class=\"table-responsive\">\n <table class=\"table table-hover\">\n <thead>\n <tr>\n <th scope=\"col\">Thumbnail</th>\n <th scope=\"col\">Nama</th>\n <th scope=\"col\">Harga</th>\n <th scope=\"col\">Durasi</th>\n <th scope=\"col\">Aksi</th>\n </tr>\n </thead>\n <tbody>\n <?php if (empty($products)): ?>\n <tr>\n <td colspan=\"5\" class=\"text-center\">Belum ada produk.</td>\n </tr>\n <?php else: ?>\n <?php foreach ($products as $product): ?>\n <tr>\n <td>\n <?php if ($product[\'thumbnail_url\']): ?>\n <img src=\"../<?php echo htmlspecialchars($product[\'thumbnail_url\']); ?>\" alt=\"<?php echo htmlspecialchars($product[\'name\']); ?>\" width=\"100\">\n <?php else: ?>\n <span class=\"text-muted\">No Image</span>\n <?php endif; ?>\n </td>\n <td><?php echo htmlspecialchars($product[\'name\']); ?></td>\n <td>Rp <?php echo number_format($product[\'price\'], 0, \',\', \'.\'); ?></td>\n <td><?php echo htmlspecialchars($product[\'duration\']); ?></td>\n <td>\n <a href=\"product_edit.php?id=<?php echo $product[\'id\']; ?>\" class=\"btn btn-sm btn-outline-primary\"><i class=\"bi bi-pencil-square\"></i></a>\n <a href=\"product_delete.php?id=<?php echo $product[\'id\']; ?>\" class=\"btn btn-sm btn-outline-danger\" onclick=\"return confirm(\'Anda yakin ingin menghapus produk ini?\');\"><i class=\"bi bi-trash\"></i></a>\n </td>\n </tr>\n <?php endforeach; ?>\n <?php endif; ?>\n </tbody>\n </table>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</div>\n\n<?php\n// Include footer\ninclude \'partials/footer.php\';\n?>\n
|
||||
73
admin/settings.php
Normal file
73
admin/settings.php
Normal file
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../db/config.php';
|
||||
|
||||
$pdo = db();
|
||||
|
||||
// Handle form submission
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$site_name = $_POST['site_name'] ?? '';
|
||||
$contact_email = $_POST['contact_email'] ?? '';
|
||||
|
||||
try {
|
||||
$stmt = $pdo->prepare("UPDATE settings SET setting_value = :value WHERE setting_name = :name");
|
||||
$stmt->execute(['value' => $site_name, 'name' => 'site_name']);
|
||||
$stmt->execute(['value' => $contact_email, 'name' => 'contact_email']);
|
||||
$success_message = "Settings updated successfully!";
|
||||
} catch (PDOException $e) {
|
||||
$error_message = "Error updating settings: " . $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch current settings
|
||||
$stmt = $pdo->query("SELECT * FROM settings");
|
||||
$settings = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
|
||||
|
||||
$site_name = $settings['site_name'] ?? '';
|
||||
$contact_email = $settings['contact_email'] ?? '';
|
||||
|
||||
$page_title = "Settings";
|
||||
include 'partials/header.php';
|
||||
?>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<?php include 'partials/sidebar.php'; ?>
|
||||
|
||||
<main class="col-md-9 ms-sm-auto col-lg-10 px-md-4">
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||
<h1 class="h2">Settings</h1>
|
||||
</div>
|
||||
|
||||
<?php if (isset($success_message)): ?>
|
||||
<div class="alert alert-success" role="alert">
|
||||
<?php echo $success_message; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if (isset($error_message)): ?>
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<?php echo $error_message; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">General Settings</h5>
|
||||
<form action="settings.php" method="POST">
|
||||
<div class="mb-3">
|
||||
<label for="site_name" class="form-label">Site Name</label>
|
||||
<input type="text" class="form-control" id="site_name" name="site_name" value="<?php echo htmlspecialchars($site_name); ?>" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="contact_email" class="form-label">Contact Email</label>
|
||||
<input type="email" class="form-control" id="contact_email" name="contact_email" value="<?php echo htmlspecialchars($contact_email); ?>" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Save Settings</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include 'partials/footer.php'; ?>
|
||||
54
admin/user_add.php
Normal file
54
admin/user_add.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
// This page contains the form to add a new user.
|
||||
|
||||
// Include header
|
||||
include 'partials/header.php';
|
||||
?>
|
||||
|
||||
<div id="page-content-wrapper">
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-transparent py-4 px-4">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="bi bi-list fs-4 me-3" id="menu-toggle"></i>
|
||||
<h2 class="fs-2 m-0">Tambah Pengguna Baru</h2>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container-fluid px-4">
|
||||
<div class="row my-5">
|
||||
<div class="col">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<form action="user_create.php" method="POST">
|
||||
<div class="mb-3">
|
||||
<label for="name" class="form-label">Nama Lengkap</label>
|
||||
<input type="text" class="form-control" id="name" name="name" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="email" class="form-label">Alamat Email</label>
|
||||
<input type="email" class="form-control" id="email" name="email" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label">Password</label>
|
||||
<input type="password" class="form-control" id="password" name="password" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="role" class="form-label">Peran</label>
|
||||
<select class="form-select" id="role" name="role">
|
||||
<option value="user" selected>User</option>
|
||||
<option value="admin">Admin</option>
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Simpan Pengguna</button>
|
||||
<a href="users.php" class="btn btn-secondary">Batal</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
// Include footer
|
||||
include 'partials/footer.php';
|
||||
?>
|
||||
53
admin/user_create.php
Normal file
53
admin/user_create.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
require_once '../db/config.php';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
// Get form data
|
||||
$name = trim($_POST['name']);
|
||||
$email = trim($_POST['email']);
|
||||
$password = $_POST['password']; // No trim on password
|
||||
$role = $_POST['role'];
|
||||
|
||||
// Validate data
|
||||
if (empty($name) || empty($email) || empty($password) || empty($role)) {
|
||||
header("Location: users.php?status=danger&message=" . urlencode('Semua kolom harus diisi.'));
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
header("Location: users.php?status=danger&message=" . urlencode('Format email tidak valid.'));
|
||||
exit;
|
||||
}
|
||||
|
||||
// Hash the password for security
|
||||
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
|
||||
|
||||
// Insert into database
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare("INSERT INTO users (name, email, password, role) VALUES (:name, :email, :password, :role)");
|
||||
$stmt->execute([
|
||||
':name' => $name,
|
||||
':email' => $email,
|
||||
':password' => $hashed_password,
|
||||
':role' => $role
|
||||
]);
|
||||
|
||||
header("Location: users.php?status=success&message=" . urlencode('Pengguna baru berhasil ditambahkan.'));
|
||||
exit;
|
||||
|
||||
} catch (PDOException $e) {
|
||||
$message = 'Gagal menambahkan pengguna.';
|
||||
// Check for duplicate email
|
||||
if ($e->errorInfo[1] == 1062) { // 1062 is the MySQL error code for duplicate entry
|
||||
$message = 'Email sudah terdaftar. Silakan gunakan email lain.';
|
||||
}
|
||||
header("Location: users.php?status=danger&message=" . urlencode($message));
|
||||
exit;
|
||||
}
|
||||
|
||||
} else {
|
||||
// Redirect if not a POST request
|
||||
header('Location: user_add.php');
|
||||
exit;
|
||||
}
|
||||
34
admin/user_delete.php
Normal file
34
admin/user_delete.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
require_once '../db/config.php';
|
||||
|
||||
// Check for user ID
|
||||
if (!isset($_GET['id'])) {
|
||||
header("Location: users.php?status=danger&message=" . urlencode('ID pengguna tidak ditemukan.'));
|
||||
exit;
|
||||
}
|
||||
|
||||
$user_id = $_GET['id'];
|
||||
|
||||
// Prevent deleting user with ID 1 (super admin, for example)
|
||||
if ($user_id == 1) {
|
||||
header("Location: users.php?status=danger&message=" . urlencode('Pengguna utama tidak dapat dihapus.'));
|
||||
exit;
|
||||
}
|
||||
|
||||
// Delete from database
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare("DELETE FROM users WHERE id = :id");
|
||||
$stmt->execute(['id' => $user_id]);
|
||||
|
||||
if ($stmt->rowCount() > 0) {
|
||||
header("Location: users.php?status=success&message=" . urlencode('Pengguna berhasil dihapus.'));
|
||||
} else {
|
||||
header("Location: users.php?status=danger&message=" . urlencode('Pengguna tidak ditemukan atau sudah dihapus.'));
|
||||
}
|
||||
exit;
|
||||
|
||||
} catch (PDOException $e) {
|
||||
header("Location: users.php?status=danger&message=" . urlencode('Gagal menghapus pengguna.'));
|
||||
exit;
|
||||
}
|
||||
80
admin/user_edit.php
Normal file
80
admin/user_edit.php
Normal file
@ -0,0 +1,80 @@
|
||||
<?php
|
||||
require_once '../db/config.php';
|
||||
|
||||
// Check for user ID
|
||||
if (!isset($_GET['id'])) {
|
||||
header("Location: users.php?status=danger&message=" . urlencode('ID pengguna tidak ditemukan.'));
|
||||
exit;
|
||||
}
|
||||
|
||||
$user_id = $_GET['id'];
|
||||
|
||||
// Fetch user data
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = :id");
|
||||
$stmt->execute(['id' => $user_id]);
|
||||
$user = $stmt->fetch();
|
||||
|
||||
if (!$user) {
|
||||
header("Location: users.php?status=danger&message=" . urlencode('Pengguna tidak ditemukan.'));
|
||||
exit;
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
header("Location: users.php?status=danger&message=" . urlencode('Gagal mengambil data pengguna.'));
|
||||
exit;
|
||||
}
|
||||
|
||||
// Include header
|
||||
include 'partials/header.php';
|
||||
?>
|
||||
|
||||
<div id="page-content-wrapper">
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-transparent py-4 px-4">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="bi bi-list fs-4 me-3" id="menu-toggle"></i>
|
||||
<h2 class="fs-2 m-0">Edit Pengguna</h2>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container-fluid px-4">
|
||||
<div class="row my-5">
|
||||
<div class="col">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<form action="user_update.php" method="POST">
|
||||
<input type="hidden" name="id" value="<?php echo $user['id']; ?>">
|
||||
<div class="mb-3">
|
||||
<label for="name" class="form-label">Nama Lengkap</label>
|
||||
<input type="text" class="form-control" id="name" name="name" value="<?php echo htmlspecialchars($user['name']); ?>" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="email" class="form-label">Alamat Email</label>
|
||||
<input type="email" class="form-control" id="email" name="email" value="<?php echo htmlspecialchars($user['email']); ?>" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label">Password (opsional)</label>
|
||||
<input type="password" class="form-control" id="password" name="password">
|
||||
<small class="form-text text-muted">Kosongkan jika tidak ingin mengubah password.</small>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="role" class="form-label">Peran</label>
|
||||
<select class="form-select" id="role" name="role">
|
||||
<option value="user" <?php echo ($user['role'] == 'user') ? 'selected' : ''; ?>>User</option>
|
||||
<option value="admin" <?php echo ($user['role'] == 'admin') ? 'selected' : ''; ?>>Admin</option>
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Simpan Perubahan</button>
|
||||
<a href="users.php" class="btn btn-secondary">Batal</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
// Include footer
|
||||
include 'partials/footer.php';
|
||||
?>
|
||||
62
admin/user_update.php
Normal file
62
admin/user_update.php
Normal file
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
require_once '../db/config.php';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
// Get form data
|
||||
$id = $_POST['id'];
|
||||
$name = trim($_POST['name']);
|
||||
$email = trim($_POST['email']);
|
||||
$password = $_POST['password']; // No trim on password
|
||||
$role = $_POST['role'];
|
||||
|
||||
// Validate data
|
||||
if (empty($id) || empty($name) || empty($email) || empty($role)) {
|
||||
header("Location: users.php?status=danger&message=" . urlencode('Semua kolom harus diisi.'));
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
header("Location: users.php?status=danger&message=" . urlencode('Format email tidak valid.'));
|
||||
exit;
|
||||
}
|
||||
|
||||
// Prepare SQL statement
|
||||
$sql = "UPDATE users SET name = :name, email = :email, role = :role";
|
||||
$params = [
|
||||
':id' => $id,
|
||||
':name' => $name,
|
||||
':email' => $email,
|
||||
':role' => $role
|
||||
];
|
||||
|
||||
// Handle password update
|
||||
if (!empty($password)) {
|
||||
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
|
||||
$sql .= ", password = :password";
|
||||
$params[':password'] = $hashed_password;
|
||||
}
|
||||
|
||||
$sql .= " WHERE id = :id";
|
||||
|
||||
// Update database
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute($params);
|
||||
|
||||
header("Location: users.php?status=success&message=" . urlencode('Data pengguna berhasil diperbarui.'));
|
||||
exit;
|
||||
|
||||
} catch (PDOException $e) {
|
||||
$message = 'Gagal memperbarui data pengguna.';
|
||||
if ($e->errorInfo[1] == 1062) {
|
||||
$message = 'Email sudah terdaftar. Silakan gunakan email lain.';
|
||||
}
|
||||
header("Location: users.php?status=danger&message=" . urlencode($message));
|
||||
exit;
|
||||
}
|
||||
|
||||
} else {
|
||||
header('Location: users.php');
|
||||
exit;
|
||||
}
|
||||
85
admin/users.php
Normal file
85
admin/users.php
Normal file
@ -0,0 +1,85 @@
|
||||
<?php
|
||||
require_once '../db/config.php';
|
||||
|
||||
// Fetch all users from the database
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->query("SELECT * FROM users ORDER BY created_at DESC");
|
||||
$users = $stmt->fetchAll();
|
||||
} catch (PDOException $e) {
|
||||
$users = [];
|
||||
$db_error = "Error fetching users: " . $e->getMessage();
|
||||
}
|
||||
|
||||
// Include header
|
||||
include 'partials/header.php';
|
||||
?>
|
||||
|
||||
<div id="page-content-wrapper">
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-transparent py-4 px-4">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="bi bi-list fs-4 me-3" id="menu-toggle"></i>
|
||||
<h2 class="fs-2 m-0">Manajemen Pengguna</h2>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container-fluid px-4">
|
||||
|
||||
<?php if (isset($_GET['status'])) : ?>
|
||||
<div class="alert alert-<?php echo $_GET['status'] == 'success' ? 'success' : 'danger'; ?> alert-dismissible fade show" role="alert">
|
||||
<?php echo htmlspecialchars($_GET['message']); ?>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (isset($db_error)) : ?>
|
||||
<div class="alert alert-danger"> <?php echo $db_error; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="row my-5">
|
||||
<div class="col">
|
||||
<a href="user_add.php" class="btn btn-primary mb-3"><i class="bi bi-plus-lg"></i> Tambah Pengguna</a>
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<h3 class="fs-4 mb-3">Daftar Pengguna</h3>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">#</th>
|
||||
<th scope="col">Nama</th>
|
||||
<th scope="col">Email</th>
|
||||
<th scope="col">Peran</th>
|
||||
<th scope="col">Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($users)) : ?>
|
||||
<tr>
|
||||
<td colspan="5" class="text-center">Belum ada pengguna.</td>
|
||||
</tr>
|
||||
<?php else : ?>
|
||||
<?php foreach ($users as $key => $user) : ?>
|
||||
<tr>
|
||||
<th scope="row"><?php echo $key + 1; ?></th>
|
||||
<td><?php echo htmlspecialchars($user['name']); ?></td>
|
||||
<td><?php echo htmlspecialchars($user['email']); ?></td>
|
||||
<td><?php echo htmlspecialchars($user['role']); ?></td>
|
||||
<td>
|
||||
<a href="user_edit.php?id=<?php echo $user['id']; ?>" class="btn btn-sm btn-primary">Edit</a>
|
||||
<a href="user_delete.php?id=<?php echo $user['id']; ?>" class="btn btn-sm btn-danger" onclick="return confirm('Anda yakin ingin menghapus pengguna ini?');">Hapus</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include 'partials/footer.php'; ?>
|
||||
76
assets/css/custom.css
Normal file
76
assets/css/custom.css
Normal file
@ -0,0 +1,76 @@
|
||||
:root {
|
||||
--primary-color: #0050A0;
|
||||
--secondary-color: #F2B705;
|
||||
--bg-light: #F8F9FA;
|
||||
--surface-white: #FFFFFF;
|
||||
--text-dark: #212529;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Poppins', sans-serif;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
#wrapper {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#sidebar-wrapper {
|
||||
min-height: 100vh;
|
||||
width: 250px;
|
||||
transition: margin .25s ease-out;
|
||||
border-right: 1px solid #ddd;
|
||||
}
|
||||
|
||||
#sidebar-wrapper .sidebar-heading {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
#sidebar-wrapper .list-group-item {
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
color: #555;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
#sidebar-wrapper .list-group-item.active {
|
||||
background-color: var(--primary-color);
|
||||
color: var(--surface-white);
|
||||
border-left: 5px solid var(--secondary-color);
|
||||
}
|
||||
|
||||
#sidebar-wrapper .list-group-item:hover:not(.active) {
|
||||
background-color: var(--bg-light);
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
#page-content-wrapper {
|
||||
flex: 1;
|
||||
background-color: var(--bg-light);
|
||||
}
|
||||
|
||||
.card-kpi {
|
||||
border: none;
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.05);
|
||||
transition: transform .2s;
|
||||
}
|
||||
|
||||
.card-kpi:hover {
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
|
||||
.card-kpi .icon-circle {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.card.shadow-sm {
|
||||
border-radius: 0.75rem;
|
||||
border: none;
|
||||
}
|
||||
33
assets/js/main.js
Normal file
33
assets/js/main.js
Normal file
@ -0,0 +1,33 @@
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
const ctx = document.getElementById('orderChart');
|
||||
if (ctx) {
|
||||
new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'Mei', 'Jun', 'Jul', 'Ags', 'Sep', 'Okt', 'Nov', 'Des'],
|
||||
datasets: [{
|
||||
label: 'Jumlah Order',
|
||||
data: [12, 19, 3, 5, 2, 3, 7, 8, 10, 15, 9, 11],
|
||||
backgroundColor: 'rgba(0, 80, 160, 0.7)',
|
||||
borderColor: 'rgba(0, 80, 160, 1)',
|
||||
borderWidth: 1,
|
||||
borderRadius: 5
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
BIN
assets/pasted-20251209-065206-934bc4d3.png
Normal file
BIN
assets/pasted-20251209-065206-934bc4d3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 111 KiB |
36
db/migration_orders.php
Normal file
36
db/migration_orders.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/config.php';
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
|
||||
// Create orders table
|
||||
$pdo->exec("
|
||||
CREATE TABLE IF NOT EXISTS `orders` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`customer_name` VARCHAR(255) NOT NULL,
|
||||
`customer_email` VARCHAR(255) NOT NULL,
|
||||
`total_amount` DECIMAL(10, 2) NOT NULL,
|
||||
`status` VARCHAR(50) NOT NULL DEFAULT 'Pending',
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
");
|
||||
|
||||
// Create order_items table
|
||||
$pdo->exec("
|
||||
CREATE TABLE IF NOT EXISTS `order_items` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`order_id` INT NOT NULL,
|
||||
`product_id` INT NOT NULL,
|
||||
`quantity` INT NOT NULL,
|
||||
`price` DECIMAL(10, 2) NOT NULL,
|
||||
FOREIGN KEY (`order_id`) REFERENCES `orders`(`id`) ON DELETE CASCADE,
|
||||
FOREIGN KEY (`product_id`) REFERENCES `products`(`id`) ON DELETE RESTRICT
|
||||
)
|
||||
");
|
||||
|
||||
echo "Tables 'orders' and 'order_items' created successfully." . PHP_EOL;
|
||||
|
||||
} catch (PDOException $e) {
|
||||
die("DB ERROR: " . $e->getMessage());
|
||||
}
|
||||
15
db/migration_products.php
Normal file
15
db/migration_products.php
Normal file
@ -0,0 +1,15 @@
|
||||
<?php
|
||||
require_once 'config.php';
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
|
||||
$sql = "CREATE TABLE IF NOT EXISTS `products` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, `price` decimal(10,2) NOT NULL, `duration` varchar(255) NOT NULL, `description` text NOT NULL, `features` text DEFAULT NULL, `thumbnail_url` varchar(255) DEFAULT NULL, `created_at` timestamp NOT NULL DEFAULT current_timestamp(), `updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";
|
||||
|
||||
$pdo->exec($sql);
|
||||
|
||||
echo "Table 'products' created successfully.";
|
||||
|
||||
} catch (PDOException $e) {
|
||||
die("DB ERROR: ". $e->getMessage());
|
||||
}
|
||||
30
db/migration_settings.php
Normal file
30
db/migration_settings.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
require_once 'config.php';
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$sql = "
|
||||
CREATE TABLE IF NOT EXISTS settings (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
setting_name VARCHAR(255) NOT NULL UNIQUE,
|
||||
setting_value TEXT
|
||||
);
|
||||
";
|
||||
$pdo->exec($sql);
|
||||
|
||||
// Insert default settings if they don't exist
|
||||
$defaults = [
|
||||
'site_name' => 'My Awesome Site',
|
||||
'contact_email' => 'contact@example.com'
|
||||
];
|
||||
|
||||
$stmt = $pdo->prepare("INSERT INTO settings (setting_name, setting_value) VALUES (:name, :value) ON DUPLICATE KEY UPDATE setting_name=setting_name");
|
||||
|
||||
foreach ($defaults as $name => $value) {
|
||||
$stmt->execute(['name' => $name, 'value' => $value]);
|
||||
}
|
||||
|
||||
echo "Table 'settings' created and default values inserted successfully." . PHP_EOL;
|
||||
} catch (PDOException $e) {
|
||||
die("DB ERROR: " . $e->getMessage());
|
||||
}
|
||||
18
db/migration_users.php
Normal file
18
db/migration_users.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
require_once 'config.php';
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$sql = "CREATE TABLE IF NOT EXISTS users (
|
||||
id INT(11) AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
email VARCHAR(255) NOT NULL UNIQUE,
|
||||
password VARCHAR(255) NOT NULL,
|
||||
role ENUM('admin', 'user') DEFAULT 'user',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
) ENGINE=INNODB;";
|
||||
$pdo->exec($sql);
|
||||
echo "Table 'users' created successfully." . PHP_EOL;
|
||||
} catch (PDOException $e) {
|
||||
die("DB ERROR: " . $e->getMessage());
|
||||
}
|
||||
120
index.php
120
index.php
@ -35,116 +35,54 @@ $projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<style>
|
||||
:root {
|
||||
--bg-color-start: #6a11cb;
|
||||
--bg-color-end: #2575fc;
|
||||
--text-color: #ffffff;
|
||||
--card-bg-color: rgba(255, 255, 255, 0.01);
|
||||
--card-border-color: rgba(255, 255, 255, 0.1);
|
||||
--primary-color: #0050A0;
|
||||
--secondary-color: #F2B705;
|
||||
--bg-light: #F8F9FA;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: 'Inter', sans-serif;
|
||||
background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
|
||||
color: var(--text-color);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
font-family: 'Poppins', sans-serif;
|
||||
background-color: var(--bg-light);
|
||||
}
|
||||
.hero {
|
||||
background: linear-gradient(45deg, var(--primary-color), #007bff);
|
||||
color: white;
|
||||
padding: 80px 0;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
body::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><path d="M-10 10L110 10M10 -10L10 110" stroke-width="1" stroke="rgba(255,255,255,0.05)"/></svg>');
|
||||
animation: bg-pan 20s linear infinite;
|
||||
z-index: -1;
|
||||
}
|
||||
@keyframes bg-pan {
|
||||
0% { background-position: 0% 0%; }
|
||||
100% { background-position: 100% 100%; }
|
||||
}
|
||||
main {
|
||||
padding: 2rem;
|
||||
}
|
||||
.card {
|
||||
background: var(--card-bg-color);
|
||||
border: 1px solid var(--card-border-color);
|
||||
border-radius: 16px;
|
||||
padding: 2rem;
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.loader {
|
||||
margin: 1.25rem auto 1.25rem;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border: 3px solid rgba(255, 255, 255, 0.25);
|
||||
border-top-color: #fff;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
@keyframes spin {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
.hint {
|
||||
opacity: 0.9;
|
||||
}
|
||||
.sr-only {
|
||||
position: absolute;
|
||||
width: 1px; height: 1px;
|
||||
padding: 0; margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap; border: 0;
|
||||
}
|
||||
h1 {
|
||||
font-size: 3rem;
|
||||
.hero h1 {
|
||||
font-weight: 700;
|
||||
margin: 0 0 1rem;
|
||||
letter-spacing: -1px;
|
||||
}
|
||||
p {
|
||||
margin: 0.5rem 0;
|
||||
font-size: 1.1rem;
|
||||
.btn-admin {
|
||||
background-color: var(--secondary-color);
|
||||
border-color: var(--secondary-color);
|
||||
color: var(--text-dark);
|
||||
font-weight: 600;
|
||||
}
|
||||
code {
|
||||
background: rgba(0,0,0,0.2);
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||||
}
|
||||
footer {
|
||||
position: absolute;
|
||||
bottom: 1rem;
|
||||
font-size: 0.8rem;
|
||||
opacity: 0.7;
|
||||
.btn-admin:hover {
|
||||
background-color: #d9a404;
|
||||
border-color: #d9a404;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="card">
|
||||
<h1>Analyzing your requirements and generating your website…</h1>
|
||||
<div class="loader" role="status" aria-live="polite" aria-label="Applying initial changes">
|
||||
<span class="sr-only">Loading…</span>
|
||||
<div class="hero">
|
||||
<div class="container">
|
||||
<h1 class="display-4">Manajemen User & Domain</h1>
|
||||
<p class="lead">Selamat datang di panel manajemen Anda. Klik tombol di bawah untuk masuk ke dashboard admin.</p>
|
||||
<a href="/admin/" class="btn btn-admin btn-lg mt-3">Masuk ke Admin Panel</a>
|
||||
</div>
|
||||
<p class="hint"><?= ($_SERVER['HTTP_HOST'] ?? '') === 'appwizzy.com' ? 'AppWizzy' : 'Flatlogic' ?> AI is collecting your requirements and applying the first changes.</p>
|
||||
<p class="hint">This page will update automatically as the plan is implemented.</p>
|
||||
</div>
|
||||
<div class="container text-center py-5">
|
||||
<p>Runtime: PHP <code><?= htmlspecialchars($phpVersion) ?></code> — UTC <code><?= htmlspecialchars($now) ?></code></p>
|
||||
</div>
|
||||
</main>
|
||||
<footer>
|
||||
<footer class="text-center text-muted py-3">
|
||||
Page updated: <?= htmlspecialchars($now) ?> (UTC)
|
||||
</footer>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user