1.0.1
This commit is contained in:
parent
3b22218c88
commit
89d2171b50
37
admin.php
Normal file
37
admin.php
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'header.php';
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
// Check if user is logged in and is an admin
|
||||||
|
if (!isset($_SESSION['user_id']) || $_SESSION['role'] !== 'admin') {
|
||||||
|
header("Location: profile.php");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<header class="hero text-center">
|
||||||
|
<div class="container">
|
||||||
|
<h1 class="display-4">Admin Panel</h1>
|
||||||
|
<p class="lead">Manage your application from here.</p>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main class="container my-5">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body p-5">
|
||||||
|
<h3>Admin Menu</h3>
|
||||||
|
<div class="list-group">
|
||||||
|
<a href="admin_users.php" class="list-group-item list-group-item-action">Manage Users</a>
|
||||||
|
<a href="admin_products.php" class="list-group-item list-group-item-action">Manage Products</a>
|
||||||
|
<a href="admin_orders.php" class="list-group-item list-group-item-action">Manage Orders</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<?php require_once 'footer.php'; ?>
|
||||||
108
admin_product_edit.php
Normal file
108
admin_product_edit.php
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'header.php';
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
// Check if user is logged in and is an admin
|
||||||
|
if (!isset($_SESSION['user_id']) || $_SESSION['role'] !== 'admin') {
|
||||||
|
header("Location: profile.php");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
$product = [
|
||||||
|
'id' => null,
|
||||||
|
'name' => '',
|
||||||
|
'description' => '',
|
||||||
|
'price' => '',
|
||||||
|
'image' => ''
|
||||||
|
];
|
||||||
|
$errors = [];
|
||||||
|
$page_title = 'Add New Product';
|
||||||
|
|
||||||
|
if (isset($_GET['id']) && is_numeric($_GET['id'])) {
|
||||||
|
$page_title = 'Edit Product';
|
||||||
|
$product_id = $_GET['id'];
|
||||||
|
$stmt = $pdo->prepare("SELECT * FROM products WHERE id = ?");
|
||||||
|
$stmt->execute([$product_id]);
|
||||||
|
$product = $stmt->fetch();
|
||||||
|
if (!$product) {
|
||||||
|
header("Location: admin_products.php");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
$product['name'] = $_POST['name'];
|
||||||
|
$product['description'] = $_POST['description'];
|
||||||
|
$product['price'] = $_POST['price'];
|
||||||
|
$product['image'] = $_POST['image'];
|
||||||
|
|
||||||
|
if (empty($product['name'])) {
|
||||||
|
$errors[] = 'Name is required';
|
||||||
|
}
|
||||||
|
if (empty($product['price']) || !is_numeric($product['price'])) {
|
||||||
|
$errors[] = 'Price must be a number';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($errors)) {
|
||||||
|
if ($product['id']) {
|
||||||
|
// Update
|
||||||
|
$stmt = $pdo->prepare("UPDATE products SET name = ?, description = ?, price = ?, image = ? WHERE id = ?");
|
||||||
|
$stmt->execute([$product['name'], $product['description'], $product['price'], $product['image'], $product['id']]);
|
||||||
|
} else {
|
||||||
|
// Insert
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO products (name, description, price, image) VALUES (?, ?, ?, ?)");
|
||||||
|
$stmt->execute([$product['name'], $product['description'], $product['price'], $product['image']]);
|
||||||
|
}
|
||||||
|
header("Location: admin_products.php");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<header class="hero text-center">
|
||||||
|
<div class="container">
|
||||||
|
<h1 class="display-4"><?php echo $page_title; ?></h1>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main class="container my-5">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body p-5">
|
||||||
|
<?php if (!empty($errors)): ?>
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<?php foreach ($errors as $error): ?>
|
||||||
|
<p><?php echo $error; ?></p>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<form action="admin_product_edit.php<?php echo $product['id'] ? '?id=' . $product['id'] : ''; ?>" method="POST">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="name" class="form-label">Name</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="description" class="form-label">Description</label>
|
||||||
|
<textarea class="form-control" id="description" name="description" rows="5"><?php echo htmlspecialchars($product['description']); ?></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="price" class="form-label">Price</label>
|
||||||
|
<input type="number" step="0.01" class="form-control" id="price" name="price" value="<?php echo htmlspecialchars($product['price']); ?>" required>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="image" class="form-label">Image URL</label>
|
||||||
|
<input type="text" class="form-control" id="image" name="image" value="<?php echo htmlspecialchars($product['image']); ?>">
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary">Save Product</button>
|
||||||
|
<a href="admin_products.php" class="btn btn-secondary">Cancel</a>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<?php require_once 'footer.php'; ?>
|
||||||
71
admin_products.php
Normal file
71
admin_products.php
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'header.php';
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
// Check if user is logged in and is an admin
|
||||||
|
if (!isset($_SESSION['user_id']) || $_SESSION['role'] !== 'admin') {
|
||||||
|
header("Location: profile.php");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
// Handle product deletion
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['delete_product'])) {
|
||||||
|
$product_id = $_POST['product_id'];
|
||||||
|
$stmt = $pdo->prepare("DELETE FROM products WHERE id = ?");
|
||||||
|
$stmt->execute([$product_id]);
|
||||||
|
header("Location: admin_products.php");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmt = $pdo->query("SELECT * FROM products ORDER BY created_at DESC");
|
||||||
|
$products = $stmt->fetchAll();
|
||||||
|
?>
|
||||||
|
|
||||||
|
<header class="hero text-center">
|
||||||
|
<div class="container">
|
||||||
|
<h1 class="display-4">Manage Products</h1>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main class="container my-5">
|
||||||
|
<div class="text-end mb-3">
|
||||||
|
<a href="admin_product_edit.php" class="btn btn-primary">Add New Product</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<table class="table table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Image</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Price</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($products as $product): ?>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<img src="<?php echo htmlspecialchars($product['image'] ? $product['image'] : 'https://via.placeholder.com/100x100'); ?>" alt="<?php echo htmlspecialchars($product['name']); ?>" style="width: 100px; height: 100px; object-fit: cover;">
|
||||||
|
</td>
|
||||||
|
<td><?php echo htmlspecialchars($product['name']); ?></td>
|
||||||
|
<td>$<?php echo htmlspecialchars(number_format($product['price'], 2)); ?></td>
|
||||||
|
<td>
|
||||||
|
<a href="admin_product_edit.php?id=<?php echo $product['id']; ?>" class="btn btn-sm btn-primary">Edit</a>
|
||||||
|
<form action="admin_products.php" method="POST" class="d-inline" onsubmit="return confirm('Are you sure you want to delete this product?');">
|
||||||
|
<input type="hidden" name="product_id" value="<?php echo $product['id']; ?>">
|
||||||
|
<button type="submit" name="delete_product" class="btn btn-sm btn-danger">Delete</button>
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<?php require_once 'footer.php'; ?>
|
||||||
54
admin_user_edit.php
Normal file
54
admin_user_edit.php
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'header.php';
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
// Check if user is logged in and is an admin
|
||||||
|
if (!isset($_SESSION['user_id']) || $_SESSION['role'] !== 'admin') {
|
||||||
|
header("Location: profile.php");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$page_title = 'Edit User';
|
||||||
|
|
||||||
|
if (!isset($_GET['id']) || !is_numeric($_GET['id'])) {
|
||||||
|
header("Location: admin_users.php");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$user_id = $_GET['id'];
|
||||||
|
|
||||||
|
$pdo = db();
|
||||||
|
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
|
||||||
|
$stmt->execute([$user_id]);
|
||||||
|
$user = $stmt->fetch();
|
||||||
|
|
||||||
|
if (!$user) {
|
||||||
|
header("Location: admin_users.php");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For now, this is just a placeholder page.
|
||||||
|
// Full edit functionality will be added later.
|
||||||
|
?>
|
||||||
|
|
||||||
|
<header class="hero text-center">
|
||||||
|
<div class="container">
|
||||||
|
<h1 class="display-4"><?php echo $page_title; ?></h1>
|
||||||
|
<p class="lead">Editing user: <?php echo htmlspecialchars($user['username']); ?></p>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main class="container my-5">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body p-5">
|
||||||
|
<p>Full user editing functionality will be implemented here soon.</p>
|
||||||
|
<a href="admin_users.php" class="btn btn-primary">Back to Users List</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<?php require_once 'footer.php'; ?>
|
||||||
108
admin_users.php
Normal file
108
admin_users.php
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'header.php';
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
// Check if user is logged in and is an admin
|
||||||
|
if (!isset($_SESSION['user_id']) || $_SESSION['role'] !== 'admin') {
|
||||||
|
header("Location: profile.php");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
// Handle user updates
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
if (isset($_POST['update_role'])) {
|
||||||
|
$user_id = $_POST['user_id'];
|
||||||
|
$role = $_POST['role'];
|
||||||
|
$stmt = $pdo->prepare("UPDATE users SET role = ? WHERE id = ?");
|
||||||
|
$stmt->execute([$role, $user_id]);
|
||||||
|
} elseif (isset($_POST['update_balance'])) {
|
||||||
|
$user_id = $_POST['user_id'];
|
||||||
|
$balance = $_POST['balance'];
|
||||||
|
$stmt = $pdo->prepare("UPDATE users SET balance = ? WHERE id = ?");
|
||||||
|
$stmt->execute([$balance, $user_id]);
|
||||||
|
} elseif (isset($_POST['update_status'])) {
|
||||||
|
$user_id = $_POST['user_id'];
|
||||||
|
$status = $_POST['status'];
|
||||||
|
$stmt = $pdo->prepare("UPDATE users SET status = ? WHERE id = ?");
|
||||||
|
$stmt->execute([$status, $user_id]);
|
||||||
|
}
|
||||||
|
header("Location: admin_users.php");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmt = $pdo->query("SELECT * FROM users ORDER BY created_at DESC");
|
||||||
|
$users = $stmt->fetchAll();
|
||||||
|
?>
|
||||||
|
|
||||||
|
<header class="hero text-center">
|
||||||
|
<div class="container">
|
||||||
|
<h1 class="display-4">Manage Users</h1>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main class="container my-5">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Username</th>
|
||||||
|
<th>Email</th>
|
||||||
|
<th>Role</th>
|
||||||
|
<th>Balance</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($users as $user): ?>
|
||||||
|
<tr>
|
||||||
|
<td><?php echo $user['id']; ?></td>
|
||||||
|
<td><?php echo htmlspecialchars($user['username']); ?></td>
|
||||||
|
<td><?php echo htmlspecialchars($user['email']); ?></td>
|
||||||
|
<td>
|
||||||
|
<form action="admin_users.php" method="POST" class="d-inline">
|
||||||
|
<input type="hidden" name="user_id" value="<?php echo $user['id']; ?>">
|
||||||
|
<select name="role" class="form-select form-select-sm" onchange="this.form.submit()">
|
||||||
|
<option value="user" <?php echo $user['role'] === 'user' ? 'selected' : ''; ?>>User</option>
|
||||||
|
<option value="admin" <?php echo $user['role'] === 'admin' ? 'selected' : ''; ?>>Admin</option>
|
||||||
|
</select>
|
||||||
|
<input type="hidden" name="update_role" value="1">
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<form action="admin_users.php" method="POST" class="d-inline">
|
||||||
|
<input type="hidden" name="user_id" value="<?php echo $user['id']; ?>">
|
||||||
|
<div class="input-group input-group-sm">
|
||||||
|
<input type="number" step="0.01" name="balance" class="form-control" value="<?php echo htmlspecialchars($user['balance']); ?>">
|
||||||
|
<button type="submit" name="update_balance" class="btn btn-outline-primary">Save</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<form action="admin_users.php" method="POST" class="d-inline">
|
||||||
|
<input type="hidden" name="user_id" value="<?php echo $user['id']; ?>">
|
||||||
|
<select name="status" class="form-select form-select-sm" onchange="this.form.submit()">
|
||||||
|
<option value="active" <?php echo $user['status'] === 'active' ? 'selected' : ''; ?>>Active</option>
|
||||||
|
<option value="banned" <?php echo $user['status'] === 'banned' ? 'selected' : ''; ?>>Banned</option>
|
||||||
|
</select>
|
||||||
|
<input type="hidden" name="update_status" value="1">
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="admin_user_edit.php?id=<?php echo $user['id']; ?>" class="btn btn-sm btn-primary">Edit</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<?php require_once 'footer.php'; ?>
|
||||||
169
cart.php
Normal file
169
cart.php
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'header.php';
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
$cart_items = [];
|
||||||
|
$total = 0;
|
||||||
|
|
||||||
|
if (isset($_SESSION['cart']) && !empty($_SESSION['cart'])) {
|
||||||
|
$product_ids = array_keys($_SESSION['cart']);
|
||||||
|
$placeholders = implode(',', array_fill(0, count($product_ids), '?'));
|
||||||
|
|
||||||
|
$pdo = db();
|
||||||
|
$stmt = $pdo->prepare("SELECT * FROM products WHERE id IN ($placeholders)");
|
||||||
|
$stmt->execute($product_ids);
|
||||||
|
$products = $stmt->fetchAll();
|
||||||
|
|
||||||
|
foreach ($products as $product) {
|
||||||
|
$product_id = $product['id'];
|
||||||
|
$quantity = $_SESSION['cart'][$product_id];
|
||||||
|
$subtotal = $product['price'] * $quantity;
|
||||||
|
$total += $subtotal;
|
||||||
|
|
||||||
|
$cart_items[] = [
|
||||||
|
'id' => $product_id,
|
||||||
|
'name' => $product['name'],
|
||||||
|
'price' => $product['price'],
|
||||||
|
'quantity' => $quantity,
|
||||||
|
'subtotal' => $subtotal
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_cart'])) {
|
||||||
|
foreach ($_POST['quantities'] as $product_id => $quantity) {
|
||||||
|
if ($quantity > 0) {
|
||||||
|
$_SESSION['cart'][$product_id] = (int)$quantity;
|
||||||
|
} else {
|
||||||
|
unset($_SESSION['cart'][$product_id]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
header("Location: cart.php");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['checkout'])) {
|
||||||
|
if (!isset($_SESSION['user_id'])) {
|
||||||
|
header("Location: login.php");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($cart_items)) {
|
||||||
|
header("Location: shop.php");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo->beginTransaction();
|
||||||
|
|
||||||
|
// Check if user has enough balance
|
||||||
|
$stmt = $pdo->prepare("SELECT balance FROM users WHERE id = ?");
|
||||||
|
$stmt->execute([$_SESSION['user_id']]);
|
||||||
|
$user = $stmt->fetch();
|
||||||
|
|
||||||
|
if ($user['balance'] < $total) {
|
||||||
|
// Not enough balance
|
||||||
|
$pdo->rollBack();
|
||||||
|
// Redirect to cart with an error message
|
||||||
|
header("Location: cart.php?error=balance");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create order
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO orders (user_id, total) VALUES (?, ?)");
|
||||||
|
$stmt->execute([$_SESSION['user_id'], $total]);
|
||||||
|
$order_id = $pdo->lastInsertId();
|
||||||
|
|
||||||
|
// Create order items
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO order_items (order_id, product_id, quantity, price) VALUES (?, ?, ?, ?)");
|
||||||
|
foreach ($cart_items as $item) {
|
||||||
|
$stmt->execute([$order_id, $item['id'], $item['quantity'], $item['price']]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deduct balance from user
|
||||||
|
$new_balance = $user['balance'] - $total;
|
||||||
|
$stmt = $pdo->prepare("UPDATE users SET balance = ? WHERE id = ?");
|
||||||
|
$stmt->execute([$new_balance, $_SESSION['user_id']]);
|
||||||
|
|
||||||
|
$pdo->commit();
|
||||||
|
|
||||||
|
// Clear cart
|
||||||
|
unset($_SESSION['cart']);
|
||||||
|
|
||||||
|
// Redirect to a success page
|
||||||
|
header("Location: order_success.php?order_id=" . $order_id);
|
||||||
|
exit;
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$pdo->rollBack();
|
||||||
|
// Log the error
|
||||||
|
error_log($e->getMessage());
|
||||||
|
// Redirect to cart with a generic error
|
||||||
|
header("Location: cart.php?error=checkout");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<header class="hero text-center">
|
||||||
|
<div class="container">
|
||||||
|
<h1 class="display-4">Shopping Cart</h1>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main class="container my-5">
|
||||||
|
<?php if (isset($_GET['error'])): ?>
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<?php if ($_GET['error'] === 'balance'): ?>
|
||||||
|
You do not have enough balance to complete this purchase.
|
||||||
|
<?php else: ?>
|
||||||
|
An error occurred during checkout. Please try again.
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if (empty($cart_items)): ?>
|
||||||
|
<div class="text-center">
|
||||||
|
<p class="lead">Your cart is empty.</p>
|
||||||
|
<a href="shop.php" class="btn btn-primary">Continue Shopping</a>
|
||||||
|
</div>
|
||||||
|
<?php else: ?>
|
||||||
|
<form action="cart.php" method="POST">
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Product</th>
|
||||||
|
<th>Price</th>
|
||||||
|
<th>Quantity</th>
|
||||||
|
<th>Subtotal</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($cart_items as $item): ?>
|
||||||
|
<tr>
|
||||||
|
<td><?php echo htmlspecialchars($item['name']); ?></td>
|
||||||
|
<td>$<?php echo htmlspecialchars(number_format($item['price'], 2)); ?></td>
|
||||||
|
<td>
|
||||||
|
<input type="number" name="quantities[<?php echo $item['id']; ?>]" value="<?php echo $item['quantity']; ?>" min="0" class="form-control" style="width: 100px;">
|
||||||
|
</td>
|
||||||
|
<td>$<?php echo htmlspecialchars(number_format($item['subtotal'], 2)); ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class="d-flex justify-content-between align-items-center">
|
||||||
|
<button type="submit" name="update_cart" class="btn btn-secondary">Update Cart</button>
|
||||||
|
<p class="fs-4">Total: $<?php echo htmlspecialchars(number_format($total, 2)); ?></p>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<form action="cart.php" method="POST" class="mt-3 text-end">
|
||||||
|
<button type="submit" name="checkout" class="btn btn-primary btn-lg">Checkout</button>
|
||||||
|
</form>
|
||||||
|
<?php endif; ?>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<?php require_once 'footer.php'; ?>
|
||||||
121
chat.php
Normal file
121
chat.php
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'header.php';
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
if (!isset($_SESSION['user_id'])) {
|
||||||
|
header("Location: login.php");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$pdo = db();
|
||||||
|
$stmt = $pdo->prepare("SELECT id, username FROM users WHERE id != ?");
|
||||||
|
$stmt->execute([$_SESSION['user_id']]);
|
||||||
|
$users = $stmt->fetchAll();
|
||||||
|
?>
|
||||||
|
|
||||||
|
<header class="hero text-center">
|
||||||
|
<div class="container">
|
||||||
|
<h1 class="display-4">Chat</h1>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main class="container my-5">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">Users</div>
|
||||||
|
<div class="list-group list-group-flush">
|
||||||
|
<?php foreach ($users as $user): ?>
|
||||||
|
<a href="chat.php?user_id=<?php echo $user['id']; ?>" class="list-group-item list-group-item-action">
|
||||||
|
<?php echo htmlspecialchars($user['username']); ?>
|
||||||
|
</a>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-8">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
Chat with <?php
|
||||||
|
if (isset($_GET['user_id'])) {
|
||||||
|
$stmt = $pdo->prepare("SELECT username FROM users WHERE id = ?");
|
||||||
|
$stmt->execute([$_GET['user_id']]);
|
||||||
|
$chat_user = $stmt->fetch();
|
||||||
|
echo htmlspecialchars($chat_user['username']);
|
||||||
|
} else {
|
||||||
|
echo '...';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
|
<div class="card-body chat-box" id="chat-box" style="height: 400px; overflow-y: scroll;">
|
||||||
|
<!-- Messages will be loaded here -->
|
||||||
|
</div>
|
||||||
|
<div class="card-footer">
|
||||||
|
<?php if (isset($_GET['user_id'])):
|
||||||
|
<form id="message-form">
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="hidden" name="receiver_id" id="receiver_id" value="<?php echo $_GET['user_id']; ?>">
|
||||||
|
<input type="text" name="message" id="message-input" class="form-control" placeholder="Type your message...">
|
||||||
|
<button type="submit" class="btn btn-primary">Send</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<?php else: ?>
|
||||||
|
<p class="text-muted">Select a user to start chatting.</p>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const chatBox = document.getElementById('chat-box');
|
||||||
|
const messageForm = document.getElementById('message-form');
|
||||||
|
const receiverId = document.getElementById('receiver_id');
|
||||||
|
|
||||||
|
function fetchMessages() {
|
||||||
|
if (!receiverId) return;
|
||||||
|
|
||||||
|
fetch(`api_chat.php?action=get_messages&receiver_id=${receiverId.value}`)
|
||||||
|
.then(response => response.text())
|
||||||
|
.then(data => {
|
||||||
|
chatBox.innerHTML = data;
|
||||||
|
chatBox.scrollTop = chatBox.scrollHeight;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (messageForm) {
|
||||||
|
messageForm.addEventListener('submit', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
const messageInput = document.getElementById('message-input');
|
||||||
|
const message = messageInput.value;
|
||||||
|
|
||||||
|
if (message.trim() === '') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('action', 'send_message');
|
||||||
|
formData.append('receiver_id', receiverId.value);
|
||||||
|
formData.append('message', message);
|
||||||
|
|
||||||
|
fetch('api_chat.php', {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
messageInput.value = '';
|
||||||
|
fetchMessages();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Fetch messages every 3 seconds
|
||||||
|
setInterval(fetchMessages, 3000);
|
||||||
|
// Initial fetch
|
||||||
|
fetchMessages();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<?php require_once 'footer.php'; ?>
|
||||||
45
db/migrate.php
Normal file
45
db/migrate.php
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/config.php';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
// First, make sure the migrations table exists
|
||||||
|
$pdo->exec("CREATE TABLE IF NOT EXISTS `migrations` (
|
||||||
|
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
`migration` VARCHAR(255) NOT NULL,
|
||||||
|
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
)");
|
||||||
|
|
||||||
|
// Get all migration files
|
||||||
|
$migrations_dir = __DIR__ . '/migrations';
|
||||||
|
$migration_files = glob($migrations_dir . '/*.sql');
|
||||||
|
sort($migration_files);
|
||||||
|
|
||||||
|
// Get already run migrations
|
||||||
|
$stmt = $pdo->query("SELECT migration FROM migrations");
|
||||||
|
$run_migrations = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||||
|
|
||||||
|
foreach ($migration_files as $file) {
|
||||||
|
$migration_name = basename($file);
|
||||||
|
|
||||||
|
if (in_array($migration_name, $run_migrations)) {
|
||||||
|
continue; // Skip already run migration
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql = file_get_contents($file);
|
||||||
|
$pdo->exec($sql);
|
||||||
|
|
||||||
|
// Record the migration
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO migrations (migration) VALUES (?)");
|
||||||
|
$stmt->execute([$migration_name]);
|
||||||
|
|
||||||
|
echo "Executed migration: " . $migration_name . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "All new migrations successful!\n";
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
die("Migration failed: " . $e->getMessage() . "\n");
|
||||||
|
}
|
||||||
|
|
||||||
5
db/migrations/000_create_migrations_table.sql
Normal file
5
db/migrations/000_create_migrations_table.sql
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS `migrations` (
|
||||||
|
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
`migration` VARCHAR(255) NOT NULL,
|
||||||
|
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
9
db/migrations/001_create_users_table.sql
Normal file
9
db/migrations/001_create_users_table.sql
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS `users` (
|
||||||
|
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
`username` VARCHAR(50) NOT NULL UNIQUE,
|
||||||
|
`email` VARCHAR(100) NOT NULL UNIQUE,
|
||||||
|
`password` VARCHAR(255) NOT NULL,
|
||||||
|
`role` ENUM('user', 'admin') NOT NULL DEFAULT 'user',
|
||||||
|
`balance` DECIMAL(10, 2) NOT NULL DEFAULT 0.00,
|
||||||
|
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
26
db/migrations/002_create_shop_tables.sql
Normal file
26
db/migrations/002_create_shop_tables.sql
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS `products` (
|
||||||
|
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
`name` VARCHAR(255) NOT NULL,
|
||||||
|
`description` TEXT,
|
||||||
|
`price` DECIMAL(10, 2) NOT NULL,
|
||||||
|
`image` VARCHAR(255),
|
||||||
|
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `orders` (
|
||||||
|
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
`user_id` INT NOT NULL,
|
||||||
|
`total` DECIMAL(10, 2) NOT NULL,
|
||||||
|
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY (user_id) REFERENCES users(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
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),
|
||||||
|
FOREIGN KEY (product_id) REFERENCES products(id)
|
||||||
|
);
|
||||||
1
db/migrations/003_add_status_to_users.sql
Normal file
1
db/migrations/003_add_status_to_users.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE `users` ADD `status` ENUM('active', 'banned') NOT NULL DEFAULT 'active';
|
||||||
30
db/migrations/004_create_chat_tables.sql
Normal file
30
db/migrations/004_create_chat_tables.sql
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS `messages` (
|
||||||
|
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
`sender_id` INT NOT NULL,
|
||||||
|
`receiver_id` INT, -- For private messages
|
||||||
|
`group_id` INT, -- For group messages
|
||||||
|
`message` TEXT NOT NULL,
|
||||||
|
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY (sender_id) REFERENCES users(id),
|
||||||
|
FOREIGN KEY (receiver_id) REFERENCES users(id)
|
||||||
|
-- FOREIGN KEY (group_id) REFERENCES chat_groups(id) -- This will be added later to avoid circular dependency
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `chat_groups` (
|
||||||
|
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
`name` VARCHAR(255) NOT NULL,
|
||||||
|
`creator_id` INT NOT NULL,
|
||||||
|
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY (creator_id) REFERENCES users(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `chat_group_members` (
|
||||||
|
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
`group_id` INT NOT NULL,
|
||||||
|
`user_id` INT NOT NULL,
|
||||||
|
`role` ENUM('member', 'admin') NOT NULL DEFAULT 'member',
|
||||||
|
FOREIGN KEY (group_id) REFERENCES chat_groups(id),
|
||||||
|
FOREIGN KEY (user_id) REFERENCES users(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE `messages` ADD CONSTRAINT `fk_messages_group_id` FOREIGN KEY (`group_id`) REFERENCES `chat_groups`(`id`);
|
||||||
10
footer.php
Normal file
10
footer.php
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<footer class="bg-dark text-white text-center py-3 mt-5">
|
||||||
|
<div class="container">
|
||||||
|
<p>© <?php echo date("Y"); ?> Calculator App. Built with Flatlogic.</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
71
header.php
Normal file
71
header.php
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<?php session_start(); ?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Interactive Calculator</title>
|
||||||
|
<meta name="description" content="An interactive calculator for various financial calculations. Built with Flatlogic Generator.">
|
||||||
|
<meta name="keywords" content="interactive calculator, loan calculator, salary calculator, VAT calculator, financial tools, Flatlogic Generator">
|
||||||
|
<meta property="og:title" content="Interactive Calculator">
|
||||||
|
<meta property="og:description" content="An interactive calculator for various financial calculations. Built with Flatlogic Generator.">
|
||||||
|
<meta property="og:image" content="">
|
||||||
|
<meta name="twitter:card" content="summary_large_image">
|
||||||
|
<meta name="twitter:image" content="">
|
||||||
|
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
||||||
|
<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 rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||||
|
<div class="container">
|
||||||
|
<a class="navbar-brand" href="index.php">Calculator App</a>
|
||||||
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
<div class="collapse navbar-collapse" id="navbarNav">
|
||||||
|
<ul class="navbar-nav ms-auto">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="index.php">Home</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="shop.php">Shop</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="chat.php">Chat</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="cart.php">
|
||||||
|
<i class="bi bi-cart"></i> Cart
|
||||||
|
<?php
|
||||||
|
$cart_count = isset($_SESSION['cart']) ? count($_SESSION['cart']) : 0;
|
||||||
|
if ($cart_count > 0):
|
||||||
|
?>
|
||||||
|
<span class="badge bg-primary"><?php echo $cart_count; ?></span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<?php if (isset($_SESSION['user_id'])): ?>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="profile.php">Profile</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="logout.php">Logout</a>
|
||||||
|
</li>
|
||||||
|
<?php else: ?>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="login.php">Login</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="register.php">Register</a>
|
||||||
|
</li>
|
||||||
|
<?php endif; ?>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
40
index.php
40
index.php
@ -1,31 +1,4 @@
|
|||||||
<!DOCTYPE html>
|
<?php require_once 'header.php'; ?>
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Interactive Calculator</title>
|
|
||||||
<meta name="description" content="An interactive calculator for various financial calculations. Built with Flatlogic Generator.">
|
|
||||||
<meta name="keywords" content="interactive calculator, loan calculator, salary calculator, VAT calculator, financial tools, Flatlogic Generator">
|
|
||||||
<meta property="og:title" content="Interactive Calculator">
|
|
||||||
<meta property="og:description" content="An interactive calculator for various financial calculations. Built with Flatlogic Generator.">
|
|
||||||
<meta property="og:image" content="">
|
|
||||||
<meta name="twitter:card" content="summary_large_image">
|
|
||||||
<meta name="twitter:image" content="">
|
|
||||||
|
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
|
||||||
<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 rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
|
||||||
<div class="container">
|
|
||||||
<a class="navbar-brand" href="#">Calculator App</a>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<header class="hero text-center">
|
<header class="hero text-center">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@ -65,13 +38,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<footer class="bg-dark text-white text-center py-3 mt-5">
|
<?php require_once 'footer.php'; ?>
|
||||||
<div class="container">
|
|
||||||
<p>© <?php echo date("Y"); ?> Calculator App. Built with Flatlogic.</p>
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
|
||||||
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
81
login.php
Normal file
81
login.php
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'header.php';
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
$errors = [];
|
||||||
|
$email = '';
|
||||||
|
|
||||||
|
if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||||
|
$email = $_POST['email'];
|
||||||
|
$password = $_POST['password'];
|
||||||
|
|
||||||
|
if (empty($email)) {
|
||||||
|
$errors[] = 'Email is required';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($password)) {
|
||||||
|
$errors[] = 'Password is required';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($errors)) {
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare("SELECT * FROM users WHERE email = ?");
|
||||||
|
$stmt->execute([$email]);
|
||||||
|
$user = $stmt->fetch();
|
||||||
|
|
||||||
|
if ($user && password_verify($password, $user['password'])) {
|
||||||
|
if ($user['status'] === 'banned') {
|
||||||
|
$errors[] = 'Your account has been banned.';
|
||||||
|
} else {
|
||||||
|
$_SESSION['user_id'] = $user['id'];
|
||||||
|
$_SESSION['username'] = $user['username'];
|
||||||
|
$_SESSION['role'] = $user['role'];
|
||||||
|
|
||||||
|
header("Location: profile.php");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$errors[] = 'Invalid email or password';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<header class="hero text-center">
|
||||||
|
<div class="container">
|
||||||
|
<h1 class="display-4">Login</h1>
|
||||||
|
<p class="lead">Access your account.</p>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main class="container my-5">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-lg-6">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body p-5">
|
||||||
|
<?php if (!empty($errors)): ?>
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<?php foreach ($errors as $error): ?>
|
||||||
|
<p><?php echo $error; ?></p>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<form action="login.php" method="POST">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="email" class="form-label">Email address</label>
|
||||||
|
<input type="email" class="form-control" id="email" name="email" value="<?php echo htmlspecialchars($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>
|
||||||
|
<button type="submit" class="btn btn-primary w-100">Login</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<?php require_once 'footer.php'; ?>
|
||||||
6
logout.php
Normal file
6
logout.php
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?php
|
||||||
|
session_start();
|
||||||
|
session_unset();
|
||||||
|
session_destroy();
|
||||||
|
header("Location: index.php");
|
||||||
|
exit;
|
||||||
51
order_success.php
Normal file
51
order_success.php
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'header.php';
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
if (!isset($_SESSION['user_id'])) {
|
||||||
|
header("Location: login.php");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($_GET['order_id']) || !is_numeric($_GET['order_id'])) {
|
||||||
|
header("Location: profile.php");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$order_id = $_GET['order_id'];
|
||||||
|
|
||||||
|
$pdo = db();
|
||||||
|
$stmt = $pdo->prepare("SELECT * FROM orders WHERE id = ? AND user_id = ?");
|
||||||
|
$stmt->execute([$order_id, $_SESSION['user_id']]);
|
||||||
|
$order = $stmt->fetch();
|
||||||
|
|
||||||
|
if (!$order) {
|
||||||
|
header("Location: profile.php");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<header class="hero text-center">
|
||||||
|
<div class="container">
|
||||||
|
<h1 class="display-4">Order Successful!</h1>
|
||||||
|
<p class="lead">Thank you for your purchase.</p>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main class="container my-5">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body p-5">
|
||||||
|
<h3>Order Details</h3>
|
||||||
|
<p>Your order #<?php echo htmlspecialchars($order['id']); ?> has been placed successfully.</p>
|
||||||
|
<p>Total amount: $<?php echo htmlspecialchars(number_format($order['total'], 2)); ?></p>
|
||||||
|
<a href="profile.php" class="btn btn-primary">View Profile</a>
|
||||||
|
<a href="shop.php" class="btn btn-secondary">Continue Shopping</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<?php require_once 'footer.php'; ?>
|
||||||
70
product.php
Normal file
70
product.php
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'header.php';
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
if (!isset($_GET['id']) || !is_numeric($_GET['id'])) {
|
||||||
|
header("Location: shop.php");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$product_id = $_GET['id'];
|
||||||
|
|
||||||
|
$pdo = db();
|
||||||
|
$stmt = $pdo->prepare("SELECT * FROM products WHERE id = ?");
|
||||||
|
$stmt->execute([$product_id]);
|
||||||
|
$product = $stmt->fetch();
|
||||||
|
|
||||||
|
if (!$product) {
|
||||||
|
header("Location: shop.php");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_to_cart'])) {
|
||||||
|
$quantity = isset($_POST['quantity']) && is_numeric($_POST['quantity']) && $_POST['quantity'] > 0 ? (int)$_POST['quantity'] : 1;
|
||||||
|
|
||||||
|
if (!isset($_SESSION['cart'])) {
|
||||||
|
$_SESSION['cart'] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($_SESSION['cart'][$product_id])) {
|
||||||
|
$_SESSION['cart'][$product_id] += $quantity;
|
||||||
|
} else {
|
||||||
|
$_SESSION['cart'][$product_id] = $quantity;
|
||||||
|
}
|
||||||
|
|
||||||
|
header("Location: cart.php");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<header class="hero text-center">
|
||||||
|
<div class="container">
|
||||||
|
<h1 class="display-4"><?php echo htmlspecialchars($product['name']); ?></h1>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main class="container my-5">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<img src="https://via.placeholder.com/600x400" class="img-fluid" alt="<?php echo htmlspecialchars($product['name']); ?>">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<h2><?php echo htmlspecialchars($product['name']); ?></h2>
|
||||||
|
<p class="lead"><?php echo htmlspecialchars($product['description']); ?></p>
|
||||||
|
<p class="fs-3 text-primary">$<?php echo htmlspecialchars(number_format($product['price'], 2)); ?></p>
|
||||||
|
|
||||||
|
<form action="product.php?id=<?php echo $product_id; ?>" method="POST">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label for="quantity" class="form-label">Quantity</label>
|
||||||
|
<input type="number" class="form-control" id="quantity" name="quantity" value="1" min="1">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="submit" name="add_to_cart" class="btn btn-primary btn-lg mt-3">Add to Cart</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<?php require_once 'footer.php'; ?>
|
||||||
67
profile.php
Normal file
67
profile.php
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'header.php';
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
// Check if user is logged in
|
||||||
|
if (!isset($_SESSION['user_id'])) {
|
||||||
|
header("Location: login.php");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$user_id = $_SESSION['user_id'];
|
||||||
|
|
||||||
|
$pdo = db();
|
||||||
|
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
|
||||||
|
$stmt->execute([$user_id]);
|
||||||
|
$user = $stmt->fetch();
|
||||||
|
|
||||||
|
if (!$user) {
|
||||||
|
// User not found, destroy session and redirect to login
|
||||||
|
session_destroy();
|
||||||
|
header("Location: login.php");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<header class="hero text-center">
|
||||||
|
<div class="container">
|
||||||
|
<h1 class="display-4">Welcome, <?php echo htmlspecialchars($user['username']); ?>!</h1>
|
||||||
|
<p class="lead">This is your profile page.</p>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main class="container my-5">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body p-5">
|
||||||
|
<h3>Profile Information</h3>
|
||||||
|
<table class="table table-bordered">
|
||||||
|
<tr>
|
||||||
|
<th>Username</th>
|
||||||
|
<td><?php echo htmlspecialchars($user['username']); ?></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Email</th>
|
||||||
|
<td><?php echo htmlspecialchars($user['email']); ?></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Role</th>
|
||||||
|
<td><?php echo htmlspecialchars($user['role']); ?></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Balance</th>
|
||||||
|
<td>$<?php echo htmlspecialchars(number_format($user['balance'], 2)); ?></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<?php if ($user['role'] === 'admin'): ?>
|
||||||
|
<a href="admin.php" class="btn btn-primary">Admin Panel</a>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<?php require_once 'footer.php'; ?>
|
||||||
114
register.php
Normal file
114
register.php
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'header.php';
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
$errors = [];
|
||||||
|
$username = '';
|
||||||
|
$email = '';
|
||||||
|
|
||||||
|
if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||||
|
$username = $_POST['username'];
|
||||||
|
$email = $_POST['email'];
|
||||||
|
$password = $_POST['password'];
|
||||||
|
$password_confirm = $_POST['password_confirm'];
|
||||||
|
|
||||||
|
if (empty($username)) {
|
||||||
|
$errors[] = 'Username is required';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($email)) {
|
||||||
|
$errors[] = 'Email is required';
|
||||||
|
} elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||||
|
$errors[] = 'Invalid email format';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($password)) {
|
||||||
|
$errors[] = 'Password is required';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($password !== $password_confirm) {
|
||||||
|
$errors[] = 'Passwords do not match';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($errors)) {
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ? OR email = ?");
|
||||||
|
$stmt->execute([$username, $email]);
|
||||||
|
$existing_user = $stmt->fetch();
|
||||||
|
|
||||||
|
if ($existing_user) {
|
||||||
|
if ($existing_user['username'] === $username) {
|
||||||
|
$errors[] = 'Username already exists';
|
||||||
|
}
|
||||||
|
if ($existing_user['email'] === $email) {
|
||||||
|
$errors[] = 'Email already exists';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO users (username, email, password) VALUES (?, ?, ?)");
|
||||||
|
if ($stmt->execute([$username, $email, $hashed_password])) {
|
||||||
|
// Get the new user's ID
|
||||||
|
$user_id = $pdo->lastInsertId();
|
||||||
|
|
||||||
|
// Start session and store user info
|
||||||
|
$_SESSION['user_id'] = $user_id;
|
||||||
|
$_SESSION['username'] = $username;
|
||||||
|
$_SESSION['role'] = 'user'; // Default role
|
||||||
|
|
||||||
|
header("Location: profile.php");
|
||||||
|
exit;
|
||||||
|
} else {
|
||||||
|
$errors[] = 'Failed to register user. Please try again.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<header class="hero text-center">
|
||||||
|
<div class="container">
|
||||||
|
<h1 class="display-4">Register</h1>
|
||||||
|
<p class="lead">Create an account to get started.</p>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main class="container my-5">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-lg-6">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body p-5">
|
||||||
|
<?php if (!empty($errors)): ?>
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<?php foreach ($errors as $error): ?>
|
||||||
|
<p><?php echo $error; ?></p>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<form action="register.php" method="POST">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="username" class="form-label">Username</label>
|
||||||
|
<input type="text" class="form-control" id="username" name="username" value="<?php echo htmlspecialchars($username); ?>" required>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="email" class="form-label">Email address</label>
|
||||||
|
<input type="email" class="form-control" id="email" name="email" value="<?php echo htmlspecialchars($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="password_confirm" class="form-label">Confirm Password</label>
|
||||||
|
<input type="password" class="form-control" id="password_confirm" name="password_confirm" required>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary w-100">Register</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<?php require_once 'footer.php'; ?>
|
||||||
35
shop.php
Normal file
35
shop.php
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'header.php';
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
$pdo = db();
|
||||||
|
$stmt = $pdo->query("SELECT * FROM products");
|
||||||
|
$products = $stmt->fetchAll();
|
||||||
|
?>
|
||||||
|
|
||||||
|
<header class="hero text-center">
|
||||||
|
<div class="container">
|
||||||
|
<h1 class="display-4">Shop</h1>
|
||||||
|
<p class="lead">Browse our collection of amazing products.</p>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main class="container my-5">
|
||||||
|
<div class="row">
|
||||||
|
<?php foreach ($products as $product): ?>
|
||||||
|
<div class="col-md-4 mb-4">
|
||||||
|
<div class="card h-100">
|
||||||
|
<img src="https://via.placeholder.com/400x300" class="card-img-top" alt="<?php echo htmlspecialchars($product['name']); ?>" style="height: 200px; object-fit: cover;">
|
||||||
|
<div class="card-body d-flex flex-column">
|
||||||
|
<h5 class="card-title"><?php echo htmlspecialchars($product['name']); ?></h5>
|
||||||
|
<p class="card-text flex-grow-1"><?php echo htmlspecialchars($product['description']); ?></p>
|
||||||
|
<p class="card-text fs-4 text-primary">$<?php echo htmlspecialchars(number_format($product['price'], 2)); ?></p>
|
||||||
|
<a href="product.php?id=<?php echo $product['id']; ?>" class="btn btn-primary mt-auto">View Product</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<?php require_once 'footer.php'; ?>
|
||||||
Loading…
x
Reference in New Issue
Block a user