Add files via upload
No files matched your search
@@ -0,0 +1,20 @@
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo BASE_URL; ?>owner/products/list.php">
|
||||
<i class="fas fa-box me-2"></i>Products
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo BASE_URL; ?>owner/orders/list.php">
|
||||
<i class="fas fa-shopping-cart me-2"></i>Orders
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo BASE_URL; ?>owner/reports.php">
|
||||
<i class="fas fa-chart-bar me-2"></i>Reports
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,531 @@
|
||||
<?php
|
||||
require_once '../includes/auth_functions.php';
|
||||
redirectIfNotLoggedIn();
|
||||
redirectIfNotAdmin();
|
||||
|
||||
require_once '../config/database.php';
|
||||
|
||||
// Get total users count
|
||||
$stmt = $pdo->prepare("SELECT COUNT(*) FROM users");
|
||||
$stmt->execute();
|
||||
$total_users = $stmt->fetchColumn();
|
||||
|
||||
// Get total products count
|
||||
$stmt = $pdo->prepare("SELECT COUNT(*) FROM products");
|
||||
$stmt->execute();
|
||||
$total_products = $stmt->fetchColumn();
|
||||
|
||||
// Get total orders count
|
||||
$stmt = $pdo->prepare("SELECT COUNT(*) FROM orders");
|
||||
$stmt->execute();
|
||||
$total_orders = $stmt->fetchColumn();
|
||||
|
||||
// Get recent users
|
||||
$stmt = $pdo->prepare("SELECT * FROM users ORDER BY user_id DESC LIMIT 5");
|
||||
$stmt->execute();
|
||||
$recent_users = $stmt->fetchAll();
|
||||
|
||||
// Get recent orders
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT o.*, u.username as customer_name
|
||||
FROM orders o
|
||||
JOIN users u ON o.customer_id = u.user_id
|
||||
ORDER BY o.order_date DESC
|
||||
LIMIT 5
|
||||
");
|
||||
$stmt->execute();
|
||||
$recent_orders = $stmt->fetchAll();
|
||||
|
||||
// Get admin's products
|
||||
$stmt = $pdo->prepare("SELECT * FROM products WHERE owner_id = ? ORDER BY created_at DESC");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
$admin_products = $stmt->fetchAll();
|
||||
|
||||
// Get admin information
|
||||
$admin_stmt = $pdo->prepare("SELECT * FROM users WHERE user_id = ? AND role = 'admin'");
|
||||
$admin_stmt->execute([$_SESSION['user_id']]);
|
||||
$admin = $admin_stmt->fetch();
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Admin Dashboard - UniMarket</title>
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/style.css">
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/responsive.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
|
||||
<style>
|
||||
.admin-dashboard {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: 20px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.stat-card h3 {
|
||||
margin: 0 0 10px 0;
|
||||
color: var(--primary-dark);
|
||||
}
|
||||
|
||||
.stat-card .number {
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.recent-section {
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.recent-section h2 {
|
||||
margin: 0 0 20px 0;
|
||||
color: var(--primary-dark);
|
||||
}
|
||||
|
||||
.admin-actions {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 15px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.admin-action-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 15px;
|
||||
background: var(--primary-color);
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 8px;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
.admin-action-btn:hover {
|
||||
background: var(--primary-dark);
|
||||
}
|
||||
|
||||
.admin-action-btn i {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
th, td {
|
||||
padding: 12px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: #f5f5f5;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
tr:hover {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
.btn-small {
|
||||
display: inline-block;
|
||||
padding: 6px 12px;
|
||||
margin: 0 4px;
|
||||
border-radius: 4px;
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.btn-edit {
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
padding: 8px 16px;
|
||||
border-radius: 4px;
|
||||
text-decoration: none;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
.btn-edit:hover {
|
||||
background-color: #45a049;
|
||||
}
|
||||
|
||||
.btn-edit i {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.btn-delete {
|
||||
background-color: #dc3545;
|
||||
color: white;
|
||||
padding: 8px 16px;
|
||||
border-radius: 4px;
|
||||
text-decoration: none;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
transition: all 0.3s ease;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.btn-delete:hover {
|
||||
background-color: #c82333;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-delete i {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.edit-product {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.form-group input[type="text"],
|
||||
.form-group input[type="number"],
|
||||
.form-group textarea,
|
||||
.form-group select {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.form-group textarea {
|
||||
height: 150px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.btn-submit {
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
padding: 12px 24px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.btn-submit:hover {
|
||||
background-color: #45a049;
|
||||
}
|
||||
|
||||
.alert {
|
||||
padding: 15px;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.alert-success {
|
||||
background-color: #dff0d8;
|
||||
color: #3c763d;
|
||||
border: 1px solid #d6e9c6;
|
||||
}
|
||||
|
||||
.alert-error {
|
||||
background-color: #f2dede;
|
||||
color: #a94442;
|
||||
border: 1px solid #ebccd1;
|
||||
}
|
||||
|
||||
.back-button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: #6c757d;
|
||||
text-decoration: none;
|
||||
margin-bottom: 20px;
|
||||
font-weight: 500;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
.back-button:hover {
|
||||
color: #495057;
|
||||
}
|
||||
|
||||
.back-button i {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.image-preview {
|
||||
max-width: 200px;
|
||||
margin-top: 10px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.btn-add {
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
padding: 8px 16px;
|
||||
border-radius: 4px;
|
||||
text-decoration: none;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.btn-add:hover {
|
||||
background-color: #45a049;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 40px;
|
||||
background-color: #f9f9f9;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.empty-state i {
|
||||
font-size: 48px;
|
||||
color: #ccc;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.empty-state p {
|
||||
color: #666;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
padding: 10px 20px;
|
||||
border-radius: 4px;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background-color: #45a049;
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
display: inline-block;
|
||||
padding: 4px 8px;
|
||||
border-radius: 12px;
|
||||
font-size: 0.9em;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.status-active {
|
||||
background-color: #dff0d8;
|
||||
color: #3c763d;
|
||||
}
|
||||
|
||||
.status-inactive {
|
||||
background-color: #f2dede;
|
||||
color: #a94442;
|
||||
}
|
||||
|
||||
.product-image {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
object-fit: cover;
|
||||
border-radius: 4px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<?php include '../includes/header.php'; ?>
|
||||
|
||||
<div class="container admin-dashboard">
|
||||
<h1>Admin Dashboard</h1>
|
||||
|
||||
<div class="stats-grid">
|
||||
<div class="stat-card">
|
||||
<h3>Total Users</h3>
|
||||
<div class="number"><?php echo $total_users; ?></div>
|
||||
</div>
|
||||
|
||||
<div class="stat-card">
|
||||
<h3>Total Products</h3>
|
||||
<div class="number"><?php echo $total_products; ?></div>
|
||||
</div>
|
||||
|
||||
<div class="stat-card">
|
||||
<h3>Total Orders</h3>
|
||||
<div class="number"><?php echo $total_orders; ?></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="admin-actions">
|
||||
<a href="/unimarket/admin/users/manage.php" class="admin-action-btn">
|
||||
<i class="fas fa-users"></i>
|
||||
<span>Manage Users</span>
|
||||
</a>
|
||||
<a href="/unimarket/admin/products/index.php" class="admin-action-btn">
|
||||
<i class="fas fa-box"></i>
|
||||
<span>Manage Products</span>
|
||||
</a>
|
||||
<a href="/unimarket/admin/orders/manage.php" class="admin-action-btn">
|
||||
<i class="fas fa-shopping-cart"></i> Manage Orders
|
||||
</a>
|
||||
<a href="/unimarket/admin/products/add.php" class="admin-action-btn">
|
||||
<i class="fas fa-plus"></i> Add My Product
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="recent-section">
|
||||
<div class="section-header">
|
||||
<h2>My Products</h2>
|
||||
<a href="/unimarket/admin/products/add.php" class="btn-add">
|
||||
<i class="fas fa-plus"></i> Add New Product
|
||||
</a>
|
||||
</div>
|
||||
<?php if (empty($admin_products)): ?>
|
||||
<div class="empty-state">
|
||||
<i class="fas fa-box-open"></i>
|
||||
<p>You haven't added any products yet.</p>
|
||||
<a href="/unimarket/admin/products/add.php" class="btn-primary">Add Your First Product</a>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Image</th>
|
||||
<th>Name</th>
|
||||
<th>Price</th>
|
||||
<th>Stock</th>
|
||||
<th>Status</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($admin_products as $product): ?>
|
||||
<tr>
|
||||
<td>
|
||||
<?php if (!empty($product['image_path'])): ?>
|
||||
<img src="/unimarket/uploads/products/<?php echo htmlspecialchars($product['image_path']); ?>" alt="Product" class="product-image">
|
||||
<?php else: ?>
|
||||
<img src="/unimarket/assets/images/no-image.png" alt="No Image" class="product-image">
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?php echo htmlspecialchars($product['name']); ?></td>
|
||||
<td>₱<?php echo number_format($product['price'], 2); ?></td>
|
||||
<td><?php echo $product['stock_quantity']; ?></td>
|
||||
<td>
|
||||
<span class="status-badge <?php echo $product['stock_quantity'] > 0 ? 'status-active' : 'status-inactive'; ?>">
|
||||
<?php echo $product['stock_quantity'] > 0 ? 'Active' : 'Inactive'; ?>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<a href="edit_product.php?id=<?php echo $product['product_id']; ?>" class="btn-edit">
|
||||
<i class="fas fa-edit"></i> Edit
|
||||
</a>
|
||||
<a href="/unimarket/admin/products/delete.php?id=<?php echo $product['product_id']; ?>" class="btn-delete" onclick="return confirm('Are you sure you want to delete this product?')">
|
||||
<i class="fas fa-trash"></i> Delete
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="recent-section">
|
||||
<h2>Recent Users</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Username</th>
|
||||
<th>Email</th>
|
||||
<th>Role</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($recent_users as $user): ?>
|
||||
<tr>
|
||||
<td><?php echo htmlspecialchars($user['username']); ?></td>
|
||||
<td><?php echo htmlspecialchars($user['email']); ?></td>
|
||||
<td><?php echo htmlspecialchars($user['role']); ?></td>
|
||||
<td>
|
||||
<a href="/unimarket/admin/users/edit.php?id=<?php echo $user['user_id']; ?>" class="btn-small btn-edit">
|
||||
<i class="fas fa-edit"></i> Edit
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="recent-section">
|
||||
<h2>Recent Orders</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Order ID</th>
|
||||
<th>Customer</th>
|
||||
<th>Date</th>
|
||||
<th>Amount</th>
|
||||
<th>Status</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($recent_orders as $order): ?>
|
||||
<tr>
|
||||
<td>#<?php echo $order['order_id']; ?></td>
|
||||
<td><?php echo htmlspecialchars($order['customer_name']); ?></td>
|
||||
<td><?php echo date('M d, Y', strtotime($order['order_date'])); ?></td>
|
||||
<td>₱<?php echo number_format($order['total_amount'], 2); ?></td>
|
||||
<td><?php echo ucfirst($order['status']); ?></td>
|
||||
<td>
|
||||
<a href="/unimarket/admin/orders/view.php?id=<?php echo $order['order_id']; ?>" class="btn-small btn-view">
|
||||
<i class="fas fa-eye"></i> View
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include '../includes/footer.php'; ?>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,563 @@
|
||||
<?php
|
||||
require_once '../includes/auth_functions.php';
|
||||
redirectIfNotLoggedIn();
|
||||
redirectIfNotAdmin();
|
||||
|
||||
require_once '../config/database.php';
|
||||
|
||||
$success_message = '';
|
||||
$error_message = '';
|
||||
|
||||
// Get product ID from URL
|
||||
$product_id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
|
||||
|
||||
// Fetch product details
|
||||
$stmt = $pdo->prepare("SELECT * FROM products WHERE product_id = ? AND owner_id = ?");
|
||||
$stmt->execute([$product_id, $_SESSION['user_id']]);
|
||||
$product = $stmt->fetch();
|
||||
|
||||
if (!$product) {
|
||||
header('Location: dashboard.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$name = trim($_POST['name']);
|
||||
$description = trim($_POST['description']);
|
||||
$price = trim($_POST['price']);
|
||||
$category = trim($_POST['category']);
|
||||
$subcategory = trim($_POST['subcategory']);
|
||||
$stock_quantity = (int)$_POST['stock_quantity'];
|
||||
|
||||
// Get size data if category is clothes
|
||||
$size_data = null;
|
||||
if ($category === 'clothes' && isset($_POST['sizes']) && isset($_POST['size_quantities'])) {
|
||||
$sizes = $_POST['sizes'];
|
||||
$quantities = $_POST['size_quantities'];
|
||||
$size_data = [];
|
||||
|
||||
for ($i = 0; $i < count($sizes); $i++) {
|
||||
if (!empty($sizes[$i]) && isset($quantities[$i]) && $quantities[$i] > 0) {
|
||||
$size_data[$sizes[$i]] = (int)$quantities[$i];
|
||||
}
|
||||
}
|
||||
|
||||
// Update stock quantity based on sizes
|
||||
$stock_quantity = array_sum($size_data);
|
||||
}
|
||||
|
||||
// Validate inputs
|
||||
if (empty($name) || empty($description) || empty($price) || empty($stock_quantity)) {
|
||||
$error_message = 'Please fill in all required fields.';
|
||||
} elseif (!is_numeric($price) || $price <= 0) {
|
||||
$error_message = 'Please enter a valid price.';
|
||||
} elseif ($stock_quantity < 0) {
|
||||
$error_message = 'Stock quantity cannot be negative.';
|
||||
} elseif ($category === 'clothes' && empty($size_data)) {
|
||||
$error_message = 'Please add at least one size with quantity.';
|
||||
} else {
|
||||
try {
|
||||
// Handle image upload
|
||||
$image_path = $product['image_path']; // Keep existing image by default
|
||||
if (isset($_FILES['image']) && $_FILES['image']['error'] === UPLOAD_ERR_OK) {
|
||||
$upload_dir = '../uploads/products/';
|
||||
if (!file_exists($upload_dir)) {
|
||||
mkdir($upload_dir, 0777, true);
|
||||
}
|
||||
|
||||
$file_extension = strtolower(pathinfo($_FILES['image']['name'], PATHINFO_EXTENSION));
|
||||
$allowed_extensions = ['jpg', 'jpeg', 'png', 'gif'];
|
||||
|
||||
if (!in_array($file_extension, $allowed_extensions)) {
|
||||
throw new Exception('Invalid file type. Only JPG, JPEG, PNG, and GIF files are allowed.');
|
||||
}
|
||||
|
||||
$image_path = uniqid() . '.' . $file_extension;
|
||||
$upload_path = $upload_dir . $image_path;
|
||||
|
||||
if (!move_uploaded_file($_FILES['image']['tmp_name'], $upload_path)) {
|
||||
throw new Exception('Failed to upload image.');
|
||||
}
|
||||
|
||||
// Delete old image if exists
|
||||
if ($product['image_path'] && file_exists($upload_dir . $product['image_path'])) {
|
||||
unlink($upload_dir . $product['image_path']);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($error_message)) {
|
||||
$pdo->beginTransaction();
|
||||
|
||||
$stmt = $pdo->prepare("
|
||||
UPDATE products
|
||||
SET name = ?, description = ?, price = ?, category = ?, Sub_Cat = ?,
|
||||
stock_quantity = ?, image_path = ?, size_data = ?
|
||||
WHERE product_id = ? AND owner_id = ?
|
||||
");
|
||||
$stmt->execute([
|
||||
$name,
|
||||
$description,
|
||||
$price,
|
||||
$category,
|
||||
$subcategory,
|
||||
$stock_quantity,
|
||||
$image_path,
|
||||
$size_data ? json_encode($size_data) : null,
|
||||
$product_id,
|
||||
$_SESSION['user_id']
|
||||
]);
|
||||
|
||||
$pdo->commit();
|
||||
$success_message = 'Product updated successfully!';
|
||||
|
||||
// Refresh product data
|
||||
$stmt = $pdo->prepare("SELECT * FROM products WHERE product_id = ? AND owner_id = ?");
|
||||
$stmt->execute([$product_id, $_SESSION['user_id']]);
|
||||
$product = $stmt->fetch();
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$pdo->rollBack();
|
||||
$error_message = $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Edit Product - UniMarket</title>
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/style.css">
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/responsive.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
|
||||
<style>
|
||||
.edit-product {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.form-group input[type="text"],
|
||||
.form-group input[type="number"],
|
||||
.form-group textarea,
|
||||
.form-group select {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.form-group textarea {
|
||||
height: 150px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.btn-submit {
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
padding: 12px 24px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.btn-submit:hover {
|
||||
background-color: #45a049;
|
||||
}
|
||||
|
||||
.alert {
|
||||
padding: 15px;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.alert-success {
|
||||
background-color: #dff0d8;
|
||||
color: #3c763d;
|
||||
border: 1px solid #d6e9c6;
|
||||
}
|
||||
|
||||
.alert-error {
|
||||
background-color: #f2dede;
|
||||
color: #a94442;
|
||||
border: 1px solid #ebccd1;
|
||||
}
|
||||
|
||||
.back-button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: #6c757d;
|
||||
text-decoration: none;
|
||||
margin-bottom: 20px;
|
||||
font-weight: 500;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
.back-button:hover {
|
||||
color: #495057;
|
||||
}
|
||||
|
||||
.back-button i {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.image-preview {
|
||||
max-width: 200px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.size-row {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-bottom: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.size-select, .size-quantity {
|
||||
padding: 8px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.size-select {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.size-quantity {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.btn-remove-size {
|
||||
background: #ff4444;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
cursor: pointer;
|
||||
font-size: 18px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.btn-add-size {
|
||||
background: var(--primary-color);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 8px 16px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.btn-add-size:hover {
|
||||
background: var(--primary-dark);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<?php include '../includes/header.php'; ?>
|
||||
|
||||
<div class="container edit-product">
|
||||
<a href="dashboard.php" class="back-button">
|
||||
<i class="fas fa-arrow-left"></i> Back to Dashboard
|
||||
</a>
|
||||
|
||||
<h1>Edit Product</h1>
|
||||
|
||||
<?php if ($success_message): ?>
|
||||
<div class="alert alert-success">
|
||||
<?php echo $success_message; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($error_message): ?>
|
||||
<div class="alert alert-error">
|
||||
<?php echo $error_message; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="POST" enctype="multipart/form-data">
|
||||
<div class="form-group">
|
||||
<label for="name">Product Name*</label>
|
||||
<input type="text" id="name" name="name" value="<?php echo htmlspecialchars($product['name']); ?>" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="description">Description*</label>
|
||||
<textarea id="description" name="description" required><?php echo htmlspecialchars($product['description']); ?></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="price">Price*</label>
|
||||
<input type="number" id="price" name="price" step="0.01" min="0" value="<?php echo htmlspecialchars($product['price']); ?>" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="category">Category*</label>
|
||||
<select id="category" name="category" onchange="updateSubcategories()" required>
|
||||
<option value="">Select a category</option>
|
||||
<option value="clothes" <?php echo $product['category'] === 'clothes' ? 'selected' : ''; ?>>Clothes</option>
|
||||
<option value="school_supplies" <?php echo $product['category'] === 'school_supplies' ? 'selected' : ''; ?>>School Supplies</option>
|
||||
<option value="others" <?php echo $product['category'] === 'others' ? 'selected' : ''; ?>>Others</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="subcategoryGroup" style="display: none;">
|
||||
<label for="subcategory">Subcategory*</label>
|
||||
<select id="subcategory" name="subcategory" onchange="handleSubcategoryChange()" required>
|
||||
<option value="">Select a subcategory</option>
|
||||
</select>
|
||||
<input type="text" id="customSubcategory" name="custom_subcategory" style="display: none;" placeholder="Enter subcategory">
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="sizeGroup" style="display: <?php echo $product['category'] === 'clothes' ? 'block' : 'none'; ?>;">
|
||||
<label>Sizes and Quantities*</label>
|
||||
<div id="sizeContainer">
|
||||
<?php
|
||||
$size_data = json_decode($product['size_data'], true);
|
||||
if ($size_data) {
|
||||
foreach ($size_data as $size => $quantity) {
|
||||
echo '<div class="size-row">';
|
||||
echo '<select class="size-select" name="sizes[]">';
|
||||
echo '<option value="XS" ' . ($size === 'XS' ? 'selected' : '') . '>XS</option>';
|
||||
echo '<option value="S" ' . ($size === 'S' ? 'selected' : '') . '>S</option>';
|
||||
echo '<option value="M" ' . ($size === 'M' ? 'selected' : '') . '>M</option>';
|
||||
echo '<option value="L" ' . ($size === 'L' ? 'selected' : '') . '>L</option>';
|
||||
echo '<option value="XL" ' . ($size === 'XL' ? 'selected' : '') . '>XL</option>';
|
||||
echo '</select>';
|
||||
echo '<input type="number" class="size-quantity" name="size_quantities[]" min="0" value="' . $quantity . '" required>';
|
||||
echo '<button type="button" class="btn-remove-size" onclick="removeSize(this)">×</button>';
|
||||
echo '</div>';
|
||||
}
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<button type="button" class="btn-add-size" onclick="addSize()">Add Size</button>
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="stockGroup" style="display: <?php echo $product['category'] === 'clothes' ? 'none' : 'block'; ?>;">
|
||||
<label for="stock_quantity">Stock Quantity*</label>
|
||||
<input type="number" id="stock_quantity" name="stock_quantity" min="0" value="<?php echo htmlspecialchars($product['stock_quantity']); ?>" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="image">Product Image</label>
|
||||
<?php if ($product['image_path']): ?>
|
||||
<img src="/unimarket/uploads/products/<?php echo htmlspecialchars($product['image_path']); ?>" class="image-preview" style="display: block;">
|
||||
<?php endif; ?>
|
||||
<input type="file" id="image" name="image" accept="image/*" onchange="previewImage(this)">
|
||||
<img id="imagePreview" class="image-preview">
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn-submit">Update Product</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const subcategories = {
|
||||
clothes: [
|
||||
'T-Shirts',
|
||||
'Pants',
|
||||
'PE Uniform',
|
||||
'University Uniform'
|
||||
],
|
||||
school_supplies: [
|
||||
'Notebooks',
|
||||
'Pens',
|
||||
'Pencils',
|
||||
'Highlighters',
|
||||
'Markers',
|
||||
'Art Supplies',
|
||||
'Paper',
|
||||
'Folders',
|
||||
'Binders',
|
||||
'Staplers'
|
||||
],
|
||||
others: [
|
||||
'University Lace',
|
||||
'Hygiene Products',
|
||||
'Seals',
|
||||
'Calculator',
|
||||
'ID Holders'
|
||||
]
|
||||
};
|
||||
|
||||
function updateSubcategories() {
|
||||
const categorySelect = document.getElementById('category');
|
||||
const subcategorySelect = document.getElementById('subcategory');
|
||||
const subcategoryGroup = document.getElementById('subcategoryGroup');
|
||||
const customSubcategory = document.getElementById('customSubcategory');
|
||||
const sizeGroup = document.getElementById('sizeGroup');
|
||||
const stockQuantityInput = document.getElementById('stock_quantity');
|
||||
const selectedCategory = categorySelect.value;
|
||||
|
||||
// Clear current options
|
||||
subcategorySelect.innerHTML = '<option value="">Select a subcategory</option>';
|
||||
|
||||
if (selectedCategory && subcategories[selectedCategory]) {
|
||||
// Show subcategory group
|
||||
subcategoryGroup.style.display = 'block';
|
||||
subcategorySelect.style.display = 'block';
|
||||
customSubcategory.style.display = 'none';
|
||||
|
||||
// Show/hide size group based on category
|
||||
if (selectedCategory === 'clothes') {
|
||||
sizeGroup.style.display = 'block';
|
||||
stockQuantityInput.style.display = 'none';
|
||||
stockQuantityInput.value = calculateTotalSizeQuantity();
|
||||
} else {
|
||||
sizeGroup.style.display = 'none';
|
||||
stockQuantityInput.style.display = 'block';
|
||||
}
|
||||
|
||||
// Add new options
|
||||
subcategories[selectedCategory].forEach(subcategory => {
|
||||
const option = document.createElement('option');
|
||||
option.value = subcategory.toLowerCase().replace(/\s+/g, '_');
|
||||
option.textContent = subcategory;
|
||||
subcategorySelect.appendChild(option);
|
||||
});
|
||||
|
||||
// Add custom option
|
||||
const customOption = document.createElement('option');
|
||||
customOption.value = 'custom';
|
||||
customOption.textContent = 'Other (Type your own)';
|
||||
subcategorySelect.appendChild(customOption);
|
||||
} else {
|
||||
// Hide subcategory group if no category selected
|
||||
subcategoryGroup.style.display = 'none';
|
||||
sizeGroup.style.display = 'none';
|
||||
stockQuantityInput.style.display = 'block';
|
||||
}
|
||||
}
|
||||
|
||||
function handleSubcategoryChange() {
|
||||
const subcategorySelect = document.getElementById('subcategory');
|
||||
const customSubcategory = document.getElementById('customSubcategory');
|
||||
|
||||
if (subcategorySelect.value === 'custom') {
|
||||
subcategorySelect.style.display = 'none';
|
||||
customSubcategory.style.display = 'block';
|
||||
customSubcategory.focus();
|
||||
customSubcategory.required = true;
|
||||
subcategorySelect.name = 'subcategory_placeholder';
|
||||
customSubcategory.name = 'subcategory';
|
||||
} else {
|
||||
subcategorySelect.style.display = 'block';
|
||||
customSubcategory.style.display = 'none';
|
||||
customSubcategory.required = false;
|
||||
subcategorySelect.name = 'subcategory';
|
||||
customSubcategory.name = 'custom_subcategory';
|
||||
}
|
||||
}
|
||||
|
||||
function calculateTotalSizeQuantity() {
|
||||
const quantities = document.getElementsByName('size_quantities[]');
|
||||
let total = 0;
|
||||
for (let input of quantities) {
|
||||
total += parseInt(input.value) || 0;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
function updateTotalQuantity() {
|
||||
const stockQuantityInput = document.getElementById('stock_quantity');
|
||||
stockQuantityInput.value = calculateTotalSizeQuantity();
|
||||
}
|
||||
|
||||
function addSize() {
|
||||
const container = document.getElementById('sizeContainer');
|
||||
const row = document.createElement('div');
|
||||
row.className = 'size-row';
|
||||
|
||||
const sizeSelect = document.createElement('select');
|
||||
sizeSelect.className = 'size-select';
|
||||
sizeSelect.name = 'sizes[]';
|
||||
|
||||
['XS', 'S', 'M', 'L', 'XL'].forEach(size => {
|
||||
const option = document.createElement('option');
|
||||
option.value = size;
|
||||
option.textContent = size;
|
||||
sizeSelect.appendChild(option);
|
||||
});
|
||||
|
||||
const quantityInput = document.createElement('input');
|
||||
quantityInput.type = 'number';
|
||||
quantityInput.className = 'size-quantity';
|
||||
quantityInput.name = 'size_quantities[]';
|
||||
quantityInput.min = '0';
|
||||
quantityInput.required = true;
|
||||
|
||||
const removeButton = document.createElement('button');
|
||||
removeButton.type = 'button';
|
||||
removeButton.className = 'btn-remove-size';
|
||||
removeButton.textContent = '×';
|
||||
removeButton.onclick = function() { removeSize(this); };
|
||||
|
||||
row.appendChild(sizeSelect);
|
||||
row.appendChild(quantityInput);
|
||||
row.appendChild(removeButton);
|
||||
container.appendChild(row);
|
||||
}
|
||||
|
||||
function removeSize(button) {
|
||||
button.parentElement.remove();
|
||||
}
|
||||
|
||||
function previewImage(input) {
|
||||
const preview = document.getElementById('imagePreview');
|
||||
if (input.files && input.files[0]) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
preview.src = e.target.result;
|
||||
preview.style.display = 'block';
|
||||
}
|
||||
reader.readAsDataURL(input.files[0]);
|
||||
} else {
|
||||
preview.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize form state
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
updateSubcategories();
|
||||
const subcategorySelect = document.getElementById('subcategory');
|
||||
const currentSubcategory = '<?php echo htmlspecialchars($product['Sub_Cat']); ?>';
|
||||
|
||||
// Check if current subcategory is in the list
|
||||
let found = false;
|
||||
for (let option of subcategorySelect.options) {
|
||||
if (option.value === currentSubcategory) {
|
||||
option.selected = true;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If not found, it's a custom subcategory
|
||||
if (!found) {
|
||||
subcategorySelect.value = 'custom';
|
||||
handleSubcategoryChange();
|
||||
document.getElementById('customSubcategory').value = currentSubcategory;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,266 @@
|
||||
<?php
|
||||
require_once '../../includes/auth_functions.php';
|
||||
redirectIfNotLoggedIn();
|
||||
redirectIfNotAdmin();
|
||||
|
||||
require_once '../../config/database.php';
|
||||
|
||||
// Handle order status updates
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_status'])) {
|
||||
$order_id = $_POST['order_id'];
|
||||
$new_status = $_POST['status'];
|
||||
|
||||
$stmt = $pdo->prepare("UPDATE orders SET status = ? WHERE order_id = ?");
|
||||
$stmt->execute([$new_status, $order_id]);
|
||||
flashMessage('success', 'Order status updated successfully.');
|
||||
|
||||
header("Location: manage.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
// Get all orders with customer information
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT o.*, u.username as customer_name
|
||||
FROM orders o
|
||||
JOIN users u ON o.customer_id = u.user_id
|
||||
ORDER BY o.order_date DESC
|
||||
");
|
||||
$stmt->execute();
|
||||
$orders = $stmt->fetchAll();
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Manage Orders - UniMarket Admin</title>
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/style.css">
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/responsive.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
|
||||
<style>
|
||||
.manage-orders {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.orders-table {
|
||||
width: 100%;
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.orders-table table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.orders-table th,
|
||||
.orders-table td {
|
||||
padding: 15px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.orders-table th {
|
||||
background-color: #f5f5f5;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.orders-table tr:hover {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
.status-select {
|
||||
padding: 5px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.btn-small {
|
||||
padding: 5px 10px;
|
||||
border-radius: 4px;
|
||||
text-decoration: none;
|
||||
font-size: 0.9em;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.btn-update {
|
||||
background: var(--primary-color);
|
||||
color: white;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.btn-update:hover {
|
||||
background: var(--primary-dark);
|
||||
}
|
||||
|
||||
.btn-view {
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
border: none;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.btn-view:hover {
|
||||
background-color: #218838;
|
||||
}
|
||||
|
||||
.alert {
|
||||
padding: 15px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.alert-success {
|
||||
background-color: #d4edda;
|
||||
color: #155724;
|
||||
border: 1px solid #c3e6cb;
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
padding: 5px 10px;
|
||||
border-radius: 15px;
|
||||
font-size: 0.9em;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.status-pending {
|
||||
background-color: #fff3cd;
|
||||
color: #856404;
|
||||
}
|
||||
|
||||
.status-completed {
|
||||
background-color: #d4edda;
|
||||
color: #155724;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.completed-note {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: #155724;
|
||||
font-weight: 500;
|
||||
padding: 5px 10px;
|
||||
background-color: #d4edda;
|
||||
border-radius: 15px;
|
||||
}
|
||||
|
||||
.completed-note i {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.status-cancelled {
|
||||
background-color: #f8d7da;
|
||||
color: #721c24;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.cancelled-note {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: #721c24;
|
||||
font-weight: 500;
|
||||
padding: 5px 10px;
|
||||
background-color: #f8d7da;
|
||||
border-radius: 15px;
|
||||
}
|
||||
|
||||
.cancelled-note i {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.back-button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: #6c757d;
|
||||
text-decoration: none;
|
||||
margin-bottom: 20px;
|
||||
font-weight: 500;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
.back-button:hover {
|
||||
color: #495057;
|
||||
}
|
||||
|
||||
.back-button i {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<?php include '../../includes/header.php'; ?>
|
||||
|
||||
<div class="container manage-orders">
|
||||
<a href="/unimarket/admin/dashboard.php" class="back-button">
|
||||
<i class="fas fa-arrow-left"></i> Back to Dashboard
|
||||
</a>
|
||||
|
||||
<h1>Manage Orders</h1>
|
||||
|
||||
<?php if ($message = getFlashMessage('success')): ?>
|
||||
<div class="alert alert-success"><?php echo $message; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="orders-table">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Order ID</th>
|
||||
<th>Customer</th>
|
||||
<th>Date</th>
|
||||
<th>Amount</th>
|
||||
<th>Status</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($orders as $order): ?>
|
||||
<tr>
|
||||
<td>#<?php echo $order['order_id']; ?></td>
|
||||
<td><?php echo htmlspecialchars($order['customer_name']); ?></td>
|
||||
<td><?php echo date('M d, Y H:i', strtotime($order['order_date'])); ?></td>
|
||||
<td>$<?php echo number_format($order['total_amount'], 2); ?></td>
|
||||
<td>
|
||||
<?php if ($order['status'] === 'completed'): ?>
|
||||
<div class="completed-note">
|
||||
<i class="fas fa-check-circle"></i> Completed
|
||||
</div>
|
||||
<?php elseif ($order['status'] === 'cancelled'): ?>
|
||||
<div class="cancelled-note">
|
||||
<i class="fas fa-times-circle"></i> Cancelled
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<form method="POST" style="display: inline;">
|
||||
<input type="hidden" name="order_id" value="<?php echo $order['order_id']; ?>">
|
||||
<select name="status" class="status-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="completed" <?php echo $order['status'] === 'completed' ? 'selected' : ''; ?>>Completed</option>
|
||||
<option value="cancelled" <?php echo $order['status'] === 'cancelled' ? 'selected' : ''; ?>>Cancelled</option>
|
||||
</select>
|
||||
<button type="submit" name="update_status" class="btn-small btn-update">Update</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<a href="view.php?id=<?php echo $order['order_id']; ?>" class="btn-small btn-view">
|
||||
<i class="fas fa-eye"></i> View Details
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include '../../includes/footer.php'; ?>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,211 @@
|
||||
<?php
|
||||
require_once '../../includes/auth_functions.php';
|
||||
redirectIfNotLoggedIn();
|
||||
redirectIfNotAdmin();
|
||||
|
||||
require_once '../../config/database.php';
|
||||
|
||||
// Check if order ID is provided
|
||||
if (!isset($_GET['id'])) {
|
||||
header("Location: /unimarket/admin/orders/manage.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
$order_id = (int)$_GET['id'];
|
||||
|
||||
// Get order details with customer information
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT o.*, u.username as customer_name, u.email as customer_email
|
||||
FROM orders o
|
||||
JOIN users u ON o.customer_id = u.user_id
|
||||
WHERE o.order_id = ?
|
||||
");
|
||||
$stmt->execute([$order_id]);
|
||||
$order = $stmt->fetch();
|
||||
|
||||
if (!$order) {
|
||||
header("Location: /unimarket/admin/orders/manage.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
// Get order items
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT oi.*, p.name as product_name, p.price as product_price
|
||||
FROM order_items oi
|
||||
JOIN products p ON oi.product_id = p.product_id
|
||||
WHERE oi.order_id = ?
|
||||
");
|
||||
$stmt->execute([$order_id]);
|
||||
$order_items = $stmt->fetchAll();
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>View Order - UniMarket</title>
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/style.css">
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/responsive.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
|
||||
<style>
|
||||
.order-details {
|
||||
max-width: 800px;
|
||||
margin: 30px auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.order-info {
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.order-info h2 {
|
||||
margin: 0 0 20px 0;
|
||||
color: var(--primary-dark);
|
||||
}
|
||||
|
||||
.info-group {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.info-group label {
|
||||
font-weight: 600;
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.info-group span {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.order-items {
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.order-items h2 {
|
||||
margin: 0 0 20px 0;
|
||||
color: var(--primary-dark);
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
th, td {
|
||||
padding: 12px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: #f5f5f5;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.order-total {
|
||||
text-align: right;
|
||||
margin-top: 20px;
|
||||
font-size: 1.2em;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
display: inline-block;
|
||||
padding: 5px 10px;
|
||||
border-radius: 15px;
|
||||
font-size: 0.9em;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.status-pending {
|
||||
background-color: #fff3cd;
|
||||
color: #856404;
|
||||
}
|
||||
|
||||
.status-processing {
|
||||
background-color: #cce5ff;
|
||||
color: #004085;
|
||||
}
|
||||
|
||||
.status-completed {
|
||||
background-color: #d4edda;
|
||||
color: #155724;
|
||||
}
|
||||
|
||||
.status-cancelled {
|
||||
background-color: #f8d7da;
|
||||
color: #721c24;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<?php include '../../includes/header.php'; ?>
|
||||
|
||||
<div class="container order-details">
|
||||
<div class="order-info">
|
||||
<h2>Order #<?php echo $order['order_id']; ?></h2>
|
||||
|
||||
<div class="info-group">
|
||||
<label>Customer</label>
|
||||
<span><?php echo htmlspecialchars($order['customer_name']); ?></span>
|
||||
</div>
|
||||
|
||||
<div class="info-group">
|
||||
<label>Email</label>
|
||||
<span><?php echo htmlspecialchars($order['customer_email']); ?></span>
|
||||
</div>
|
||||
|
||||
<div class="info-group">
|
||||
<label>Order Date</label>
|
||||
<span><?php echo date('F d, Y H:i', strtotime($order['order_date'])); ?></span>
|
||||
</div>
|
||||
|
||||
<div class="info-group">
|
||||
<label>Status</label>
|
||||
<span class="status-badge status-<?php echo strtolower($order['status']); ?>">
|
||||
<?php echo ucfirst($order['status']); ?>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="order-items">
|
||||
<h2>Order Items</h2>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Product</th>
|
||||
<th>Price</th>
|
||||
<th>Quantity</th>
|
||||
<th>Subtotal</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($order_items as $item): ?>
|
||||
<tr>
|
||||
<td><?php echo htmlspecialchars($item['product_name']); ?></td>
|
||||
<td>₱<?php echo number_format($item['product_price'], 2); ?></td>
|
||||
<td><?php echo $item['quantity']; ?></td>
|
||||
<td>₱<?php echo number_format($item['product_price'] * $item['quantity'], 2); ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="order-total">
|
||||
Total: ₱<?php echo number_format($order['total_amount'], 2); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include '../../includes/footer.php'; ?>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,538 @@
|
||||
<?php
|
||||
require_once '../../includes/auth_functions.php';
|
||||
redirectIfNotLoggedIn();
|
||||
redirectIfNotAdmin();
|
||||
|
||||
require_once '../../config/database.php';
|
||||
|
||||
$success_message = '';
|
||||
$error_message = '';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$name = trim($_POST['name']);
|
||||
$description = trim($_POST['description']);
|
||||
$price = trim($_POST['price']);
|
||||
$category = trim($_POST['category']);
|
||||
$subcategory = trim($_POST['subcategory']);
|
||||
$stock_quantity = (int)$_POST['stock_quantity'];
|
||||
|
||||
// Get size data if category is clothes
|
||||
$size_data = null;
|
||||
if ($category === 'clothes' && isset($_POST['sizes']) && isset($_POST['size_quantities'])) {
|
||||
$sizes = $_POST['sizes'];
|
||||
$quantities = $_POST['size_quantities'];
|
||||
$size_data = [];
|
||||
|
||||
for ($i = 0; $i < count($sizes); $i++) {
|
||||
if (!empty($sizes[$i]) && isset($quantities[$i]) && $quantities[$i] > 0) {
|
||||
$size_data[$sizes[$i]] = (int)$quantities[$i];
|
||||
}
|
||||
}
|
||||
|
||||
// Update stock quantity based on sizes
|
||||
$stock_quantity = array_sum($size_data);
|
||||
}
|
||||
|
||||
// Validate inputs
|
||||
if (empty($name) || empty($description) || empty($price) || empty($stock_quantity)) {
|
||||
$error_message = 'Please fill in all required fields.';
|
||||
} elseif (!is_numeric($price) || $price <= 0) {
|
||||
$error_message = 'Please enter a valid price.';
|
||||
} elseif ($stock_quantity < 0) {
|
||||
$error_message = 'Stock quantity cannot be negative.';
|
||||
} elseif ($category === 'clothes' && empty($size_data)) {
|
||||
$error_message = 'Please add at least one size with quantity.';
|
||||
} else {
|
||||
try {
|
||||
// Handle image upload
|
||||
$image_path = null;
|
||||
if (isset($_FILES['image']) && $_FILES['image']['error'] === UPLOAD_ERR_OK) {
|
||||
$upload_dir = '../../uploads/products/';
|
||||
if (!file_exists($upload_dir)) {
|
||||
mkdir($upload_dir, 0777, true);
|
||||
}
|
||||
|
||||
$file_extension = strtolower(pathinfo($_FILES['image']['name'], PATHINFO_EXTENSION));
|
||||
$allowed_extensions = ['jpg', 'jpeg', 'png', 'gif'];
|
||||
|
||||
if (!in_array($file_extension, $allowed_extensions)) {
|
||||
throw new Exception('Invalid file type. Only JPG, JPEG, PNG, and GIF files are allowed.');
|
||||
}
|
||||
|
||||
$image_path = uniqid() . '.' . $file_extension;
|
||||
$upload_path = $upload_dir . $image_path;
|
||||
|
||||
if (!move_uploaded_file($_FILES['image']['tmp_name'], $upload_path)) {
|
||||
throw new Exception('Failed to upload image.');
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($error_message)) {
|
||||
$pdo->beginTransaction();
|
||||
|
||||
// Get admin's user ID from session
|
||||
$owner_id = $_SESSION['user_id'];
|
||||
|
||||
$stmt = $pdo->prepare("
|
||||
INSERT INTO products
|
||||
(owner_id, name, description, price, category, Sub_Cat, stock_quantity, image_path, size_data)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
");
|
||||
$stmt->execute([
|
||||
$owner_id,
|
||||
$name,
|
||||
$description,
|
||||
$price,
|
||||
$category,
|
||||
$subcategory,
|
||||
$stock_quantity,
|
||||
$image_path,
|
||||
$size_data ? json_encode($size_data) : null
|
||||
]);
|
||||
|
||||
$pdo->commit();
|
||||
$success_message = 'Product added successfully!';
|
||||
|
||||
// Clear form
|
||||
$name = $description = $price = $category = $subcategory = '';
|
||||
$stock_quantity = 0;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$pdo->rollBack();
|
||||
$error_message = $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Add Product - UniMarket</title>
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/style.css">
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/responsive.css">
|
||||
<style>
|
||||
.add-product {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.form-group input[type="text"],
|
||||
.form-group input[type="number"],
|
||||
.form-group textarea,
|
||||
.form-group select {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.form-group textarea {
|
||||
height: 150px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.btn-submit {
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
padding: 12px 24px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.btn-submit:hover {
|
||||
background-color: #45a049;
|
||||
}
|
||||
|
||||
.alert {
|
||||
padding: 15px;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.alert-success {
|
||||
background-color: #dff0d8;
|
||||
color: #3c763d;
|
||||
border: 1px solid #d6e9c6;
|
||||
}
|
||||
|
||||
.alert-error {
|
||||
background-color: #f2dede;
|
||||
color: #a94442;
|
||||
border: 1px solid #ebccd1;
|
||||
}
|
||||
|
||||
.back-button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: #6c757d;
|
||||
text-decoration: none;
|
||||
margin-bottom: 20px;
|
||||
font-weight: 500;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
.back-button:hover {
|
||||
color: #495057;
|
||||
}
|
||||
|
||||
.back-button i {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.image-preview {
|
||||
max-width: 200px;
|
||||
margin-top: 10px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.size-row {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-bottom: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.size-select, .size-quantity {
|
||||
padding: 8px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.size-select {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.size-quantity {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.btn-remove-size {
|
||||
background: #ff4444;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
cursor: pointer;
|
||||
font-size: 18px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.btn-add-size {
|
||||
background: var(--primary-color);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 8px 16px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.btn-add-size:hover {
|
||||
background: var(--primary-dark);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<?php include '../../includes/header.php'; ?>
|
||||
|
||||
<div class="container add-product">
|
||||
<a href="index.php" class="back-button">
|
||||
<i class="fas fa-arrow-left"></i> Back to Products
|
||||
</a>
|
||||
|
||||
<h1>Add New Product</h1>
|
||||
|
||||
<?php if ($success_message): ?>
|
||||
<div class="alert alert-success">
|
||||
<?php echo $success_message; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($error_message): ?>
|
||||
<div class="alert alert-error">
|
||||
<?php echo $error_message; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="POST" enctype="multipart/form-data">
|
||||
<div class="form-group">
|
||||
<label for="name">Product Name *</label>
|
||||
<input type="text" id="name" name="name" value="<?php echo isset($name) ? htmlspecialchars($name) : ''; ?>" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="description">Description *</label>
|
||||
<textarea id="description" name="description" required><?php echo isset($description) ? htmlspecialchars($description) : ''; ?></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="price">Price (₱) *</label>
|
||||
<input type="number" id="price" name="price" min="0" step="0.01" value="<?php echo isset($price) ? $price : ''; ?>" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="stock_quantity">Stock Quantity *</label>
|
||||
<input type="number" id="stock_quantity" name="stock_quantity" min="0" value="<?php echo isset($stock_quantity) ? $stock_quantity : ''; ?>" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="category">Category*</label>
|
||||
<select id="category" name="category" onchange="updateSubcategories()" required>
|
||||
<option value="">Select a category</option>
|
||||
<option value="clothes">Clothes</option>
|
||||
<option value="school_supplies">School Supplies</option>
|
||||
<option value="others">Others</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="subcategoryGroup" style="display: none;">
|
||||
<label for="subcategory">Subcategory*</label>
|
||||
<select id="subcategory" name="subcategory" onchange="handleSubcategoryChange()" required>
|
||||
<option value="">Select a subcategory</option>
|
||||
</select>
|
||||
<input type="text" id="customSubcategory" name="custom_subcategory" style="display: none;" placeholder="Enter subcategory">
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="sizeGroup" style="display: none;">
|
||||
<label>Sizes and Quantities*</label>
|
||||
<div id="sizeContainer">
|
||||
<div class="size-row">
|
||||
<select name="sizes[]" class="size-select">
|
||||
<option value="">Select Size</option>
|
||||
<option value="XS">XS</option>
|
||||
<option value="S">S</option>
|
||||
<option value="M">M</option>
|
||||
<option value="L">L</option>
|
||||
<option value="XL">XL</option>
|
||||
<option value="XXL">XXL</option>
|
||||
</select>
|
||||
<input type="number" name="size_quantities[]" min="0" placeholder="Quantity" class="size-quantity">
|
||||
<button type="button" class="btn-remove-size" onclick="removeSizeRow(this)">×</button>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn-add-size" onclick="addSizeRow()">Add Another Size</button>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="image">Product Image</label>
|
||||
<input type="file" id="image" name="image" accept="image/*" onchange="previewImage(this)">
|
||||
<img id="imagePreview" class="image-preview" src="#" alt="Image Preview">
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn-submit">Add Product</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<?php include '../../includes/footer.php'; ?>
|
||||
|
||||
<script>
|
||||
function previewImage(input) {
|
||||
const preview = document.getElementById('imagePreview');
|
||||
if (input.files && input.files[0]) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
preview.src = e.target.result;
|
||||
preview.style.display = 'block';
|
||||
}
|
||||
reader.readAsDataURL(input.files[0]);
|
||||
} else {
|
||||
preview.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
const subcategories = {
|
||||
clothes: [
|
||||
'T-Shirts',
|
||||
'Pants',
|
||||
'PE Uniform',
|
||||
'University Uniform'
|
||||
],
|
||||
school_supplies: [
|
||||
'Notebooks',
|
||||
'Pens',
|
||||
'Pencils',
|
||||
'Highlighters',
|
||||
'Markers',
|
||||
'Art Supplies',
|
||||
'Paper',
|
||||
'Folders',
|
||||
'Binders',
|
||||
'Staplers'
|
||||
],
|
||||
others: [
|
||||
'University Lace',
|
||||
'Hygiene Products',
|
||||
'Seals',
|
||||
'Calculator',
|
||||
'ID Holders'
|
||||
]
|
||||
};
|
||||
|
||||
function updateSubcategories() {
|
||||
const categorySelect = document.getElementById('category');
|
||||
const subcategorySelect = document.getElementById('subcategory');
|
||||
const subcategoryGroup = document.getElementById('subcategoryGroup');
|
||||
const customSubcategory = document.getElementById('customSubcategory');
|
||||
const sizeGroup = document.getElementById('sizeGroup');
|
||||
const stockQuantityInput = document.getElementById('stock_quantity');
|
||||
const selectedCategory = categorySelect.value;
|
||||
|
||||
// Clear current options
|
||||
subcategorySelect.innerHTML = '<option value="">Select a subcategory</option>';
|
||||
|
||||
if (selectedCategory && subcategories[selectedCategory]) {
|
||||
// Show subcategory group
|
||||
subcategoryGroup.style.display = 'block';
|
||||
subcategorySelect.style.display = 'block';
|
||||
customSubcategory.style.display = 'none';
|
||||
|
||||
// Show/hide size group based on category
|
||||
if (selectedCategory === 'clothes') {
|
||||
sizeGroup.style.display = 'block';
|
||||
stockQuantityInput.style.display = 'none';
|
||||
stockQuantityInput.value = calculateTotalSizeQuantity();
|
||||
} else {
|
||||
sizeGroup.style.display = 'none';
|
||||
stockQuantityInput.style.display = 'block';
|
||||
}
|
||||
|
||||
// Add new options
|
||||
subcategories[selectedCategory].forEach(subcategory => {
|
||||
const option = document.createElement('option');
|
||||
option.value = subcategory.toLowerCase().replace(/\s+/g, '_');
|
||||
option.textContent = subcategory;
|
||||
subcategorySelect.appendChild(option);
|
||||
});
|
||||
|
||||
// Add custom option
|
||||
const customOption = document.createElement('option');
|
||||
customOption.value = 'custom';
|
||||
customOption.textContent = 'Other (Type your own)';
|
||||
subcategorySelect.appendChild(customOption);
|
||||
} else {
|
||||
// Hide subcategory group if no category selected
|
||||
subcategoryGroup.style.display = 'none';
|
||||
sizeGroup.style.display = 'none';
|
||||
stockQuantityInput.style.display = 'block';
|
||||
}
|
||||
}
|
||||
|
||||
function handleSubcategoryChange() {
|
||||
const subcategorySelect = document.getElementById('subcategory');
|
||||
const customSubcategory = document.getElementById('customSubcategory');
|
||||
|
||||
if (subcategorySelect.value === 'custom') {
|
||||
subcategorySelect.style.display = 'none';
|
||||
customSubcategory.style.display = 'block';
|
||||
customSubcategory.focus();
|
||||
customSubcategory.required = true;
|
||||
subcategorySelect.name = 'subcategory_placeholder';
|
||||
customSubcategory.name = 'subcategory';
|
||||
} else {
|
||||
subcategorySelect.style.display = 'block';
|
||||
customSubcategory.style.display = 'none';
|
||||
customSubcategory.required = false;
|
||||
subcategorySelect.name = 'subcategory';
|
||||
customSubcategory.name = 'custom_subcategory';
|
||||
}
|
||||
}
|
||||
|
||||
function addSizeRow() {
|
||||
const container = document.getElementById('sizeContainer');
|
||||
const newRow = document.createElement('div');
|
||||
newRow.className = 'size-row';
|
||||
newRow.innerHTML = `
|
||||
<select name="sizes[]" class="size-select" onchange="updateTotalQuantity()">
|
||||
<option value="">Select Size</option>
|
||||
<option value="XS">XS</option>
|
||||
<option value="S">S</option>
|
||||
<option value="M">M</option>
|
||||
<option value="L">L</option>
|
||||
<option value="XL">XL</option>
|
||||
<option value="XXL">XXL</option>
|
||||
</select>
|
||||
<input type="number" name="size_quantities[]" min="0" placeholder="Quantity" class="size-quantity" onchange="updateTotalQuantity()">
|
||||
<button type="button" class="btn-remove-size" onclick="removeSizeRow(this)">×</button>
|
||||
`;
|
||||
container.appendChild(newRow);
|
||||
}
|
||||
|
||||
function removeSizeRow(button) {
|
||||
button.parentElement.remove();
|
||||
updateTotalQuantity();
|
||||
}
|
||||
|
||||
function calculateTotalSizeQuantity() {
|
||||
const quantities = document.getElementsByName('size_quantities[]');
|
||||
let total = 0;
|
||||
for (let input of quantities) {
|
||||
total += parseInt(input.value) || 0;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
function updateTotalQuantity() {
|
||||
const stockQuantityInput = document.getElementById('stock_quantity');
|
||||
stockQuantityInput.value = calculateTotalSizeQuantity();
|
||||
}
|
||||
|
||||
// Form submission validation
|
||||
document.querySelector('form').addEventListener('submit', function(e) {
|
||||
const category = document.getElementById('category').value;
|
||||
const subcategorySelect = document.getElementById('subcategory');
|
||||
const customSubcategory = document.getElementById('customSubcategory');
|
||||
|
||||
if (subcategorySelect.style.display === 'none' && !customSubcategory.value.trim()) {
|
||||
e.preventDefault();
|
||||
alert('Please enter a subcategory');
|
||||
return;
|
||||
}
|
||||
|
||||
if (category === 'clothes') {
|
||||
const sizeSelects = document.getElementsByName('sizes[]');
|
||||
const sizeQuantities = document.getElementsByName('size_quantities[]');
|
||||
let hasValidSize = false;
|
||||
|
||||
for (let i = 0; i < sizeSelects.length; i++) {
|
||||
if (sizeSelects[i].value && sizeQuantities[i].value > 0) {
|
||||
hasValidSize = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasValidSize) {
|
||||
e.preventDefault();
|
||||
alert('Please add at least one size with quantity');
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize subcategories on page load
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
updateSubcategories();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
require_once '../../includes/auth_functions.php';
|
||||
redirectIfNotLoggedIn();
|
||||
redirectIfNotAdmin();
|
||||
|
||||
require_once '../../config/database.php';
|
||||
|
||||
// Check if product ID is provided
|
||||
if (!isset($_GET['id'])) {
|
||||
header('Location: /unimarket/admin/dashboard.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$product_id = $_GET['id'];
|
||||
|
||||
// Get product details to check ownership and get image path
|
||||
$stmt = $pdo->prepare("SELECT * FROM products WHERE product_id = ? AND owner_id = ?");
|
||||
$stmt->execute([$product_id, $_SESSION['user_id']]);
|
||||
$product = $stmt->fetch();
|
||||
|
||||
if (!$product) {
|
||||
header('Location: /unimarket/admin/dashboard.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
// Delete product image if exists
|
||||
if (!empty($product['image_path'])) {
|
||||
$image_path = '../../assets/images/products/' . $product['image_path'];
|
||||
if (file_exists($image_path)) {
|
||||
unlink($image_path);
|
||||
}
|
||||
}
|
||||
|
||||
// Delete product from database
|
||||
$stmt = $pdo->prepare("DELETE FROM products WHERE product_id = ? AND owner_id = ?");
|
||||
$stmt->execute([$product_id, $_SESSION['user_id']]);
|
||||
|
||||
// Redirect back to dashboard with success message
|
||||
header('Location: /unimarket/admin/dashboard.php?message=Product deleted successfully');
|
||||
exit;
|
||||
} catch (PDOException $e) {
|
||||
// Redirect back to dashboard with error message
|
||||
header('Location: /unimarket/admin/dashboard.php?error=Failed to delete product');
|
||||
exit;
|
||||
}
|
||||
@@ -0,0 +1,457 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../../config/database.php';
|
||||
require_once __DIR__ . '/../../includes/auth_functions.php';
|
||||
|
||||
// Check if user is logged in and is an admin
|
||||
if (!isAdmin()) {
|
||||
header('Location: ../../login.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
$success_message = '';
|
||||
$error_message = '';
|
||||
|
||||
// Check if product ID is provided
|
||||
if (!isset($_GET['id'])) {
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$product_id = $_GET['id'];
|
||||
|
||||
// Get product details
|
||||
$stmt = $pdo->prepare("SELECT * FROM products WHERE product_id = ?");
|
||||
$stmt->execute([$product_id]);
|
||||
$product = $stmt->fetch();
|
||||
|
||||
if (!$product) {
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$name = trim($_POST['name']);
|
||||
$description = trim($_POST['description']);
|
||||
$price = floatval($_POST['price']);
|
||||
$stock = intval($_POST['stock']);
|
||||
$category = trim($_POST['category']);
|
||||
$subcategory = isset($_POST['subcategory']) ? trim($_POST['subcategory']) : '';
|
||||
$size = isset($_POST['size']) ? trim($_POST['size']) : null;
|
||||
|
||||
// Validate input
|
||||
if (empty($name) || empty($description) || $price <= 0 || $stock < 0) {
|
||||
$error_message = "Please fill in all required fields correctly.";
|
||||
} else {
|
||||
// Handle image upload
|
||||
$image = $product['image'];
|
||||
if (isset($_FILES['image']) && $_FILES['image']['error'] === UPLOAD_ERR_OK) {
|
||||
$upload_dir = '../../uploads/products/';
|
||||
if (!file_exists($upload_dir)) {
|
||||
mkdir($upload_dir, 0777, true);
|
||||
}
|
||||
|
||||
$file_extension = strtolower(pathinfo($_FILES['image']['name'], PATHINFO_EXTENSION));
|
||||
$allowed_extensions = ['jpg', 'jpeg', 'png', 'gif'];
|
||||
|
||||
if (in_array($file_extension, $allowed_extensions)) {
|
||||
// Delete old image if exists
|
||||
if (!empty($product['image'])) {
|
||||
$old_image_path = $upload_dir . $product['image'];
|
||||
if (file_exists($old_image_path)) {
|
||||
unlink($old_image_path);
|
||||
}
|
||||
}
|
||||
|
||||
$image = uniqid() . '.' . $file_extension;
|
||||
$upload_path = $upload_dir . $image;
|
||||
|
||||
if (!move_uploaded_file($_FILES['image']['tmp_name'], $upload_path)) {
|
||||
$error_message = "Failed to upload image.";
|
||||
}
|
||||
} else {
|
||||
$error_message = "Invalid image format. Allowed formats: JPG, JPEG, PNG, GIF";
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($error_message)) {
|
||||
try {
|
||||
$stmt = $pdo->prepare("
|
||||
UPDATE products
|
||||
SET name = ?, description = ?, price = ?, stock = ?,
|
||||
category = ?, subcategory = ?, size = ?, image = ?
|
||||
WHERE product_id = ?
|
||||
");
|
||||
|
||||
$stmt->execute([
|
||||
$name,
|
||||
$description,
|
||||
$price,
|
||||
$stock,
|
||||
$category,
|
||||
$subcategory,
|
||||
$size,
|
||||
$image,
|
||||
$product_id
|
||||
]);
|
||||
|
||||
$success_message = "Product updated successfully!";
|
||||
|
||||
// Refresh product data
|
||||
$stmt = $pdo->prepare("SELECT * FROM products WHERE product_id = ?");
|
||||
$stmt->execute([$product_id]);
|
||||
$product = $stmt->fetch();
|
||||
} catch (PDOException $e) {
|
||||
$error_message = "Error updating product: " . $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Edit Product - Admin Dashboard</title>
|
||||
<link rel="stylesheet" href="../../assets/css/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<?php include '../../includes/header.php'; ?>
|
||||
|
||||
<div class="content">
|
||||
<a href="index.php" class="back-button">
|
||||
<i class="fas fa-arrow-left"></i> Back to Products
|
||||
</a>
|
||||
|
||||
<div class="header">
|
||||
<h1>Edit Product</h1>
|
||||
</div>
|
||||
|
||||
<?php if ($success_message): ?>
|
||||
<div class="alert alert-success">
|
||||
<?php echo $success_message; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($error_message): ?>
|
||||
<div class="alert alert-danger">
|
||||
<?php echo $error_message; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="POST" enctype="multipart/form-data" class="form-container">
|
||||
<div class="form-group">
|
||||
<label for="name">Product Name*</label>
|
||||
<input type="text" id="name" name="name" value="<?php echo isset($product['name']) ? htmlspecialchars($product['name']) : ''; ?>" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="description">Description*</label>
|
||||
<textarea id="description" name="description" required><?php echo isset($product['description']) ? htmlspecialchars($product['description']) : ''; ?></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="price">Price (₱)*</label>
|
||||
<input type="number" id="price" name="price" min="0" step="0.01" value="<?php echo isset($product['price']) ? $product['price'] : ''; ?>" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="stock">Stock*</label>
|
||||
<input type="number" id="stock" name="stock" min="0" value="<?php echo isset($product['stock']) ? $product['stock'] : ''; ?>" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="category">Category*</label>
|
||||
<select id="category" name="category" required onchange="updateSubcategories()">
|
||||
<option value="">Select a category</option>
|
||||
<option value="clothes" <?php echo (isset($product['category']) && $product['category'] === 'clothes') ? 'selected' : ''; ?>>Clothes</option>
|
||||
<option value="school_supplies" <?php echo (isset($product['category']) && $product['category'] === 'school_supplies') ? 'selected' : ''; ?>>School Supplies</option>
|
||||
<option value="others" <?php echo (isset($product['category']) && $product['category'] === 'others') ? 'selected' : ''; ?>>Others</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="subcategoryGroup" style="display: none;">
|
||||
<label for="subcategory">Subcategory*</label>
|
||||
<div class="subcategory-container">
|
||||
<select id="subcategory" name="subcategory" onchange="handleSubcategoryChange()">
|
||||
<option value="">Select a subcategory</option>
|
||||
</select>
|
||||
<div class="subcategory-divider">or</div>
|
||||
<input type="text" id="customSubcategory" name="customSubcategory" placeholder="Type your own subcategory" value="<?php echo isset($product['subcategory']) ? htmlspecialchars($product['subcategory']) : ''; ?>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="sizeGroup" style="display: none;">
|
||||
<label for="size">Size*</label>
|
||||
<select id="size" name="size">
|
||||
<option value="">Select a size</option>
|
||||
<option value="XS" <?php echo (isset($product['size']) && $product['size'] === 'XS') ? 'selected' : ''; ?>>Extra Small (XS)</option>
|
||||
<option value="S" <?php echo (isset($product['size']) && $product['size'] === 'S') ? 'selected' : ''; ?>>Small (S)</option>
|
||||
<option value="M" <?php echo (isset($product['size']) && $product['size'] === 'M') ? 'selected' : ''; ?>>Medium (M)</option>
|
||||
<option value="L" <?php echo (isset($product['size']) && $product['size'] === 'L') ? 'selected' : ''; ?>>Large (L)</option>
|
||||
<option value="XL" <?php echo (isset($product['size']) && $product['size'] === 'XL') ? 'selected' : ''; ?>>Extra Large (XL)</option>
|
||||
<option value="XXL" <?php echo (isset($product['size']) && $product['size'] === 'XXL') ? 'selected' : ''; ?>>Double Extra Large (XXL)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="image">Product Image</label>
|
||||
<?php if (isset($product['image']) && $product['image']): ?>
|
||||
<div class="current-image">
|
||||
<img src="../../uploads/products/<?php echo htmlspecialchars($product['image']); ?>" alt="Current product image" style="max-width: 200px;">
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<input type="file" id="image" name="image" accept="image/*" onchange="previewImage(this)">
|
||||
<img id="imagePreview" class="image-preview" src="#" alt="Image preview">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="fas fa-save"></i> Update Product
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const subcategories = {
|
||||
clothes: [
|
||||
'T-Shirts',
|
||||
'Pants',
|
||||
'PE Uniform',
|
||||
'University Uniform'
|
||||
],
|
||||
school_supplies: [
|
||||
'Notebooks',
|
||||
'Pens',
|
||||
'Pencils',
|
||||
'Highlighters',
|
||||
'Markers',
|
||||
'Art Supplies',
|
||||
'Paper',
|
||||
'Folders',
|
||||
'Binders',
|
||||
'Staplers'
|
||||
],
|
||||
others: [
|
||||
'University Lace',
|
||||
'Hygiene Products',
|
||||
'Seals',
|
||||
'Calculator',
|
||||
'ID Holders'
|
||||
]
|
||||
};
|
||||
|
||||
function updateSubcategories() {
|
||||
const categorySelect = document.getElementById('category');
|
||||
const subcategorySelect = document.getElementById('subcategory');
|
||||
const subcategoryGroup = document.getElementById('subcategoryGroup');
|
||||
const sizeGroup = document.getElementById('sizeGroup');
|
||||
const customSubcategory = document.getElementById('customSubcategory');
|
||||
const selectedCategory = categorySelect.value;
|
||||
|
||||
// Clear current options
|
||||
subcategorySelect.innerHTML = '<option value="">Select a subcategory</option>';
|
||||
|
||||
if (selectedCategory && subcategories[selectedCategory]) {
|
||||
// Show subcategory group
|
||||
subcategoryGroup.style.display = 'block';
|
||||
subcategorySelect.style.display = 'block';
|
||||
customSubcategory.style.display = 'none';
|
||||
|
||||
// Show/hide size group based on category
|
||||
if (selectedCategory === 'clothes') {
|
||||
sizeGroup.style.display = 'block';
|
||||
document.getElementById('size').required = true;
|
||||
} else {
|
||||
sizeGroup.style.display = 'none';
|
||||
document.getElementById('size').required = false;
|
||||
}
|
||||
|
||||
// Add new options
|
||||
subcategories[selectedCategory].forEach(subcategory => {
|
||||
const option = document.createElement('option');
|
||||
option.value = subcategory.toLowerCase().replace(/\s+/g, '_');
|
||||
option.textContent = subcategory;
|
||||
// If this is the current subcategory, select it
|
||||
if (option.value === '<?php echo isset($product['subcategory']) ? $product['subcategory'] : ''; ?>') {
|
||||
option.selected = true;
|
||||
}
|
||||
subcategorySelect.appendChild(option);
|
||||
});
|
||||
|
||||
// Add custom option
|
||||
const customOption = document.createElement('option');
|
||||
customOption.value = 'custom';
|
||||
customOption.textContent = 'Other (Type your own)';
|
||||
subcategorySelect.appendChild(customOption);
|
||||
|
||||
// If current subcategory is not in the list, show custom input
|
||||
const currentSubcategory = '<?php echo isset($product['subcategory']) ? $product['subcategory'] : ''; ?>';
|
||||
if (currentSubcategory && !subcategories[selectedCategory].some(sub => sub.toLowerCase().replace(/\s+/g, '_') === currentSubcategory)) {
|
||||
subcategorySelect.value = 'custom';
|
||||
handleSubcategoryChange();
|
||||
}
|
||||
} else {
|
||||
// Hide subcategory group if no category selected
|
||||
subcategoryGroup.style.display = 'none';
|
||||
sizeGroup.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
function handleSubcategoryChange() {
|
||||
const subcategorySelect = document.getElementById('subcategory');
|
||||
const customSubcategory = document.getElementById('customSubcategory');
|
||||
|
||||
if (subcategorySelect.value === 'custom') {
|
||||
subcategorySelect.style.display = 'none';
|
||||
customSubcategory.style.display = 'block';
|
||||
customSubcategory.focus();
|
||||
customSubcategory.required = true;
|
||||
} else {
|
||||
subcategorySelect.style.display = 'block';
|
||||
customSubcategory.style.display = 'none';
|
||||
customSubcategory.required = false;
|
||||
}
|
||||
}
|
||||
|
||||
function previewImage(input) {
|
||||
const preview = document.getElementById('imagePreview');
|
||||
if (input.files && input.files[0]) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
preview.src = e.target.result;
|
||||
preview.style.display = 'block';
|
||||
}
|
||||
reader.readAsDataURL(input.files[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize subcategories on page load
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
updateSubcategories();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.back-button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: #6c757d;
|
||||
text-decoration: none;
|
||||
margin-bottom: 20px;
|
||||
font-weight: 500;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
.back-button:hover {
|
||||
color: #495057;
|
||||
}
|
||||
|
||||
.back-button i {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.form-container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.form-group input[type="text"],
|
||||
.form-group input[type="number"],
|
||||
.form-group textarea,
|
||||
.form-group select {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.form-group textarea {
|
||||
height: 150px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.subcategory-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.subcategory-divider {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.current-image {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.image-preview {
|
||||
max-width: 200px;
|
||||
margin-top: 10px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 16px;
|
||||
border-radius: 4px;
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.btn i {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background-color: #218838;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background-color: #6c757d;
|
||||
color: white;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background-color: #5a6268;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
</style>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,331 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../../config/database.php';
|
||||
require_once __DIR__ . '/../../includes/auth_functions.php';
|
||||
|
||||
// Check if user is logged in and is an admin
|
||||
if (!isAdmin()) {
|
||||
header('Location: ../../login.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
// Start session if not already started
|
||||
if (session_status() === PHP_SESSION_NONE) {
|
||||
session_start();
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Product Management - Admin Dashboard</title>
|
||||
<link rel="stylesheet" href="../../assets/css/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<?php include '../../includes/header.php'; ?>
|
||||
<div class="content">
|
||||
<div class="header">
|
||||
<h1>Manage Products</h1>
|
||||
</div>
|
||||
|
||||
<a href="../dashboard.php" class="back-button">
|
||||
<i class="fas fa-arrow-left"></i> Back to Dashboard
|
||||
</a>
|
||||
|
||||
<?php if (isset($_SESSION['success_message'])): ?>
|
||||
<div class="alert alert-success">
|
||||
<?php
|
||||
echo $_SESSION['success_message'];
|
||||
unset($_SESSION['success_message']);
|
||||
?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (isset($_SESSION['error_message'])): ?>
|
||||
<div class="alert alert-danger">
|
||||
<?php
|
||||
echo $_SESSION['error_message'];
|
||||
unset($_SESSION['error_message']);
|
||||
?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php
|
||||
// Get all products with owner information
|
||||
$stmt = $pdo->query("
|
||||
SELECT p.*, u.username as owner_name
|
||||
FROM products p
|
||||
JOIN users u ON p.owner_id = u.user_id
|
||||
ORDER BY u.username, p.created_at DESC
|
||||
");
|
||||
$products = $stmt->fetchAll();
|
||||
|
||||
// Debug information
|
||||
echo "<div style='background: #f8f9fa; padding: 10px; margin: 10px 0; border-radius: 4px;'>";
|
||||
echo "<h3>Debug Information:</h3>";
|
||||
echo "<p>Total products found: " . count($products) . "</p>";
|
||||
|
||||
// Group products by owner
|
||||
$grouped_products = [];
|
||||
foreach ($products as $product) {
|
||||
$owner_name = $product['owner_name'];
|
||||
if (!isset($grouped_products[$owner_name])) {
|
||||
$grouped_products[$owner_name] = [];
|
||||
}
|
||||
$grouped_products[$owner_name][] = $product;
|
||||
}
|
||||
|
||||
echo "<p>Number of sellers: " . count($grouped_products) . "</p>";
|
||||
echo "<p>Sellers found: " . implode(", ", array_keys($grouped_products)) . "</p>";
|
||||
echo "</div>";
|
||||
?>
|
||||
|
||||
<?php foreach ($grouped_products as $owner_name => $owner_products): ?>
|
||||
<div class="seller-section">
|
||||
<h2 class="seller-name"><?php echo htmlspecialchars($owner_name); ?>'s Products</h2>
|
||||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Image</th>
|
||||
<th>Name</th>
|
||||
<th>Category</th>
|
||||
<th>Subcategory</th>
|
||||
<th>Price</th>
|
||||
<th>Stock</th>
|
||||
<th>Status</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($owner_products as $product): ?>
|
||||
<tr>
|
||||
<td>
|
||||
<?php if (isset($product['image']) && !empty($product['image'])): ?>
|
||||
<img src="../../uploads/products/<?php echo htmlspecialchars($product['image']); ?>" alt="<?php echo htmlspecialchars($product['name']); ?>" class="product-thumbnail">
|
||||
<?php else: ?>
|
||||
<div class="no-image">No Image</div>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?php echo htmlspecialchars($product['name']); ?></td>
|
||||
<td><?php echo htmlspecialchars($product['category']); ?></td>
|
||||
<td><?php echo isset($product['subcategory']) ? htmlspecialchars($product['subcategory']) : ''; ?></td>
|
||||
<td>₱<?php echo number_format($product['price'], 2); ?></td>
|
||||
<td><?php echo isset($product['stock']) ? $product['stock'] : '0'; ?></td>
|
||||
<td>
|
||||
<span class="status-badge <?php echo isset($product['status']) ? $product['status'] : 'pending'; ?>">
|
||||
<?php echo isset($product['status']) ? ucfirst($product['status']) : 'Pending'; ?>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<div class="action-buttons">
|
||||
<a href="edit.php?id=<?php echo $product['product_id']; ?>" class="btn btn-edit">
|
||||
<i class="fas fa-edit"></i> Edit
|
||||
</a>
|
||||
<a href="delete.php?id=<?php echo $product['product_id']; ?>" class="btn btn-delete" onclick="return confirm('Are you sure you want to delete this product?')">
|
||||
<i class="fas fa-trash"></i> Delete
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.seller-section {
|
||||
margin-bottom: 2rem;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.seller-name {
|
||||
color: #333;
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 1rem;
|
||||
padding-bottom: 0.5rem;
|
||||
border-bottom: 2px solid #4CAF50;
|
||||
}
|
||||
|
||||
.table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.table th,
|
||||
.table td {
|
||||
padding: 1rem;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.table th {
|
||||
background-color: #f8f9fa;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.product-thumbnail {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
object-fit: cover;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.no-image {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
background: #f8f9fa;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 4px;
|
||||
font-size: 0.8rem;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 4px;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.status-badge.active {
|
||||
background-color: #e8f5e9;
|
||||
color: #2e7d32;
|
||||
}
|
||||
|
||||
.status-badge.inactive {
|
||||
background-color: #ffebee;
|
||||
color: #c62828;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 16px;
|
||||
border-radius: 4px;
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.btn i {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background-color: #218838;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background-color: #6c757d;
|
||||
color: white;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background-color: #5a6268;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-edit {
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 6px 12px;
|
||||
border-radius: 4px;
|
||||
text-decoration: none;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.btn-edit:hover {
|
||||
background-color: #218838;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.btn-delete {
|
||||
background-color: #dc3545;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 6px 12px;
|
||||
border-radius: 4px;
|
||||
text-decoration: none;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.btn-delete:hover {
|
||||
background-color: #c82333;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.alert {
|
||||
padding: 1rem;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.alert-success {
|
||||
background-color: #e8f5e9;
|
||||
color: #2e7d32;
|
||||
border: 1px solid #c8e6c9;
|
||||
}
|
||||
|
||||
.alert-danger {
|
||||
background-color: #ffebee;
|
||||
color: #c62828;
|
||||
border: 1px solid #ffcdd2;
|
||||
}
|
||||
|
||||
.back-button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: #6c757d;
|
||||
text-decoration: none;
|
||||
margin-bottom: 20px;
|
||||
font-weight: 500;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
.back-button:hover {
|
||||
color: #495057;
|
||||
}
|
||||
|
||||
.back-button i {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
</style>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,204 @@
|
||||
<?php
|
||||
require_once '../includes/auth_functions.php';
|
||||
redirectIfNotLoggedIn();
|
||||
redirectIfNotAdmin();
|
||||
|
||||
require_once '../config/database.php';
|
||||
|
||||
// Get total users by role
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT role, COUNT(*) as count
|
||||
FROM users
|
||||
GROUP BY role
|
||||
");
|
||||
$stmt->execute();
|
||||
$users_by_role = $stmt->fetchAll();
|
||||
|
||||
// Get total products by status
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT status, COUNT(*) as count
|
||||
FROM products
|
||||
GROUP BY status
|
||||
");
|
||||
$stmt->execute();
|
||||
$products_by_status = $stmt->fetchAll();
|
||||
|
||||
// Get total orders by status
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT status, COUNT(*) as count
|
||||
FROM orders
|
||||
GROUP BY status
|
||||
");
|
||||
$stmt->execute();
|
||||
$orders_by_status = $stmt->fetchAll();
|
||||
|
||||
// Get total revenue
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT SUM(total_amount) as total
|
||||
FROM orders
|
||||
WHERE status = 'completed'
|
||||
");
|
||||
$stmt->execute();
|
||||
$total_revenue = $stmt->fetchColumn();
|
||||
|
||||
// Get recent sales (last 7 days)
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT DATE(order_date) as date, SUM(total_amount) as total
|
||||
FROM orders
|
||||
WHERE status = 'completed'
|
||||
AND order_date >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)
|
||||
GROUP BY DATE(order_date)
|
||||
ORDER BY date DESC
|
||||
");
|
||||
$stmt->execute();
|
||||
$recent_sales = $stmt->fetchAll();
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Reports - UniMarket Admin</title>
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/style.css">
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/responsive.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<style>
|
||||
.reports {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: 20px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.stat-card h3 {
|
||||
margin: 0 0 10px 0;
|
||||
color: var(--primary-dark);
|
||||
}
|
||||
|
||||
.stat-card .number {
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.chart-container h2 {
|
||||
margin: 0 0 20px 0;
|
||||
color: var(--primary-dark);
|
||||
}
|
||||
|
||||
.chart-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
|
||||
gap: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<?php include '../includes/header.php'; ?>
|
||||
|
||||
<div class="container reports">
|
||||
<h1>System Reports</h1>
|
||||
|
||||
<div class="stats-grid">
|
||||
<div class="stat-card">
|
||||
<h3>Total Revenue</h3>
|
||||
<div class="number">$<?php echo number_format($total_revenue, 2); ?></div>
|
||||
</div>
|
||||
|
||||
<?php foreach ($users_by_role as $role): ?>
|
||||
<div class="stat-card">
|
||||
<h3>Total <?php echo ucfirst($role['role']); ?>s</h3>
|
||||
<div class="number"><?php echo $role['count']; ?></div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<div class="chart-grid">
|
||||
<div class="chart-container">
|
||||
<h2>Products by Status</h2>
|
||||
<canvas id="productsChart"></canvas>
|
||||
</div>
|
||||
|
||||
<div class="chart-container">
|
||||
<h2>Orders by Status</h2>
|
||||
<canvas id="ordersChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="chart-container">
|
||||
<h2>Recent Sales (Last 7 Days)</h2>
|
||||
<canvas id="salesChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include '../includes/footer.php'; ?>
|
||||
|
||||
<script>
|
||||
// Products by Status Chart
|
||||
new Chart(document.getElementById('productsChart'), {
|
||||
type: 'pie',
|
||||
data: {
|
||||
labels: <?php echo json_encode(array_column($products_by_status, 'status')); ?>,
|
||||
datasets: [{
|
||||
data: <?php echo json_encode(array_column($products_by_status, 'count')); ?>,
|
||||
backgroundColor: ['#4CAF50', '#FFC107', '#F44336']
|
||||
}]
|
||||
}
|
||||
});
|
||||
|
||||
// Orders by Status Chart
|
||||
new Chart(document.getElementById('ordersChart'), {
|
||||
type: 'pie',
|
||||
data: {
|
||||
labels: <?php echo json_encode(array_column($orders_by_status, 'status')); ?>,
|
||||
datasets: [{
|
||||
data: <?php echo json_encode(array_column($orders_by_status, 'count')); ?>,
|
||||
backgroundColor: ['#2196F3', '#FFC107', '#4CAF50', '#F44336']
|
||||
}]
|
||||
}
|
||||
});
|
||||
|
||||
// Recent Sales Chart
|
||||
new Chart(document.getElementById('salesChart'), {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: <?php echo json_encode(array_column($recent_sales, 'date')); ?>,
|
||||
datasets: [{
|
||||
label: 'Daily Sales',
|
||||
data: <?php echo json_encode(array_column($recent_sales, 'total')); ?>,
|
||||
borderColor: '#2196F3',
|
||||
tension: 0.1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,206 @@
|
||||
<?php
|
||||
require_once '../../includes/auth_functions.php';
|
||||
redirectIfNotLoggedIn();
|
||||
redirectIfNotAdmin();
|
||||
|
||||
require_once '../../config/database.php';
|
||||
|
||||
// Check if user ID is provided
|
||||
if (!isset($_GET['id'])) {
|
||||
header("Location: /unimarket/admin/users/manage.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
$user_id = (int)$_GET['id'];
|
||||
|
||||
// Get user details
|
||||
$stmt = $pdo->prepare("SELECT * FROM users WHERE user_id = ?");
|
||||
$stmt->execute([$user_id]);
|
||||
$user = $stmt->fetch();
|
||||
|
||||
if (!$user) {
|
||||
header("Location: /unimarket/admin/users/manage.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
$error_message = '';
|
||||
$success_message = '';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$username = trim($_POST['username']);
|
||||
$email = trim($_POST['email']);
|
||||
$role = $_POST['role'];
|
||||
|
||||
// Validate inputs
|
||||
if (empty($username) || empty($email)) {
|
||||
$error_message = 'Please fill in all required fields.';
|
||||
} else {
|
||||
try {
|
||||
// Check if username or email already exists (excluding current user)
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT COUNT(*) FROM users
|
||||
WHERE (username = ? OR email = ?)
|
||||
AND user_id != ?
|
||||
");
|
||||
$stmt->execute([$username, $email, $user_id]);
|
||||
|
||||
if ($stmt->fetchColumn() > 0) {
|
||||
$error_message = 'Username or email already exists.';
|
||||
} else {
|
||||
// Update user
|
||||
$stmt = $pdo->prepare("
|
||||
UPDATE users
|
||||
SET username = ?, email = ?, role = ?
|
||||
WHERE user_id = ?
|
||||
");
|
||||
$stmt->execute([$username, $email, $role, $user_id]);
|
||||
|
||||
if ($stmt->rowCount() > 0) {
|
||||
$success_message = 'User updated successfully!';
|
||||
// Refresh user data
|
||||
$stmt = $pdo->prepare("SELECT * FROM users WHERE user_id = ?");
|
||||
$stmt->execute([$user_id]);
|
||||
$user = $stmt->fetch();
|
||||
} else {
|
||||
$error_message = 'No changes were made.';
|
||||
}
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$error_message = 'Failed to update user. Please try again.';
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Edit User - UniMarket</title>
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/style.css">
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/responsive.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
|
||||
<style>
|
||||
.edit-user-container {
|
||||
max-width: 600px;
|
||||
margin: 30px auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.form-group input,
|
||||
.form-group select {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.btn-submit {
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
padding: 10px 20px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.btn-submit:hover {
|
||||
background-color: #218838;
|
||||
}
|
||||
|
||||
.alert {
|
||||
padding: 15px;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.alert-success {
|
||||
background-color: #dff0d8;
|
||||
color: #3c763d;
|
||||
border: 1px solid #d6e9c6;
|
||||
}
|
||||
|
||||
.alert-error {
|
||||
background-color: #f2dede;
|
||||
color: #a94442;
|
||||
border: 1px solid #ebccd1;
|
||||
}
|
||||
|
||||
.back-button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: #6c757d;
|
||||
text-decoration: none;
|
||||
margin-bottom: 20px;
|
||||
font-weight: 500;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
.back-button:hover {
|
||||
color: #495057;
|
||||
}
|
||||
|
||||
.back-button i {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<?php include '../../includes/header.php'; ?>
|
||||
|
||||
<div class="container edit-user-container">
|
||||
<a href="/unimarket/admin/users/manage.php" class="back-button">
|
||||
<i class="fas fa-arrow-left"></i> Back to Users
|
||||
</a>
|
||||
|
||||
<h1>Edit User</h1>
|
||||
|
||||
<?php if ($success_message): ?>
|
||||
<div class="alert alert-success"><?php echo $success_message; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($error_message): ?>
|
||||
<div class="alert alert-error"><?php echo $error_message; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="POST" class="card">
|
||||
<div class="form-group">
|
||||
<label for="username">Username</label>
|
||||
<input type="text" id="username" name="username" value="<?php echo htmlspecialchars($user['username']); ?>" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="email">Email</label>
|
||||
<input type="email" id="email" name="email" value="<?php echo htmlspecialchars($user['email']); ?>" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="role">Role</label>
|
||||
<select id="role" name="role" required>
|
||||
<option value="customer" <?php echo $user['role'] === 'customer' ? 'selected' : ''; ?>>Customer</option>
|
||||
<option value="owner" <?php echo $user['role'] === 'owner' ? 'selected' : ''; ?>>Owner</option>
|
||||
<option value="admin" <?php echo $user['role'] === 'admin' ? 'selected' : ''; ?>>Admin</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn-submit">Update User</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<?php include '../../includes/footer.php'; ?>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,261 @@
|
||||
<?php
|
||||
require_once '../../includes/auth_functions.php';
|
||||
redirectIfNotLoggedIn();
|
||||
redirectIfNotAdmin();
|
||||
|
||||
require_once '../../config/database.php';
|
||||
|
||||
// Handle user role updates
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_role'])) {
|
||||
$user_id = $_POST['user_id'];
|
||||
$new_role = $_POST['role'];
|
||||
|
||||
// Prevent changing own role
|
||||
if ($user_id != $_SESSION['user_id']) {
|
||||
$stmt = $pdo->prepare("UPDATE users SET role = ? WHERE user_id = ?");
|
||||
$stmt->execute([$new_role, $user_id]);
|
||||
flashMessage('success', 'User role updated successfully.');
|
||||
} else {
|
||||
flashMessage('error', 'You cannot change your own role.');
|
||||
}
|
||||
|
||||
header("Location: manage.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
// Get all users
|
||||
$stmt = $pdo->prepare("SELECT * FROM users ORDER BY user_id DESC");
|
||||
$stmt->execute();
|
||||
$users = $stmt->fetchAll();
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Manage Users - UniMarket Admin</title>
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/style.css">
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/responsive.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
|
||||
<style>
|
||||
.manage-users {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.users-table {
|
||||
width: 100%;
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.users-table table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.users-table th,
|
||||
.users-table td {
|
||||
padding: 15px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.users-table th {
|
||||
background-color: #f5f5f5;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.users-table tr:hover {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
.role-select {
|
||||
padding: 5px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.btn-small {
|
||||
padding: 5px 10px;
|
||||
border-radius: 4px;
|
||||
text-decoration: none;
|
||||
font-size: 0.9em;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.btn-update {
|
||||
background: var(--primary-color);
|
||||
color: white;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.btn-update:hover {
|
||||
background: var(--primary-dark);
|
||||
}
|
||||
|
||||
.btn-edit {
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btn-edit:hover {
|
||||
background-color: #218838;
|
||||
}
|
||||
|
||||
.btn-delete {
|
||||
background-color: #dc3545;
|
||||
color: white;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btn-delete:hover {
|
||||
background-color: #c82333;
|
||||
}
|
||||
|
||||
.alert {
|
||||
padding: 15px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.alert-success {
|
||||
background-color: #d4edda;
|
||||
color: #155724;
|
||||
border: 1px solid #c3e6cb;
|
||||
}
|
||||
|
||||
.alert-error {
|
||||
background-color: #f8d7da;
|
||||
color: #721c24;
|
||||
border: 1px solid #f5c6cb;
|
||||
}
|
||||
|
||||
.role-badge {
|
||||
display: inline-block;
|
||||
padding: 5px 10px;
|
||||
border-radius: 15px;
|
||||
font-size: 0.9em;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.role-customer {
|
||||
background-color: #e2e3e5;
|
||||
color: #383d41;
|
||||
}
|
||||
|
||||
.role-owner {
|
||||
background-color: #cce5ff;
|
||||
color: #004085;
|
||||
}
|
||||
|
||||
.role-admin {
|
||||
background-color: #d4edda;
|
||||
color: #155724;
|
||||
}
|
||||
|
||||
.btn-edit.disabled {
|
||||
background-color: #6c757d;
|
||||
cursor: not-allowed;
|
||||
opacity: 0.65;
|
||||
}
|
||||
|
||||
.btn-edit.disabled:hover {
|
||||
background-color: #6c757d;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.back-button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: #6c757d;
|
||||
text-decoration: none;
|
||||
margin-bottom: 20px;
|
||||
font-weight: 500;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
.back-button:hover {
|
||||
color: #495057;
|
||||
}
|
||||
|
||||
.back-button i {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<?php include '../../includes/header.php'; ?>
|
||||
|
||||
<div class="container manage-users">
|
||||
<a href="/unimarket/admin/dashboard.php" class="back-button">
|
||||
<i class="fas fa-arrow-left"></i> Back to Dashboard
|
||||
</a>
|
||||
|
||||
<h1>Manage Users</h1>
|
||||
|
||||
<?php if ($message = getFlashMessage('success')): ?>
|
||||
<div class="alert alert-success"><?php echo $message; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($message = getFlashMessage('error')): ?>
|
||||
<div class="alert alert-error"><?php echo $message; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="users-table">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Username</th>
|
||||
<th>Email</th>
|
||||
<th>Role</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($users as $user): ?>
|
||||
<tr>
|
||||
<td><?php echo $user['user_id']; ?></td>
|
||||
<td><?php echo htmlspecialchars($user['username']); ?></td>
|
||||
<td><?php echo htmlspecialchars($user['email']); ?></td>
|
||||
<td>
|
||||
<?php
|
||||
$role_class = 'role-' . $user['role'];
|
||||
$role_display = ucfirst($user['role']);
|
||||
?>
|
||||
<span class="role-badge <?php echo $role_class; ?>">
|
||||
<?php echo $role_display; ?>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ($user['role'] === 'admin'): ?>
|
||||
<span class="btn-small btn-edit disabled">
|
||||
<i class="fas fa-edit"></i> Edit
|
||||
</span>
|
||||
<?php else: ?>
|
||||
<a href="edit.php?id=<?php echo $user['user_id']; ?>" class="btn-small btn-edit">
|
||||
<i class="fas fa-edit"></i> Edit
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<?php if ($user['user_id'] != $_SESSION['user_id']): ?>
|
||||
<a href="delete.php?id=<?php echo $user['user_id']; ?>" class="btn-small btn-delete" onclick="return confirm('Are you sure you want to delete this user?')">
|
||||
<i class="fas fa-trash"></i> Delete
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include '../../includes/footer.php'; ?>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
require_once '../includes/auth_functions.php';
|
||||
require_once '../config/database.php';
|
||||
|
||||
// Enable error reporting for debugging
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', 1);
|
||||
|
||||
// Check if user is logged in and is a customer
|
||||
if (!isLoggedIn() || !isCustomer()) {
|
||||
echo json_encode(['success' => false, 'message' => 'Please log in to add items to cart']);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Check if required parameters are provided
|
||||
if (!isset($_POST['product_id']) || !isset($_POST['quantity'])) {
|
||||
echo json_encode(['success' => false, 'message' => 'Missing required parameters']);
|
||||
exit();
|
||||
}
|
||||
|
||||
$product_id = (int)$_POST['product_id'];
|
||||
$quantity = (int)$_POST['quantity'];
|
||||
$size = isset($_POST['size']) ? $_POST['size'] : null;
|
||||
|
||||
// Validate quantity
|
||||
if ($quantity < 1) {
|
||||
echo json_encode(['success' => false, 'message' => 'Quantity must be at least 1']);
|
||||
exit();
|
||||
}
|
||||
|
||||
try {
|
||||
// Check product availability
|
||||
$stmt = $pdo->prepare("SELECT stock_quantity, category, size_data FROM products WHERE product_id = ?");
|
||||
$stmt->execute([$product_id]);
|
||||
$product = $stmt->fetch();
|
||||
|
||||
if (!$product) {
|
||||
echo json_encode(['success' => false, 'message' => 'Product not found']);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Check if size is required for clothing items
|
||||
if ($product['category'] === 'clothes' && empty($size)) {
|
||||
echo json_encode(['success' => false, 'message' => 'Please select a size']);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Validate size availability for clothing items
|
||||
if ($product['category'] === 'clothes' && $product['size_data']) {
|
||||
$size_data = json_decode($product['size_data'], true);
|
||||
if (!isset($size_data[$size]) || $size_data[$size] < $quantity) {
|
||||
echo json_encode(['success' => false, 'message' => "Selected size is not available in the requested quantity"]);
|
||||
exit();
|
||||
}
|
||||
} else if ($quantity > $product['stock_quantity']) {
|
||||
echo json_encode(['success' => false, 'message' => "Only {$product['stock_quantity']} available in stock"]);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Get or create cart for user
|
||||
$stmt = $pdo->prepare("SELECT cart_id FROM cart WHERE user_id = ?");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
$cart = $stmt->fetch();
|
||||
|
||||
if (!$cart) {
|
||||
$stmt = $pdo->prepare("INSERT INTO cart (user_id) VALUES (?)");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
$cart_id = $pdo->lastInsertId();
|
||||
} else {
|
||||
$cart_id = $cart['cart_id'];
|
||||
}
|
||||
|
||||
// Check if product already in cart
|
||||
$stmt = $pdo->prepare("SELECT * FROM cart_items WHERE cart_id = ? AND product_id = ?");
|
||||
$stmt->execute([$cart_id, $product_id]);
|
||||
$existing_item = $stmt->fetch();
|
||||
|
||||
if ($existing_item) {
|
||||
// Update quantity if already in cart
|
||||
$new_quantity = $existing_item['quantity'] + $quantity;
|
||||
if ($product['category'] === 'clothes' && $product['size_data']) {
|
||||
$size_data = json_decode($product['size_data'], true);
|
||||
if ($new_quantity > $size_data[$size]) {
|
||||
echo json_encode(['success' => false, 'message' => "Cannot add more than available stock for selected size"]);
|
||||
exit();
|
||||
}
|
||||
} else if ($new_quantity > $product['stock_quantity']) {
|
||||
echo json_encode(['success' => false, 'message' => "Cannot add more than available stock"]);
|
||||
exit();
|
||||
}
|
||||
$stmt = $pdo->prepare("UPDATE cart_items SET quantity = ? WHERE cart_item_id = ?");
|
||||
$stmt->execute([$new_quantity, $existing_item['cart_item_id']]);
|
||||
} else {
|
||||
// Add new item to cart
|
||||
try {
|
||||
$stmt = $pdo->prepare("INSERT INTO cart_items (cart_id, product_id, quantity, size) VALUES (?, ?, ?, ?)");
|
||||
$stmt->execute([$cart_id, $product_id, $quantity, $size]);
|
||||
} catch (PDOException $e) {
|
||||
// If the size column doesn't exist, try without it
|
||||
if (strpos($e->getMessage(), 'Unknown column') !== false) {
|
||||
$stmt = $pdo->prepare("INSERT INTO cart_items (cart_id, product_id, quantity) VALUES (?, ?, ?)");
|
||||
$stmt->execute([$cart_id, $product_id, $quantity]);
|
||||
} else {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get updated cart count
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT SUM(quantity) as count
|
||||
FROM cart_items ci
|
||||
JOIN cart c ON ci.cart_id = c.cart_id
|
||||
WHERE c.user_id = ?
|
||||
");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
$cart_count = $stmt->fetch()['count'] ?? 0;
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'message' => 'Product added to cart!',
|
||||
'cart_count' => $cart_count
|
||||
]);
|
||||
|
||||
} catch (PDOException $e) {
|
||||
error_log("Add to cart error: " . $e->getMessage());
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'Failed to add product to cart. Please try again.',
|
||||
'debug' => $e->getMessage()
|
||||
]);
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
require_once '../includes/auth_functions.php';
|
||||
require_once '../config/database.php';
|
||||
|
||||
// Enable error reporting for debugging
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', 1);
|
||||
|
||||
// Set proper content type
|
||||
header('Content-Type: application/json');
|
||||
|
||||
// Check if user is logged in and is a customer
|
||||
if (!isLoggedIn() || !isCustomer()) {
|
||||
echo json_encode(['success' => false, 'message' => 'Please log in to remove items from cart']);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Check if required parameters are provided
|
||||
if (!isset($_POST['cart_item_id'])) {
|
||||
echo json_encode(['success' => false, 'message' => 'Missing required parameters']);
|
||||
exit();
|
||||
}
|
||||
|
||||
$cart_item_id = (int)$_POST['cart_item_id'];
|
||||
|
||||
try {
|
||||
// Verify the cart item belongs to the user
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT ci.*
|
||||
FROM cart_items ci
|
||||
JOIN cart c ON ci.cart_id = c.cart_id
|
||||
WHERE ci.cart_item_id = ? AND c.user_id = ?
|
||||
");
|
||||
$stmt->execute([$cart_item_id, $_SESSION['user_id']]);
|
||||
$cart_item = $stmt->fetch();
|
||||
|
||||
if (!$cart_item) {
|
||||
echo json_encode(['success' => false, 'message' => 'Cart item not found']);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Delete the cart item
|
||||
$stmt = $pdo->prepare("DELETE FROM cart_items WHERE cart_item_id = ?");
|
||||
$result = $stmt->execute([$cart_item_id]);
|
||||
|
||||
if (!$result) {
|
||||
throw new PDOException("Failed to remove cart item");
|
||||
}
|
||||
|
||||
// Get updated cart total
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT SUM(ci.quantity * p.price) as total
|
||||
FROM cart_items ci
|
||||
JOIN products p ON ci.product_id = p.product_id
|
||||
JOIN cart c ON ci.cart_id = c.cart_id
|
||||
WHERE c.user_id = ?
|
||||
");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
$cart_total = $stmt->fetch()['total'] ?? 0;
|
||||
|
||||
// Get updated cart count
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT SUM(quantity) as count
|
||||
FROM cart_items ci
|
||||
JOIN cart c ON ci.cart_id = c.cart_id
|
||||
WHERE c.user_id = ?
|
||||
");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
$cart_count = $stmt->fetch()['count'] ?? 0;
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'message' => 'Item removed from cart',
|
||||
'total' => $cart_total,
|
||||
'cart_count' => $cart_count
|
||||
]);
|
||||
|
||||
} catch (PDOException $e) {
|
||||
error_log("Database error: " . $e->getMessage());
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'Failed to remove item from cart. Please try again.'
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
error_log("General error: " . $e->getMessage());
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'An unexpected error occurred. Please try again.'
|
||||
]);
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
require_once '../includes/auth_functions.php';
|
||||
require_once '../config/database.php';
|
||||
|
||||
// Enable error reporting for debugging
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', 1);
|
||||
|
||||
// Set proper content type
|
||||
header('Content-Type: application/json');
|
||||
|
||||
// Check if user is logged in and is a customer
|
||||
if (!isLoggedIn() || !isCustomer()) {
|
||||
echo json_encode(['success' => false, 'message' => 'Please log in to update cart']);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Check if required parameters are provided
|
||||
if (!isset($_POST['cart_item_id']) || !isset($_POST['quantity'])) {
|
||||
echo json_encode(['success' => false, 'message' => 'Missing required parameters']);
|
||||
exit();
|
||||
}
|
||||
|
||||
$cart_item_id = (int)$_POST['cart_item_id'];
|
||||
$quantity = (int)$_POST['quantity'];
|
||||
|
||||
// Log the received data
|
||||
error_log("Received update request - Cart Item ID: $cart_item_id, Quantity: $quantity");
|
||||
|
||||
// Validate quantity
|
||||
if ($quantity < 1) {
|
||||
echo json_encode(['success' => false, 'message' => 'Quantity must be at least 1']);
|
||||
exit();
|
||||
}
|
||||
|
||||
try {
|
||||
// Get current cart item and product details
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT ci.*, p.stock_quantity, p.price, p.product_id
|
||||
FROM cart_items ci
|
||||
JOIN products p ON ci.product_id = p.product_id
|
||||
JOIN cart c ON ci.cart_id = c.cart_id
|
||||
WHERE ci.cart_item_id = ? AND c.user_id = ?
|
||||
");
|
||||
$stmt->execute([$cart_item_id, $_SESSION['user_id']]);
|
||||
$cart_item = $stmt->fetch();
|
||||
|
||||
if (!$cart_item) {
|
||||
echo json_encode(['success' => false, 'message' => 'Cart item not found']);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Log the cart item details
|
||||
error_log("Cart item found: " . print_r($cart_item, true));
|
||||
|
||||
// Get current stock quantity
|
||||
$stmt = $pdo->prepare("SELECT stock_quantity FROM products WHERE product_id = ?");
|
||||
$stmt->execute([$cart_item['product_id']]);
|
||||
$current_stock = $stmt->fetch()['stock_quantity'];
|
||||
|
||||
// Check stock availability
|
||||
if ($quantity > $current_stock) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => "Only {$current_stock} available in stock",
|
||||
'previous_quantity' => $cart_item['quantity'],
|
||||
'current_stock' => $current_stock
|
||||
]);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Update quantity
|
||||
$stmt = $pdo->prepare("UPDATE cart_items SET quantity = ? WHERE cart_item_id = ?");
|
||||
$result = $stmt->execute([$quantity, $cart_item_id]);
|
||||
|
||||
if (!$result) {
|
||||
throw new PDOException("Failed to update cart item");
|
||||
}
|
||||
|
||||
// Get updated cart total
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT SUM(ci.quantity * p.price) as total
|
||||
FROM cart_items ci
|
||||
JOIN products p ON ci.product_id = p.product_id
|
||||
JOIN cart c ON ci.cart_id = c.cart_id
|
||||
WHERE c.user_id = ?
|
||||
");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
$cart_total = $stmt->fetch()['total'] ?? 0;
|
||||
|
||||
// Log success
|
||||
error_log("Cart updated successfully - New quantity: $quantity, Total: $cart_total");
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'message' => 'Quantity updated successfully',
|
||||
'cart_total' => $cart_total,
|
||||
'current_stock' => $current_stock
|
||||
]);
|
||||
|
||||
} catch (PDOException $e) {
|
||||
error_log("Database error: " . $e->getMessage());
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'Failed to update quantity. Please try again.',
|
||||
'previous_quantity' => $cart_item['quantity'] ?? 1
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
error_log("General error: " . $e->getMessage());
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'An unexpected error occurred. Please try again.',
|
||||
'previous_quantity' => $cart_item['quantity'] ?? 1
|
||||
]);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
@media (max-width: 768px) {
|
||||
.header-content {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
nav ul {
|
||||
margin-top: 15px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
nav ul li {
|
||||
margin: 0 10px;
|
||||
}
|
||||
|
||||
.dashboard-container {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.product-grid {
|
||||
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.container {
|
||||
width: 95%;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.product-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 8px 15px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.table {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,466 @@
|
||||
:root {
|
||||
--primary-color: #2e7d32;
|
||||
--primary-light: #60ad5e;
|
||||
--primary-dark: #005005;
|
||||
--secondary-color: #f5f5f5;
|
||||
--text-color: #333;
|
||||
--light-text: #fff;
|
||||
--error-color: #d32f2f;
|
||||
--success-color: #388e3c;
|
||||
--warning-color: #f57c00;
|
||||
--light-bg: #f5f5f5;
|
||||
--white: #ffffff;
|
||||
--border-color: #e0e0e0;
|
||||
--shadow-color: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #f9f9f9;
|
||||
color: var(--text-color);
|
||||
line-height: 1.6;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(135deg, #f5f7fa 0%, #e4e8eb 100%);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
body::before {
|
||||
content: '';
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background:
|
||||
radial-gradient(circle at 20% 20%, rgba(46, 125, 50, 0.05) 0%, transparent 50%),
|
||||
radial-gradient(circle at 80% 80%, rgba(76, 175, 80, 0.05) 0%, transparent 50%),
|
||||
radial-gradient(circle at 50% 50%, rgba(27, 94, 32, 0.03) 0%, transparent 50%);
|
||||
pointer-events: none;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 90%;
|
||||
max-width: 1200px;
|
||||
margin: 20px auto;
|
||||
padding: 30px;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
border-radius: 15px;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
|
||||
backdrop-filter: blur(10px);
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.container:hover {
|
||||
transform: none;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
header {
|
||||
background-color: var(--primary-color);
|
||||
color: var(--light-text);
|
||||
padding: 15px 0;
|
||||
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.header-content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.logo {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
nav ul {
|
||||
display: flex;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
nav ul li {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
nav ul li a {
|
||||
color: var(--light-text);
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
nav ul li a:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
padding: 12px 24px;
|
||||
background: var(--primary-color);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
font-size: 1rem;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s ease;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.btn::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(45deg, transparent, rgba(255, 255, 255, 0.1), transparent);
|
||||
transform: translateX(-100%);
|
||||
transition: transform 0.6s ease;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background: var(--primary-dark);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(46, 125, 50, 0.2);
|
||||
}
|
||||
|
||||
.btn:hover::after {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background-color: #757575;
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background-color: #616161;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
|
||||
padding: 25px;
|
||||
margin-bottom: 25px;
|
||||
backdrop-filter: blur(5px);
|
||||
-webkit-backdrop-filter: blur(5px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
transform: translateY(-3px);
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.form-group:hover {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="email"],
|
||||
input[type="password"],
|
||||
input[type="number"],
|
||||
input[type="tel"],
|
||||
select,
|
||||
textarea {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
border-radius: 8px;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
transition: all 0.3s ease;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
input[type="text"]:focus,
|
||||
input[type="email"]:focus,
|
||||
input[type="password"]:focus,
|
||||
input[type="number"]:focus,
|
||||
input[type="tel"]:focus,
|
||||
select:focus,
|
||||
textarea:focus {
|
||||
border-color: var(--primary-color);
|
||||
box-shadow: 0 0 0 3px rgba(46, 125, 50, 0.2);
|
||||
outline: none;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.alert {
|
||||
padding: 15px 20px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 20px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
backdrop-filter: blur(5px);
|
||||
-webkit-backdrop-filter: blur(5px);
|
||||
}
|
||||
|
||||
.alert::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(45deg, transparent, rgba(255, 255, 255, 0.1), transparent);
|
||||
transform: translateX(-100%);
|
||||
animation: shimmer 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes shimmer {
|
||||
100% {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
}
|
||||
|
||||
.alert-success {
|
||||
background: rgba(56, 142, 60, 0.95);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.alert-error {
|
||||
background: rgba(211, 47, 47, 0.95);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.product-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||
gap: 25px;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.product-card {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
|
||||
transition: all 0.3s ease;
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.product-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.product-image {
|
||||
height: 200px;
|
||||
background-color: #f5f5f5;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.product-image img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.product-info {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.product-title {
|
||||
font-size: 18px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.product-price {
|
||||
font-weight: bold;
|
||||
color: var(--primary-color);
|
||||
font-size: 20px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
/* Dashboard styles */
|
||||
.dashboard-container {
|
||||
display: grid;
|
||||
grid-template-columns: 250px 1fr;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.sidebar ul {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.sidebar ul li {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.sidebar ul li a {
|
||||
color: var(--text-color);
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
padding: 8px 0;
|
||||
transition: color 0.3s;
|
||||
}
|
||||
|
||||
.sidebar ul li a:hover {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.sidebar ul li a.active {
|
||||
color: var(--primary-color);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
/* Table styles */
|
||||
.table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.table th,
|
||||
.table td {
|
||||
padding: 12px 15px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.table th {
|
||||
background-color: #f5f5f5;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.table tr:hover {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
/* Size grid styles */
|
||||
.size-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
|
||||
gap: 12px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.size-item {
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
border-radius: 8px;
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.size-item.in-stock {
|
||||
border-color: var(--success-color);
|
||||
background: rgba(56, 142, 60, 0.1);
|
||||
}
|
||||
|
||||
.size-item.out-of-stock {
|
||||
border-color: var(--error-color);
|
||||
background: rgba(211, 47, 47, 0.1);
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.size-item:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* Custom scrollbar */
|
||||
::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: var(--primary-color);
|
||||
border-radius: 5px;
|
||||
border: 2px solid rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--primary-dark);
|
||||
}
|
||||
|
||||
/* Responsive styles are in responsive.css */
|
||||
|
||||
/* Toast Notification Styles */
|
||||
.toast-container {
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.toast {
|
||||
background: #333;
|
||||
color: white;
|
||||
padding: 12px 24px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 10px;
|
||||
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
transform: translateX(120%);
|
||||
transition: transform 0.3s ease-in-out;
|
||||
min-width: 250px;
|
||||
}
|
||||
|
||||
.toast.show {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.toast.success {
|
||||
background: #28a745;
|
||||
}
|
||||
|
||||
.toast.error {
|
||||
background: #dc3545;
|
||||
}
|
||||
|
||||
.toast i {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
After Width: | Height: | Size: 2.9 MiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 2.6 MiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 169 KiB |
|
After Width: | Height: | Size: 1.9 MiB |
@@ -0,0 +1,145 @@
|
||||
// Helper function to make AJAX requests
|
||||
function makeRequest(url, method, data) {
|
||||
console.log('Making request to:', url, 'with data:', data);
|
||||
return fetch(url, {
|
||||
method: method,
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
body: new URLSearchParams(data)
|
||||
})
|
||||
.then(response => {
|
||||
console.log('Response status:', response.status);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
console.log('Response data:', data);
|
||||
return data;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Request error:', error);
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
|
||||
// Helper function to show toast messages
|
||||
function showToast(message, type = 'success') {
|
||||
const toast = document.createElement('div');
|
||||
toast.className = `toast toast-${type}`;
|
||||
toast.textContent = message;
|
||||
document.body.appendChild(toast);
|
||||
|
||||
setTimeout(() => {
|
||||
toast.classList.add('show');
|
||||
}, 100);
|
||||
|
||||
setTimeout(() => {
|
||||
toast.classList.remove('show');
|
||||
setTimeout(() => {
|
||||
document.body.removeChild(toast);
|
||||
}, 300);
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
// Initialize add to cart functionality
|
||||
function initAddToCart() {
|
||||
document.querySelectorAll('.add-to-cart-form').forEach(form => {
|
||||
form.addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const productId = this.querySelector('input[name="product_id"]').value;
|
||||
const quantity = this.querySelector('input[name="quantity"]').value;
|
||||
|
||||
makeRequest('/unimarket/ajax/add_to_cart.php', 'POST', {
|
||||
product_id: productId,
|
||||
quantity: quantity
|
||||
})
|
||||
.then(response => {
|
||||
if (response.success) {
|
||||
// Update cart count in header
|
||||
const cartCount = document.querySelector('.cart-count');
|
||||
if (cartCount) {
|
||||
cartCount.textContent = response.cart_count;
|
||||
cartCount.classList.add('pulse');
|
||||
setTimeout(() => {
|
||||
cartCount.classList.remove('pulse');
|
||||
}, 500);
|
||||
}
|
||||
|
||||
// Show success message
|
||||
showToast(response.message);
|
||||
} else {
|
||||
showToast(response.message, 'error');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
showToast('An error occurred. Please try again.', 'error');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize quantity controls
|
||||
function initQuantityControls() {
|
||||
document.querySelectorAll('.quantity-control').forEach(control => {
|
||||
const input = control.querySelector('.quantity-input');
|
||||
const increment = control.querySelector('.quantity-increment');
|
||||
const decrement = control.querySelector('.quantity-decrement');
|
||||
|
||||
// Remove any existing event listeners
|
||||
const newIncrement = increment.cloneNode(true);
|
||||
const newDecrement = decrement.cloneNode(true);
|
||||
increment.parentNode.replaceChild(newIncrement, increment);
|
||||
decrement.parentNode.replaceChild(newDecrement, decrement);
|
||||
|
||||
// Add new event listeners
|
||||
newIncrement.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
const max = parseInt(input.getAttribute('max'));
|
||||
const current = parseInt(input.value) || 1;
|
||||
|
||||
if (current < max) {
|
||||
input.value = current + 1;
|
||||
} else {
|
||||
showToast(`Only ${max} available in stock`, 'error');
|
||||
}
|
||||
});
|
||||
|
||||
newDecrement.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
const current = parseInt(input.value) || 1;
|
||||
if (current > 1) {
|
||||
input.value = current - 1;
|
||||
}
|
||||
});
|
||||
|
||||
// Handle direct input
|
||||
input.addEventListener('input', function() {
|
||||
const max = parseInt(this.getAttribute('max'));
|
||||
let value = parseInt(this.value);
|
||||
|
||||
if (isNaN(value) || value < 1) {
|
||||
value = 1;
|
||||
} else if (value > max) {
|
||||
value = max;
|
||||
showToast(`Only ${max} available in stock`, 'error');
|
||||
}
|
||||
|
||||
this.value = value;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize when DOM is loaded
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
console.log('DOM loaded, initializing cart functionality');
|
||||
initAddToCart();
|
||||
initQuantityControls();
|
||||
});
|
||||
@@ -0,0 +1,45 @@
|
||||
// Create toast container if it doesn't exist
|
||||
function ensureToastContainer() {
|
||||
let container = document.querySelector('.toast-container');
|
||||
if (!container) {
|
||||
container = document.createElement('div');
|
||||
container.className = 'toast-container';
|
||||
document.body.appendChild(container);
|
||||
}
|
||||
return container;
|
||||
}
|
||||
|
||||
// Show a toast notification
|
||||
function showToast(message, type = 'success') {
|
||||
const container = ensureToastContainer();
|
||||
|
||||
// Create toast element
|
||||
const toast = document.createElement('div');
|
||||
toast.className = `toast ${type}`;
|
||||
|
||||
// Add icon based on type
|
||||
const icon = document.createElement('i');
|
||||
icon.className = type === 'success' ? 'fas fa-check-circle' : 'fas fa-exclamation-circle';
|
||||
toast.appendChild(icon);
|
||||
|
||||
// Add message
|
||||
const messageText = document.createElement('span');
|
||||
messageText.textContent = message;
|
||||
toast.appendChild(messageText);
|
||||
|
||||
// Add to container
|
||||
container.appendChild(toast);
|
||||
|
||||
// Trigger animation
|
||||
setTimeout(() => {
|
||||
toast.classList.add('show');
|
||||
}, 10);
|
||||
|
||||
// Remove after 3 seconds
|
||||
setTimeout(() => {
|
||||
toast.classList.remove('show');
|
||||
setTimeout(() => {
|
||||
container.removeChild(toast);
|
||||
}, 300);
|
||||
}, 3000);
|
||||
}
|
||||
@@ -0,0 +1,425 @@
|
||||
/**
|
||||
* UniMarket - Main JavaScript File
|
||||
* Handles frontend interactions, form validations, and UI enhancements
|
||||
*/
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Mobile menu toggle functionality
|
||||
const mobileMenuToggle = document.querySelector('.mobile-menu-toggle');
|
||||
if (mobileMenuToggle) {
|
||||
mobileMenuToggle.addEventListener('click', function() {
|
||||
const menu = document.getElementById('mobileMenu');
|
||||
if (menu) {
|
||||
menu.style.display = menu.style.display === 'block' ? 'none' : 'block';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize all tooltips
|
||||
initTooltips();
|
||||
|
||||
// Initialize all form validations
|
||||
initFormValidations();
|
||||
|
||||
// Initialize product quantity controls
|
||||
initQuantityControls();
|
||||
|
||||
// Initialize image preview for file uploads
|
||||
initImagePreviews();
|
||||
|
||||
// Initialize date/time pickers
|
||||
initDateTimePickers();
|
||||
|
||||
// Initialize cart interactions
|
||||
if (document.querySelector('.cart-page')) {
|
||||
initCartInteractions();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Initialize tooltips throughout the application
|
||||
*/
|
||||
function initTooltips() {
|
||||
const tooltips = document.querySelectorAll('[data-tooltip]');
|
||||
|
||||
tooltips.forEach(tooltip => {
|
||||
const tooltipText = tooltip.getAttribute('data-tooltip');
|
||||
const tooltipElement = document.createElement('span');
|
||||
tooltipElement.className = 'tooltip-text';
|
||||
tooltipElement.textContent = tooltipText;
|
||||
tooltip.appendChild(tooltipElement);
|
||||
|
||||
// Position tooltip on hover
|
||||
tooltip.addEventListener('mouseenter', function() {
|
||||
const rect = this.getBoundingClientRect();
|
||||
tooltipElement.style.left = `${rect.width / 2}px`;
|
||||
tooltipElement.style.top = `${rect.height + 5}px`;
|
||||
tooltipElement.style.opacity = '1';
|
||||
});
|
||||
|
||||
tooltip.addEventListener('mouseleave', function() {
|
||||
tooltipElement.style.opacity = '0';
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize form validation handlers
|
||||
*/
|
||||
function initFormValidations() {
|
||||
const forms = document.querySelectorAll('form[data-validate]');
|
||||
|
||||
forms.forEach(form => {
|
||||
form.addEventListener('submit', function(e) {
|
||||
let isValid = true;
|
||||
const requiredFields = this.querySelectorAll('[required]');
|
||||
|
||||
requiredFields.forEach(field => {
|
||||
if (!field.value.trim()) {
|
||||
isValid = false;
|
||||
field.classList.add('error');
|
||||
|
||||
// Create or show error message
|
||||
let errorMsg = field.nextElementSibling;
|
||||
if (!errorMsg || !errorMsg.classList.contains('error-message')) {
|
||||
errorMsg = document.createElement('small');
|
||||
errorMsg.className = 'error-message';
|
||||
errorMsg.textContent = 'This field is required';
|
||||
field.parentNode.insertBefore(errorMsg, field.nextSibling);
|
||||
}
|
||||
} else {
|
||||
field.classList.remove('error');
|
||||
const errorMsg = field.nextElementSibling;
|
||||
if (errorMsg && errorMsg.classList.contains('error-message')) {
|
||||
errorMsg.remove();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!isValid) {
|
||||
e.preventDefault();
|
||||
|
||||
// Scroll to first error
|
||||
const firstError = this.querySelector('.error');
|
||||
if (firstError) {
|
||||
firstError.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize quantity controls for product pages
|
||||
*/
|
||||
function initQuantityControls() {
|
||||
document.querySelectorAll('.quantity-control').forEach(control => {
|
||||
const input = control.querySelector('.quantity-input');
|
||||
const increment = control.querySelector('.quantity-increment');
|
||||
const decrement = control.querySelector('.quantity-decrement');
|
||||
|
||||
increment.addEventListener('click', () => {
|
||||
input.value = parseInt(input.value) + 1;
|
||||
input.dispatchEvent(new Event('change'));
|
||||
});
|
||||
|
||||
decrement.addEventListener('click', () => {
|
||||
if (parseInt(input.value) > 1) {
|
||||
input.value = parseInt(input.value) - 1;
|
||||
input.dispatchEvent(new Event('change'));
|
||||
}
|
||||
});
|
||||
|
||||
// Validate input
|
||||
input.addEventListener('change', () => {
|
||||
if (parseInt(input.value) < 1) {
|
||||
input.value = 1;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize image previews for file uploads
|
||||
*/
|
||||
function initImagePreviews() {
|
||||
document.querySelectorAll('.image-upload').forEach(upload => {
|
||||
const input = upload.querySelector('input[type="file"]');
|
||||
const preview = upload.querySelector('.image-preview');
|
||||
const defaultText = upload.querySelector('.default-text');
|
||||
|
||||
if (input && preview) {
|
||||
input.addEventListener('change', function() {
|
||||
const file = this.files[0];
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = function(e) {
|
||||
preview.style.backgroundImage = `url(${e.target.result})`;
|
||||
preview.classList.add('has-image');
|
||||
if (defaultText) defaultText.style.display = 'none';
|
||||
}
|
||||
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize date/time pickers for pickup scheduling
|
||||
*/
|
||||
function initDateTimePickers() {
|
||||
const datePickers = document.querySelectorAll('.date-picker');
|
||||
|
||||
if (datePickers.length > 0) {
|
||||
// Load flatpickr if not already loaded
|
||||
if (typeof flatpickr === 'undefined') {
|
||||
const script = document.createElement('script');
|
||||
script.src = 'https://cdn.jsdelivr.net/npm/flatpickr';
|
||||
script.onload = function() {
|
||||
setupDateTimePickers();
|
||||
};
|
||||
document.head.appendChild(script);
|
||||
|
||||
const style = document.createElement('link');
|
||||
style.rel = 'stylesheet';
|
||||
style.href = 'https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css';
|
||||
document.head.appendChild(style);
|
||||
} else {
|
||||
setupDateTimePickers();
|
||||
}
|
||||
}
|
||||
|
||||
function setupDateTimePickers() {
|
||||
document.querySelectorAll('.date-picker').forEach(picker => {
|
||||
flatpickr(picker, {
|
||||
enableTime: picker.classList.contains('time-picker'),
|
||||
dateFormat: picker.classList.contains('time-picker') ? "Y-m-d H:i" : "Y-m-d",
|
||||
minDate: "today",
|
||||
time_24hr: true
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize cart interactions
|
||||
*/
|
||||
function initCartInteractions() {
|
||||
// Update cart item quantities
|
||||
document.querySelectorAll('.cart-item-quantity').forEach(input => {
|
||||
input.addEventListener('change', function() {
|
||||
const form = this.closest('form');
|
||||
if (form) {
|
||||
form.submit();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Handle remove item buttons
|
||||
document.querySelectorAll('.remove-item-btn').forEach(button => {
|
||||
button.addEventListener('click', function(e) {
|
||||
if (!confirm('Are you sure you want to remove this item from your cart?')) {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Handle checkout button
|
||||
const checkoutBtn = document.querySelector('.checkout-btn');
|
||||
if (checkoutBtn) {
|
||||
checkoutBtn.addEventListener('click', function(e) {
|
||||
if (document.querySelector('.cart-item').length === 0) {
|
||||
e.preventDefault();
|
||||
alert('Your cart is empty. Please add items before checking out.');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX helper function
|
||||
*/
|
||||
function makeRequest(url, method = 'GET', data = null) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open(method, url);
|
||||
xhr.setRequestHeader('Content-Type', 'application/json');
|
||||
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
|
||||
|
||||
xhr.onload = function() {
|
||||
if (xhr.status >= 200 && xhr.status < 300) {
|
||||
try {
|
||||
resolve(JSON.parse(xhr.responseText));
|
||||
} catch (e) {
|
||||
resolve(xhr.responseText);
|
||||
}
|
||||
} else {
|
||||
reject(xhr.statusText);
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onerror = function() {
|
||||
reject(xhr.statusText);
|
||||
};
|
||||
|
||||
xhr.send(data ? JSON.stringify(data) : null);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Display flash messages
|
||||
*/
|
||||
function displayFlashMessages() {
|
||||
const flashMessages = document.querySelector('.flash-messages');
|
||||
if (flashMessages) {
|
||||
setTimeout(() => {
|
||||
flashMessages.style.opacity = '0';
|
||||
setTimeout(() => {
|
||||
flashMessages.remove();
|
||||
}, 500);
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
// Display flash messages when page loads
|
||||
displayFlashMessages();
|
||||
|
||||
/**
|
||||
* Debounce function for performance optimization
|
||||
*/
|
||||
function debounce(func, wait, immediate) {
|
||||
let timeout;
|
||||
return function() {
|
||||
const context = this, args = arguments;
|
||||
const later = function() {
|
||||
timeout = null;
|
||||
if (!immediate) func.apply(context, args);
|
||||
};
|
||||
const callNow = immediate && !timeout;
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(later, wait);
|
||||
if (callNow) func.apply(context, args);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Throttle function for performance optimization
|
||||
*/
|
||||
function throttle(func, limit) {
|
||||
let lastFunc;
|
||||
let lastRan;
|
||||
return function() {
|
||||
const context = this;
|
||||
const args = arguments;
|
||||
if (!lastRan) {
|
||||
func.apply(context, args);
|
||||
lastRan = Date.now();
|
||||
} else {
|
||||
clearTimeout(lastFunc);
|
||||
lastFunc = setTimeout(function() {
|
||||
if ((Date.now() - lastRan) >= limit) {
|
||||
func.apply(context, args);
|
||||
lastRan = Date.now();
|
||||
}
|
||||
}, limit - (Date.now() - lastRan));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add to cart functionality
|
||||
document.querySelectorAll('.add-to-cart').forEach(button => {
|
||||
button.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const productId = this.dataset.productId;
|
||||
const quantity = this.closest('form')?.querySelector('input[name="quantity"]')?.value || 1;
|
||||
|
||||
makeRequest('/unimarket/ajax/add_to_cart.php', 'POST', {
|
||||
product_id: productId,
|
||||
quantity: quantity
|
||||
})
|
||||
.then(response => {
|
||||
if (response.success) {
|
||||
// Update cart count in header
|
||||
const cartCount = document.querySelector('.cart-count');
|
||||
if (cartCount) {
|
||||
cartCount.textContent = response.cart_count;
|
||||
cartCount.classList.add('pulse');
|
||||
setTimeout(() => {
|
||||
cartCount.classList.remove('pulse');
|
||||
}, 500);
|
||||
}
|
||||
|
||||
// Show success message
|
||||
showToast('Item added to cart!');
|
||||
} else {
|
||||
showToast(response.message || 'Failed to add item to cart', 'error');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
showToast('An error occurred. Please try again.', 'error');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Show toast notification
|
||||
*/
|
||||
function showToast(message, type = 'success') {
|
||||
const toast = document.createElement('div');
|
||||
toast.className = `toast toast-${type}`;
|
||||
toast.textContent = message;
|
||||
document.body.appendChild(toast);
|
||||
|
||||
setTimeout(() => {
|
||||
toast.classList.add('show');
|
||||
}, 10);
|
||||
|
||||
setTimeout(() => {
|
||||
toast.classList.remove('show');
|
||||
setTimeout(() => {
|
||||
toast.remove();
|
||||
}, 300);
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
// Add CSS for toast notifications
|
||||
const toastStyles = document.createElement('style');
|
||||
toastStyles.textContent = `
|
||||
.toast {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
padding: 15px 25px;
|
||||
border-radius: 4px;
|
||||
color: white;
|
||||
background-color: #2e7d32;
|
||||
box-shadow: 0 3px 10px rgba(0,0,0,0.2);
|
||||
transform: translateY(100px);
|
||||
opacity: 0;
|
||||
transition: all 0.3s ease;
|
||||
z-index: 1000;
|
||||
}
|
||||
.toast.show {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
.toast-error {
|
||||
background-color: #d32f2f;
|
||||
}
|
||||
.toast-success {
|
||||
background-color: #2e7d32;
|
||||
}
|
||||
.pulse {
|
||||
animation: pulse 0.5s;
|
||||
}
|
||||
@keyframes pulse {
|
||||
0% { transform: scale(1); }
|
||||
50% { transform: scale(1.2); }
|
||||
100% { transform: scale(1); }
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(toastStyles);
|
||||
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
require_once '../includes/auth_functions.php';
|
||||
|
||||
if (isLoggedIn()) {
|
||||
header("Location: /unimarket/index.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
$error = '';
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
require_once '../config/database.php';
|
||||
|
||||
$username = trim($_POST['username']);
|
||||
$password = trim($_POST['password']);
|
||||
|
||||
if (empty($username) || empty($password)) {
|
||||
$error = 'Please fill in all fields.';
|
||||
} else {
|
||||
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ?");
|
||||
$stmt->execute([$username]);
|
||||
$user = $stmt->fetch();
|
||||
|
||||
if ($user && password_verify($password, $user['password'])) {
|
||||
$_SESSION['user_id'] = $user['user_id'];
|
||||
$_SESSION['username'] = $user['username'];
|
||||
$_SESSION['role'] = $user['role'];
|
||||
|
||||
if ($user['role'] === 'admin') {
|
||||
header("Location: /unimarket/admin/dashboard.php");
|
||||
} elseif ($user['role'] === 'owner') {
|
||||
header("Location: /unimarket/owner/dashboard.php");
|
||||
} else {
|
||||
header("Location: /unimarket/index.php");
|
||||
}
|
||||
exit();
|
||||
} else {
|
||||
$error = 'Invalid username or password.';
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Login - UniMarket</title>
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/style.css">
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/responsive.css">
|
||||
</head>
|
||||
<body>
|
||||
<?php include '../includes/header.php'; ?>
|
||||
|
||||
<div class="container">
|
||||
<div class="card" style="max-width: 500px; margin: 50px auto;">
|
||||
<h1 style="text-align: center; margin-bottom: 20px;">Login to UniMarket</h1>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<div class="alert alert-error"><?php echo $error; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form action="" method="POST">
|
||||
<div class="form-group">
|
||||
<label for="username">Username</label>
|
||||
<input type="text" id="username" name="username" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="password">Password</label>
|
||||
<input type="password" id="password" name="password" required>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn">Login</button>
|
||||
</form>
|
||||
|
||||
<p style="text-align: center; margin-top: 20px;">
|
||||
Don't have an account? <a href="/unimarket/auth/register.php">Register here</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include '../includes/footer.php'; ?>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../includes/auth_functions.php';
|
||||
|
||||
// Destroy the current session
|
||||
destroySession();
|
||||
|
||||
// Set a success flash message
|
||||
flashMessage('logout_success', 'You have been successfully logged out.');
|
||||
|
||||
// Redirect to the homepage with a success message
|
||||
header("Location: /unimarket/index.php");
|
||||
exit();
|
||||
@@ -0,0 +1,325 @@
|
||||
<?php
|
||||
require_once '../includes/auth_functions.php';
|
||||
|
||||
if (isLoggedIn()) {
|
||||
header("Location: /unimarket/index.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
require_once '../config/database.php';
|
||||
|
||||
$errors = [];
|
||||
$success = false;
|
||||
|
||||
// Form fields
|
||||
$fields = [
|
||||
'username' => '',
|
||||
'email' => '',
|
||||
'first_name' => '',
|
||||
'last_name' => '',
|
||||
'university_id' => '',
|
||||
'phone' => '',
|
||||
'role' => 'customer' // Default role
|
||||
];
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// Sanitize and validate input
|
||||
$fields['username'] = trim($_POST['username']);
|
||||
$fields['email'] = trim($_POST['email']);
|
||||
$fields['first_name'] = trim($_POST['first_name']);
|
||||
$fields['last_name'] = trim($_POST['last_name']);
|
||||
$fields['university_id'] = trim($_POST['university_id']);
|
||||
$fields['phone'] = trim($_POST['phone']);
|
||||
$fields['role'] = $_POST['role'] === 'owner' ? 'owner' : 'customer';
|
||||
$password = trim($_POST['password']);
|
||||
$confirm_password = trim($_POST['confirm_password']);
|
||||
|
||||
// Validate inputs
|
||||
if (empty($fields['username'])) {
|
||||
$errors['username'] = 'Username is required.';
|
||||
} elseif (!preg_match('/^[a-zA-Z0-9_]{4,20}$/', $fields['username'])) {
|
||||
$errors['username'] = 'Username must be 4-20 characters (letters, numbers, underscores).';
|
||||
}
|
||||
|
||||
if (empty($fields['email'])) {
|
||||
$errors['email'] = 'Email is required.';
|
||||
} elseif (!filter_var($fields['email'], FILTER_VALIDATE_EMAIL)) {
|
||||
$errors['email'] = 'Please enter a valid email address.';
|
||||
}
|
||||
|
||||
if (empty($fields['first_name'])) {
|
||||
$errors['first_name'] = 'First name is required.';
|
||||
}
|
||||
|
||||
if (empty($fields['last_name'])) {
|
||||
$errors['last_name'] = 'Last name is required.';
|
||||
}
|
||||
|
||||
if (empty($fields['university_id'])) {
|
||||
$errors['university_id'] = 'University ID is required.';
|
||||
}
|
||||
|
||||
if (empty($password)) {
|
||||
$errors['password'] = 'Password is required.';
|
||||
} elseif (strlen($password) < 8) {
|
||||
$errors['password'] = 'Password must be at least 8 characters.';
|
||||
} elseif ($password !== $confirm_password) {
|
||||
$errors['confirm_password'] = 'Passwords do not match.';
|
||||
}
|
||||
|
||||
// Check if username or email already exists
|
||||
if (empty($errors)) {
|
||||
$stmt = $pdo->prepare("SELECT user_id FROM users WHERE username = ? OR email = ?");
|
||||
$stmt->execute([$fields['username'], $fields['email']]);
|
||||
if ($stmt->fetch()) {
|
||||
$errors['general'] = 'Username or email already exists.';
|
||||
}
|
||||
}
|
||||
|
||||
// If no errors, create user
|
||||
if (empty($errors)) {
|
||||
try {
|
||||
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
|
||||
|
||||
$stmt = $pdo->prepare("INSERT INTO users
|
||||
(username, password, email, first_name, last_name, university_id, phone, role)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
|
||||
$stmt->execute([
|
||||
$fields['username'],
|
||||
$hashed_password,
|
||||
$fields['email'],
|
||||
$fields['first_name'],
|
||||
$fields['last_name'],
|
||||
$fields['university_id'],
|
||||
$fields['phone'],
|
||||
$fields['role']
|
||||
]);
|
||||
|
||||
// Create a cart for customers
|
||||
if ($fields['role'] === 'customer') {
|
||||
$user_id = $pdo->lastInsertId();
|
||||
$stmt = $pdo->prepare("INSERT INTO cart (user_id) VALUES (?)");
|
||||
$stmt->execute([$user_id]);
|
||||
}
|
||||
|
||||
$success = true;
|
||||
} catch (PDOException $e) {
|
||||
$errors['general'] = 'Registration failed. Please try again.';
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Register - UniMarket</title>
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/style.css">
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/responsive.css">
|
||||
<style>
|
||||
.role-selector {
|
||||
display: flex;
|
||||
margin-bottom: 20px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.role-option {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
.role-option input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.role-option label {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.role-option:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.role-option.active {
|
||||
background-color: var(--primary-color);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.password-strength {
|
||||
height: 5px;
|
||||
background-color: #eee;
|
||||
margin-top: 5px;
|
||||
border-radius: 3px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.password-strength-bar {
|
||||
height: 100%;
|
||||
width: 0%;
|
||||
background-color: #ff0000;
|
||||
transition: width 0.3s, background-color 0.3s;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<?php include '../includes/header.php'; ?>
|
||||
|
||||
<div class="container">
|
||||
<div class="card" style="max-width: 600px; margin: 50px auto;">
|
||||
<h1 style="text-align: center; margin-bottom: 20px;">Create Your Account</h1>
|
||||
|
||||
<?php if ($success): ?>
|
||||
<div class="alert alert-success">
|
||||
Registration successful! You can now <a href="/unimarket/auth/login.php">login</a>.
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<?php if (isset($errors['general'])): ?>
|
||||
<div class="alert alert-error"><?php echo $errors['general']; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form action="" method="POST" id="registrationForm">
|
||||
<div class="role-selector">
|
||||
<div class="role-option <?php echo $fields['role'] === 'customer' ? 'active' : ''; ?>">
|
||||
<input type="radio" id="role_customer" name="role" value="customer" <?php echo $fields['role'] === 'customer' ? 'checked' : ''; ?>>
|
||||
<label for="role_customer">I'm a Student</label>
|
||||
</div>
|
||||
<div class="role-option <?php echo $fields['role'] === 'owner' ? 'active' : ''; ?>">
|
||||
<input type="radio" id="role_owner" name="role" value="owner" <?php echo $fields['role'] === 'owner' ? 'checked' : ''; ?>>
|
||||
<label for="role_owner">I'm a Vendor</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="username">Username*</label>
|
||||
<input type="text" id="username" name="username" value="<?php echo htmlspecialchars($fields['username']); ?>" required>
|
||||
<?php if (isset($errors['username'])): ?>
|
||||
<small style="color: var(--error-color);"><?php echo $errors['username']; ?></small>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="email">Email*</label>
|
||||
<input type="email" id="email" name="email" value="<?php echo htmlspecialchars($fields['email']); ?>" required>
|
||||
<?php if (isset($errors['email'])): ?>
|
||||
<small style="color: var(--error-color);"><?php echo $errors['email']; ?></small>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="first_name">First Name*</label>
|
||||
<input type="text" id="first_name" name="first_name" value="<?php echo htmlspecialchars($fields['first_name']); ?>" required>
|
||||
<?php if (isset($errors['first_name'])): ?>
|
||||
<small style="color: var(--error-color);"><?php echo $errors['first_name']; ?></small>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="last_name">Last Name*</label>
|
||||
<input type="text" id="last_name" name="last_name" value="<?php echo htmlspecialchars($fields['last_name']); ?>" required>
|
||||
<?php if (isset($errors['last_name'])): ?>
|
||||
<small style="color: var(--error-color);"><?php echo $errors['last_name']; ?></small>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="university_id">University ID*</label>
|
||||
<input type="text" id="university_id" name="university_id" value="<?php echo htmlspecialchars($fields['university_id']); ?>" required>
|
||||
<?php if (isset($errors['university_id'])): ?>
|
||||
<small style="color: var(--error-color);"><?php echo $errors['university_id']; ?></small>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="phone">Phone Number</label>
|
||||
<input type="tel" id="phone" name="phone" class="form-control" value="<?php echo htmlspecialchars($fields['phone']); ?>">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="password">Password*</label>
|
||||
<input type="password" id="password" name="password" required>
|
||||
<div class="password-strength">
|
||||
<div class="password-strength-bar" id="passwordStrengthBar"></div>
|
||||
</div>
|
||||
<?php if (isset($errors['password'])): ?>
|
||||
<small style="color: var(--error-color);"><?php echo $errors['password']; ?></small>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="confirm_password">Confirm Password*</label>
|
||||
<input type="password" id="confirm_password" name="confirm_password" required>
|
||||
<?php if (isset($errors['confirm_password'])): ?>
|
||||
<small style="color: var(--error-color);"><?php echo $errors['confirm_password']; ?></small>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn" style="width: 100%;">Register</button>
|
||||
|
||||
<p style="text-align: center; margin-top: 20px;">
|
||||
Already have an account? <a href="/unimarket/auth/login.php">Login here</a>
|
||||
</p>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include '../includes/footer.php'; ?>
|
||||
|
||||
<script>
|
||||
// Role selector styling
|
||||
document.querySelectorAll('.role-option').forEach(option => {
|
||||
option.addEventListener('click', function() {
|
||||
document.querySelectorAll('.role-option').forEach(opt => {
|
||||
opt.classList.remove('active');
|
||||
});
|
||||
this.classList.add('active');
|
||||
this.querySelector('input').checked = true;
|
||||
});
|
||||
});
|
||||
|
||||
// Password strength indicator
|
||||
const passwordInput = document.getElementById('password');
|
||||
const strengthBar = document.getElementById('passwordStrengthBar');
|
||||
|
||||
passwordInput.addEventListener('input', function() {
|
||||
const password = this.value;
|
||||
let strength = 0;
|
||||
|
||||
if (password.length >= 8) strength += 1;
|
||||
if (password.match(/[a-z]/)) strength += 1;
|
||||
if (password.match(/[A-Z]/)) strength += 1;
|
||||
if (password.match(/[0-9]/)) strength += 1;
|
||||
if (password.match(/[^a-zA-Z0-9]/)) strength += 1;
|
||||
|
||||
const width = strength * 20;
|
||||
let color;
|
||||
|
||||
if (strength <= 1) color = '#ff0000';
|
||||
else if (strength <= 3) color = '#ff9900';
|
||||
else color = '#00aa00';
|
||||
|
||||
strengthBar.style.width = width + '%';
|
||||
strengthBar.style.backgroundColor = color;
|
||||
});
|
||||
|
||||
// Form validation
|
||||
document.getElementById('registrationForm').addEventListener('submit', function(e) {
|
||||
const password = document.getElementById('password').value;
|
||||
const confirmPassword = document.getElementById('confirm_password').value;
|
||||
|
||||
if (password !== confirmPassword) {
|
||||
e.preventDefault();
|
||||
alert('Passwords do not match!');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
$host = 'localhost';
|
||||
$dbname = 'unimarket';
|
||||
$username = 'root';
|
||||
$password = '';
|
||||
|
||||
try {
|
||||
$pdo = new PDO("mysql:host=$host;dbname=$dbname", $username, $password);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
} catch (PDOException $e) {
|
||||
die("Database connection failed: " . $e->getMessage());
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,14 @@
|
||||
CREATE TABLE IF NOT EXISTS products (
|
||||
product_id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
owner_id INT NOT NULL,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
description TEXT,
|
||||
price DECIMAL(10,2) NOT NULL,
|
||||
category VARCHAR(50),
|
||||
subcategory VARCHAR(50),
|
||||
stock_quantity INT NOT NULL DEFAULT 0,
|
||||
image_path VARCHAR(255),
|
||||
size_data JSON,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (owner_id) REFERENCES users(user_id)
|
||||
);
|
||||
@@ -0,0 +1,688 @@
|
||||
<?php
|
||||
require_once '../includes/auth_functions.php';
|
||||
redirectIfNotLoggedIn();
|
||||
redirectIfNotCustomer();
|
||||
|
||||
require_once '../config/database.php';
|
||||
|
||||
// Initialize variables
|
||||
$success_message = '';
|
||||
$cart_items = [];
|
||||
|
||||
// Get cart items
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT
|
||||
ci.cart_item_id,
|
||||
ci.product_id,
|
||||
ci.quantity,
|
||||
ci.size,
|
||||
p.name as product_name,
|
||||
p.price,
|
||||
p.image_path,
|
||||
p.stock_quantity,
|
||||
p.category,
|
||||
p.size_data
|
||||
FROM cart_items ci
|
||||
JOIN products p ON ci.product_id = p.product_id
|
||||
JOIN cart c ON ci.cart_id = c.cart_id
|
||||
WHERE c.user_id = ?
|
||||
");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
$cart_items = $stmt->fetchAll();
|
||||
|
||||
// Calculate total
|
||||
$total = array_reduce($cart_items, function($sum, $item) {
|
||||
return $sum + ($item['price'] * $item['quantity']);
|
||||
}, 0);
|
||||
|
||||
// Handle checkout process
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['checkout'])) {
|
||||
try {
|
||||
// Start transaction
|
||||
$pdo->beginTransaction();
|
||||
|
||||
// Get cart items
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT
|
||||
ci.cart_item_id,
|
||||
ci.product_id,
|
||||
ci.quantity,
|
||||
ci.size,
|
||||
p.price,
|
||||
p.stock_quantity,
|
||||
p.owner_id,
|
||||
p.name as product_name,
|
||||
p.category,
|
||||
p.size_data
|
||||
FROM cart_items ci
|
||||
JOIN products p ON ci.product_id = p.product_id
|
||||
JOIN cart c ON ci.cart_id = c.cart_id
|
||||
WHERE c.user_id = ?
|
||||
");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
$cart_items = $stmt->fetchAll();
|
||||
|
||||
// Debug cart items
|
||||
error_log("Cart items before order creation: " . print_r($cart_items, true));
|
||||
|
||||
if (empty($cart_items)) {
|
||||
throw new Exception('Your cart is empty');
|
||||
}
|
||||
|
||||
// Create order
|
||||
$stmt = $pdo->prepare("
|
||||
INSERT INTO orders (customer_id, total_amount, status, order_date)
|
||||
VALUES (?, ?, 'pending', NOW())
|
||||
");
|
||||
$total_amount = array_reduce($cart_items, function($sum, $item) {
|
||||
return $sum + ($item['price'] * $item['quantity']);
|
||||
}, 0);
|
||||
$stmt->execute([$_SESSION['user_id'], $total_amount]);
|
||||
$order_id = $pdo->lastInsertId();
|
||||
|
||||
// Create order items
|
||||
$stmt = $pdo->prepare("
|
||||
INSERT INTO order_items (order_id, product_id, quantity, price, size)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
");
|
||||
|
||||
foreach ($cart_items as $item) {
|
||||
// Debug each item being added to order
|
||||
error_log("Adding item to order: " . print_r($item, true));
|
||||
|
||||
// Check stock
|
||||
if ($item['quantity'] > $item['stock_quantity']) {
|
||||
throw new Exception("Not enough stock for {$item['product_name']}");
|
||||
}
|
||||
|
||||
// For clothing items, ensure size is set
|
||||
$size = null;
|
||||
if ($item['category'] === 'clothes') {
|
||||
$size = $item['size'];
|
||||
if (empty($size)) {
|
||||
throw new Exception("Size is required for clothing item: {$item['product_name']}");
|
||||
}
|
||||
}
|
||||
|
||||
// Add order item
|
||||
$stmt->execute([
|
||||
$order_id,
|
||||
$item['product_id'],
|
||||
$item['quantity'],
|
||||
$item['price'],
|
||||
$size
|
||||
]);
|
||||
|
||||
// Update product stock
|
||||
$update_stock = $pdo->prepare("
|
||||
UPDATE products
|
||||
SET stock_quantity = stock_quantity - ?
|
||||
WHERE product_id = ?
|
||||
");
|
||||
$update_stock->execute([$item['quantity'], $item['product_id']]);
|
||||
}
|
||||
|
||||
// Clear cart
|
||||
$stmt = $pdo->prepare("
|
||||
DELETE ci FROM cart_items ci
|
||||
JOIN cart c ON ci.cart_id = c.cart_id
|
||||
WHERE c.user_id = ?
|
||||
");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
|
||||
// Commit transaction
|
||||
$pdo->commit();
|
||||
|
||||
// Set success message
|
||||
$success_message = 'Order placed successfully! Your order #' . $order_id . ' is being processed.';
|
||||
|
||||
// Clear cart items array after successful checkout
|
||||
$cart_items = [];
|
||||
|
||||
} catch (Exception $e) {
|
||||
// Rollback transaction on error
|
||||
$pdo->rollBack();
|
||||
$success_message = $e->getMessage();
|
||||
}
|
||||
} else {
|
||||
// Get cart items only if not processing checkout
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT
|
||||
ci.cart_item_id,
|
||||
ci.product_id,
|
||||
ci.quantity,
|
||||
ci.size,
|
||||
p.name as product_name,
|
||||
p.price,
|
||||
p.image_path,
|
||||
p.stock_quantity,
|
||||
p.category,
|
||||
p.size_data
|
||||
FROM cart_items ci
|
||||
JOIN products p ON ci.product_id = p.product_id
|
||||
JOIN cart c ON ci.cart_id = c.cart_id
|
||||
WHERE c.user_id = ?
|
||||
");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
$cart_items = $stmt->fetchAll();
|
||||
}
|
||||
|
||||
// Calculate total
|
||||
$total = array_reduce($cart_items, function($sum, $item) {
|
||||
return $sum + ($item['price'] * $item['quantity']);
|
||||
}, 0);
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Shopping Cart - UniMarket</title>
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/style.css">
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/responsive.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||
<script src="/unimarket/assets/js/notifications.js"></script>
|
||||
<style>
|
||||
/* Cart item styles */
|
||||
.cart-container {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.cart-items {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.cart-item {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
padding: 15px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.item-image {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
flex-shrink: 0;
|
||||
background: #f8f9fa;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.item-image img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.item-image .no-image {
|
||||
color: #ccc;
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
.item-details {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.item-details h3 {
|
||||
margin: 0;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.item-price {
|
||||
font-weight: 500;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.item-size {
|
||||
color: #666;
|
||||
font-size: 0.9em;
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.quantity-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.quantity-controls button {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border: 1px solid #ddd;
|
||||
background: white;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.quantity-input {
|
||||
width: 60px;
|
||||
text-align: center;
|
||||
padding: 5px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.remove-item {
|
||||
color: #dc3545;
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
padding: 5px 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.remove-item:hover {
|
||||
color: #c82333;
|
||||
}
|
||||
|
||||
.cart-summary {
|
||||
width: 300px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.cart-total {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 1.2em;
|
||||
font-weight: 500;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.cart-actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.empty-cart {
|
||||
text-align: center;
|
||||
padding: 50px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.empty-cart i {
|
||||
font-size: 3em;
|
||||
color: #ccc;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
/* Purchase confirmation modal styles */
|
||||
.purchase-modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 2000;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.purchase-modal-content {
|
||||
background: white;
|
||||
padding: 30px;
|
||||
border-radius: 8px;
|
||||
text-align: center;
|
||||
max-width: 400px;
|
||||
width: 90%;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.purchase-modal h2 {
|
||||
margin-bottom: 20px;
|
||||
color: var(--primary-dark);
|
||||
}
|
||||
|
||||
.purchase-modal-buttons {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 15px;
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
.purchase-modal-buttons button {
|
||||
padding: 10px 25px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.purchase-modal-buttons .btn-cancel {
|
||||
background: #e0e0e0;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.purchase-modal-buttons .btn-cancel:hover {
|
||||
background: #d0d0d0;
|
||||
}
|
||||
|
||||
.purchase-modal-buttons .btn-confirm {
|
||||
background: var(--primary-color);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.purchase-modal-buttons .btn-confirm:hover {
|
||||
background: var(--primary-dark);
|
||||
}
|
||||
|
||||
.payment-info {
|
||||
background: #f8f9fa;
|
||||
padding: 15px;
|
||||
border-radius: 4px;
|
||||
margin: 20px 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.payment-info i {
|
||||
color: var(--primary-color);
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.payment-info p {
|
||||
margin: 0;
|
||||
color: #666;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.cart-container {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.cart-summary {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.cart-item {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.item-image {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
}
|
||||
}
|
||||
|
||||
.notification {
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
padding: 15px 25px;
|
||||
border-radius: 5px;
|
||||
color: white;
|
||||
font-weight: 500;
|
||||
z-index: 1000;
|
||||
animation: slideIn 0.5s ease-out;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
background-color: #28a745;
|
||||
}
|
||||
|
||||
@keyframes slideIn {
|
||||
from {
|
||||
transform: translateX(100%);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideOut {
|
||||
from {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
transform: translateX(100%);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.notification.hide {
|
||||
animation: slideOut 0.5s ease-out forwards;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<?php include '../includes/header.php'; ?>
|
||||
|
||||
<div class="container">
|
||||
<h1>Shopping Cart</h1>
|
||||
|
||||
<?php if (empty($cart_items)): ?>
|
||||
<div class="empty-cart">
|
||||
<i class="fas fa-shopping-cart"></i>
|
||||
<h2>Your cart is empty</h2>
|
||||
<p>Looks like you haven't added any items to your cart yet.</p>
|
||||
<a href="/unimarket/customer/products/browse.php" class="btn">Continue Shopping</a>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="cart-container">
|
||||
<div class="cart-items">
|
||||
<?php foreach ($cart_items as $item): ?>
|
||||
<div class="cart-item card">
|
||||
<div class="item-image">
|
||||
<?php if ($item['image_path']): ?>
|
||||
<img src="/unimarket/assets/images/products/<?php echo $item['image_path']; ?>"
|
||||
alt="<?php echo htmlspecialchars($item['product_name']); ?>">
|
||||
<?php else: ?>
|
||||
<div class="no-image">
|
||||
<i class="fas fa-box-open"></i>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="item-details">
|
||||
<h3><?php echo htmlspecialchars($item['product_name']); ?></h3>
|
||||
<p class="item-price">₱<?php echo number_format($item['price'], 2); ?></p>
|
||||
|
||||
<?php if ($item['category'] === 'clothes' && isset($item['size'])): ?>
|
||||
<p class="item-size">Size: <?php echo htmlspecialchars($item['size']); ?></p>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="POST" action="../ajax/update_cart.php" class="quantity-form">
|
||||
<input type="hidden" name="cart_item_id" value="<?php echo $item['cart_item_id']; ?>">
|
||||
<div class="quantity-controls">
|
||||
<button type="button" class="quantity-decrement">-</button>
|
||||
<input type="number" name="quantity" value="<?php echo $item['quantity']; ?>"
|
||||
min="1" max="<?php echo $item['stock_quantity']; ?>"
|
||||
class="quantity-input">
|
||||
<button type="button" class="quantity-increment">+</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<p class="item-total">₱<?php echo number_format($item['price'] * $item['quantity'], 2); ?></p>
|
||||
|
||||
<form method="POST" action="../ajax/remove_from_cart.php" class="remove-form">
|
||||
<input type="hidden" name="cart_item_id" value="<?php echo $item['cart_item_id']; ?>">
|
||||
<button type="button" class="remove-item">
|
||||
<i class="fas fa-trash"></i> Remove
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<div class="cart-summary card">
|
||||
<h2>Order Summary</h2>
|
||||
<div class="cart-total">
|
||||
<span>Total:</span>
|
||||
<span class="total-amount">₱<?php echo number_format($total, 2); ?></span>
|
||||
</div>
|
||||
|
||||
<div class="cart-actions">
|
||||
<a href="/unimarket/customer/products/browse.php" class="btn btn-secondary">
|
||||
<i class="fas fa-arrow-left"></i> Continue Shopping
|
||||
</a>
|
||||
<form method="POST" id="checkoutForm">
|
||||
<input type="hidden" name="checkout" value="1">
|
||||
<button type="button" onclick="openPurchaseModal()" class="btn btn-primary">
|
||||
<i class="fas fa-shopping-bag"></i> Proceed to Checkout
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Purchase confirmation modal HTML -->
|
||||
<div class="purchase-modal" id="purchaseModal">
|
||||
<div class="purchase-modal-content">
|
||||
<h2>Confirm Purchase</h2>
|
||||
<p>Are you sure you want to proceed with this purchase?</p>
|
||||
<div class="payment-info">
|
||||
<i class="fas fa-info-circle"></i>
|
||||
<p>Payment will be collected when you pick up your items. The seller will contact you to schedule the pickup time.</p>
|
||||
</div>
|
||||
<div class="purchase-modal-buttons">
|
||||
<button class="btn-cancel" onclick="closePurchaseModal()">Cancel</button>
|
||||
<button class="btn-confirm" onclick="confirmPurchase()">Confirm Purchase</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php include '../includes/footer.php'; ?>
|
||||
|
||||
<script>
|
||||
// Purchase modal functions
|
||||
function openPurchaseModal() {
|
||||
document.getElementById('purchaseModal').style.display = 'flex';
|
||||
}
|
||||
|
||||
function closePurchaseModal() {
|
||||
document.getElementById('purchaseModal').style.display = 'none';
|
||||
}
|
||||
|
||||
function confirmPurchase() {
|
||||
document.getElementById('checkoutForm').submit();
|
||||
}
|
||||
|
||||
// Close modal when clicking outside
|
||||
document.getElementById('purchaseModal').addEventListener('click', function(e) {
|
||||
if (e.target === this) {
|
||||
closePurchaseModal();
|
||||
}
|
||||
});
|
||||
|
||||
// Quantity update handling
|
||||
document.querySelectorAll('.quantity-input').forEach(input => {
|
||||
input.addEventListener('change', function() {
|
||||
const form = this.closest('form');
|
||||
const formData = new FormData(form);
|
||||
|
||||
fetch('../ajax/update_cart.php', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
// Update total price
|
||||
const totalElement = document.querySelector('.cart-total .total-amount');
|
||||
if (totalElement) {
|
||||
totalElement.textContent = '₱' + data.total.toFixed(2);
|
||||
}
|
||||
// Update item total
|
||||
const itemTotal = this.closest('.cart-item').querySelector('.item-total');
|
||||
if (itemTotal) {
|
||||
itemTotal.textContent = '₱' + data.item_total.toFixed(2);
|
||||
}
|
||||
} else {
|
||||
alert(data.message || 'Failed to update quantity');
|
||||
// Reset to previous value
|
||||
this.value = this.defaultValue;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('An error occurred while updating quantity');
|
||||
// Reset to previous value
|
||||
this.value = this.defaultValue;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Remove item handling
|
||||
document.querySelectorAll('.remove-item').forEach(button => {
|
||||
button.addEventListener('click', function() {
|
||||
if (confirm('Are you sure you want to remove this item from your cart?')) {
|
||||
const form = this.closest('form');
|
||||
const formData = new FormData(form);
|
||||
|
||||
fetch('../ajax/remove_from_cart.php', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
// Remove item from DOM
|
||||
const cartItem = this.closest('.cart-item');
|
||||
cartItem.remove();
|
||||
|
||||
// Update total price
|
||||
const totalElement = document.querySelector('.cart-total .total-amount');
|
||||
if (totalElement) {
|
||||
totalElement.textContent = '₱' + data.total.toFixed(2);
|
||||
}
|
||||
|
||||
// Update cart count in header
|
||||
const cartCount = document.querySelector('.cart-count');
|
||||
if (cartCount) {
|
||||
cartCount.textContent = data.cart_count;
|
||||
}
|
||||
|
||||
// Show success message
|
||||
showToast('Item removed from cart', 'success');
|
||||
|
||||
// If cart is empty, reload page to show empty cart message
|
||||
if (data.cart_count === 0) {
|
||||
location.reload();
|
||||
}
|
||||
} else {
|
||||
showToast(data.message || 'Failed to remove item', 'error');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
showToast('An error occurred while removing item', 'error');
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Auto-hide notifications after 5 seconds
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const notifications = document.querySelectorAll('.notification');
|
||||
notifications.forEach(notification => {
|
||||
setTimeout(() => {
|
||||
notification.classList.add('hide');
|
||||
setTimeout(() => {
|
||||
notification.remove();
|
||||
}, 500);
|
||||
}, 5000);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
require_once '../includes/auth_functions.php';
|
||||
require_once '../config/database.php';
|
||||
|
||||
// Check if user is logged in and is a customer
|
||||
if (!isLoggedIn() || !isCustomer()) {
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['error' => 'Unauthorized']);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Get user ID
|
||||
$user_id = $_SESSION['user_id'];
|
||||
|
||||
try {
|
||||
// Get notifications for the user's orders
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT
|
||||
o.order_id,
|
||||
o.status,
|
||||
o.order_date,
|
||||
CASE
|
||||
WHEN o.status = 'ready' THEN CONCAT('Your order #', o.order_id, ' is ready for pickup!')
|
||||
WHEN o.status = 'completed' THEN CONCAT('Your order #', o.order_id, ' has been completed.')
|
||||
WHEN o.status = 'cancelled' THEN CONCAT('Your order #', o.order_id, ' has been cancelled.')
|
||||
ELSE NULL
|
||||
END as title,
|
||||
o.order_date as notification_time,
|
||||
CASE
|
||||
WHEN o.status = 'ready' AND o.notification_read = 0 THEN 1
|
||||
ELSE 0
|
||||
END as unread,
|
||||
o.pickup_schedule
|
||||
FROM orders o
|
||||
WHERE o.customer_id = ?
|
||||
AND o.status IN ('ready', 'completed', 'cancelled')
|
||||
AND o.order_date >= DATE_SUB(NOW(), INTERVAL 7 DAY)
|
||||
ORDER BY o.order_date DESC
|
||||
");
|
||||
|
||||
$stmt->execute([$user_id]);
|
||||
$notifications = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Format notifications
|
||||
$formatted_notifications = array_map(function($notification) {
|
||||
$message = $notification['title'];
|
||||
if ($notification['status'] === 'ready' && $notification['pickup_schedule']) {
|
||||
$message .= ' Scheduled for ' . date('M d, Y h:i A', strtotime($notification['pickup_schedule']));
|
||||
}
|
||||
return [
|
||||
'id' => $notification['order_id'],
|
||||
'title' => $message,
|
||||
'time' => date('M d, Y h:i A', strtotime($notification['notification_time'])),
|
||||
'unread' => (bool)$notification['unread'],
|
||||
'status' => $notification['status']
|
||||
];
|
||||
}, $notifications);
|
||||
|
||||
// Count unread notifications
|
||||
$unread_count = array_reduce($notifications, function($carry, $notification) {
|
||||
return $carry + ($notification['unread'] ? 1 : 0);
|
||||
}, 0);
|
||||
|
||||
// Mark notifications as read
|
||||
if ($unread_count > 0) {
|
||||
$stmt = $pdo->prepare("
|
||||
UPDATE orders
|
||||
SET notification_read = 1
|
||||
WHERE customer_id = ?
|
||||
AND status = 'ready'
|
||||
AND notification_read = 0
|
||||
");
|
||||
$stmt->execute([$user_id]);
|
||||
}
|
||||
|
||||
// Return JSON response
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode([
|
||||
'notifications' => $formatted_notifications,
|
||||
'unread_count' => $unread_count
|
||||
]);
|
||||
|
||||
} catch (PDOException $e) {
|
||||
error_log("Notification Error: " . $e->getMessage());
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['error' => 'Database error: ' . $e->getMessage()]);
|
||||
} catch (Exception $e) {
|
||||
error_log("Notification Error: " . $e->getMessage());
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['error' => 'Server error: ' . $e->getMessage()]);
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
<?php
|
||||
require_once '../../includes/auth_functions.php';
|
||||
redirectIfNotLoggedIn();
|
||||
redirectIfNotCustomer();
|
||||
|
||||
require_once '../../config/database.php';
|
||||
|
||||
// Check if order ID is provided
|
||||
if (!isset($_GET['order_id'])) {
|
||||
header("Location: /unimarket/customer/orders/list.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
$order_id = (int)$_GET['order_id'];
|
||||
|
||||
// Verify order belongs to current user and is ready for pickup
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT o.order_id, o.status, o.pickup_schedule
|
||||
FROM orders o
|
||||
WHERE o.order_id = ? AND o.customer_id = ? AND o.status = 'ready_for_pickup'
|
||||
");
|
||||
$stmt->execute([$order_id, $_SESSION['user_id']]);
|
||||
$order = $stmt->fetch();
|
||||
|
||||
if (!$order) {
|
||||
header("Location: /unimarket/customer/orders/list.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
$success_message = '';
|
||||
$error_message = '';
|
||||
|
||||
// Handle order completion
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['complete_order'])) {
|
||||
try {
|
||||
$pdo->beginTransaction();
|
||||
|
||||
// Update order status to completed
|
||||
$stmt = $pdo->prepare("UPDATE orders SET status = 'completed' WHERE order_id = ?");
|
||||
$stmt->execute([$order_id]);
|
||||
|
||||
$pdo->commit();
|
||||
$success_message = 'Order has been marked as completed. Thank you for your purchase!';
|
||||
|
||||
// Redirect to order view page after a short delay
|
||||
header("Refresh: 2; URL=/unimarket/customer/orders/view.php?order_id=" . $order_id);
|
||||
} catch (Exception $e) {
|
||||
$pdo->rollBack();
|
||||
$error_message = 'An error occurred while completing the order. Please try again.';
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Complete Order - UniMarket</title>
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/style.css">
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/responsive.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||
<style>
|
||||
.complete-order-container {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.order-card {
|
||||
background-color: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
padding: 20px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.order-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.pickup-info {
|
||||
margin: 20px 0;
|
||||
padding: 15px;
|
||||
background-color: #f8f9fa;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.pickup-info h3 {
|
||||
margin-bottom: 10px;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.pickup-info p {
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.complete-form {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.btn-complete {
|
||||
background-color: var(--primary-color);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 12px 20px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 1rem;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
.btn-complete:hover {
|
||||
background-color: var(--primary-dark);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<?php include '../../includes/header.php'; ?>
|
||||
|
||||
<div class="container complete-order-container">
|
||||
<a href="/unimarket/customer/orders/view.php?order_id=<?php echo $order_id; ?>" class="back-link">
|
||||
<i class="fas fa-arrow-left"></i> Back to Order Details
|
||||
</a>
|
||||
|
||||
<h1>Complete Order</h1>
|
||||
|
||||
<?php if ($success_message): ?>
|
||||
<div class="alert alert-success"><?php echo $success_message; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($error_message): ?>
|
||||
<div class="alert alert-error"><?php echo $error_message; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="order-card">
|
||||
<div class="order-header">
|
||||
<h2>Order #<?php echo $order['order_id']; ?></h2>
|
||||
<span class="order-status status-ready">Ready for Pickup</span>
|
||||
</div>
|
||||
|
||||
<div class="pickup-info">
|
||||
<h3><i class="fas fa-info-circle"></i> Pickup Information</h3>
|
||||
<p><strong>Scheduled Pickup:</strong> <?php echo date('F j, Y g:i A', strtotime($order['pickup_schedule'])); ?></p>
|
||||
<p><strong>Payment Method:</strong> Pay on Pickup</p>
|
||||
<p><strong>Instructions:</strong> Please bring your university ID for verification when picking up your order.</p>
|
||||
</div>
|
||||
|
||||
<form method="POST" class="complete-form">
|
||||
<p>Click the button below to mark this order as completed after you have picked up your items and made the payment.</p>
|
||||
<button type="submit" name="complete_order" class="btn-complete">
|
||||
<i class="fas fa-check-circle"></i> Mark Order as Completed
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include '../../includes/footer.php'; ?>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,281 @@
|
||||
<?php
|
||||
require_once '../../includes/auth_functions.php';
|
||||
redirectIfNotLoggedIn();
|
||||
redirectIfNotCustomer();
|
||||
|
||||
require_once '../../config/database.php';
|
||||
|
||||
// Pagination variables
|
||||
$current_page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
|
||||
$per_page = 10;
|
||||
$offset = ($current_page - 1) * $per_page;
|
||||
|
||||
// Add cache control headers
|
||||
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
|
||||
header("Cache-Control: post-check=0, pre-check=0", false);
|
||||
header("Pragma: no-cache");
|
||||
|
||||
// Get total orders count
|
||||
$count_stmt = $pdo->prepare("SELECT COUNT(*) FROM orders WHERE customer_id = ? AND status != 'deleted'");
|
||||
$count_stmt->execute([$_SESSION['user_id']]);
|
||||
$total_orders = $count_stmt->fetchColumn();
|
||||
|
||||
// Get orders with pagination
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT o.order_id, o.order_date, o.total_amount, o.status, o.pickup_schedule
|
||||
FROM orders o
|
||||
WHERE o.customer_id = ? AND o.status != 'deleted'
|
||||
ORDER BY o.order_date DESC
|
||||
LIMIT ? OFFSET ?
|
||||
");
|
||||
$stmt->bindValue(1, $_SESSION['user_id'], PDO::PARAM_INT);
|
||||
$stmt->bindValue(2, $per_page, PDO::PARAM_INT);
|
||||
$stmt->bindValue(3, $offset, PDO::PARAM_INT);
|
||||
$stmt->execute();
|
||||
$orders = $stmt->fetchAll();
|
||||
|
||||
// Debug information
|
||||
error_log("User ID: " . $_SESSION['user_id']);
|
||||
error_log("Total Orders: " . $total_orders);
|
||||
foreach ($orders as $order) {
|
||||
error_log("Order ID: " . $order['order_id'] . ", Status: " . $order['status']);
|
||||
}
|
||||
|
||||
// Calculate total pages
|
||||
$total_pages = ceil($total_orders / $per_page);
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>My Orders - UniMarket</title>
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/style.css">
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/responsive.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||
<style>
|
||||
.back-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 16px;
|
||||
background-color: #f8f9fa;
|
||||
border: 1px solid #e9ecef;
|
||||
border-radius: 6px;
|
||||
color: #2e7d32;
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
margin-bottom: 20px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.back-link:hover {
|
||||
background-color: #e9ecef;
|
||||
color: #1b5e20;
|
||||
text-decoration: none;
|
||||
transform: translateX(-2px);
|
||||
}
|
||||
|
||||
.back-link i {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.orders-container {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.orders-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.orders-table th, .orders-table td {
|
||||
padding: 12px 15px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.orders-table th {
|
||||
background-color: #f5f5f5;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.order-status {
|
||||
display: inline-block;
|
||||
padding: 5px 10px;
|
||||
border-radius: 4px;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.status-pending {
|
||||
background-color: #fff3cd;
|
||||
color: #856404;
|
||||
}
|
||||
|
||||
.status-processing {
|
||||
background-color: #cce5ff;
|
||||
color: #004085;
|
||||
}
|
||||
|
||||
.status-ready {
|
||||
background-color: #d4edda;
|
||||
color: #155724;
|
||||
}
|
||||
|
||||
.status-completed {
|
||||
background-color: #e2e3e5;
|
||||
color: #383d41;
|
||||
}
|
||||
|
||||
.status-cancelled {
|
||||
background-color: #f8d7da;
|
||||
color: #721c24;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 30px;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.pagination a, .pagination span {
|
||||
display: inline-block;
|
||||
padding: 8px 15px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
text-decoration: none;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.pagination a:hover {
|
||||
background-color: var(--primary-color);
|
||||
color: white;
|
||||
border-color: var(--primary-color);
|
||||
}
|
||||
|
||||
.pagination .current {
|
||||
background-color: var(--primary-color);
|
||||
color: white;
|
||||
border-color: var(--primary-color);
|
||||
}
|
||||
|
||||
.empty-orders {
|
||||
text-align: center;
|
||||
padding: 50px;
|
||||
background-color: #f9f9f9;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.orders-table {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<?php include '../../includes/header.php'; ?>
|
||||
|
||||
<div class="container orders-container">
|
||||
<a href="/unimarket/customer/profile.php" class="back-link">
|
||||
<i class="fas fa-arrow-left"></i> Back to Profile
|
||||
</a>
|
||||
<h1>My Orders</h1>
|
||||
|
||||
<?php if (empty($orders)): ?>
|
||||
<div class="empty-orders card">
|
||||
<i class="fas fa-box-open" style="font-size: 3em; color: #ccc; margin-bottom: 20px;"></i>
|
||||
<h3>You haven't placed any orders yet</h3>
|
||||
<p>Start shopping to see your orders here</p>
|
||||
<a href="/unimarket/customer/products/browse.php" class="btn">Browse Products</a>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<table class="orders-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Order #</th>
|
||||
<th>Date</th>
|
||||
<th>Total</th>
|
||||
<th>Status</th>
|
||||
<th>Pickup Schedule</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($orders as $order): ?>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="/unimarket/customer/orders/view.php?order_id=<?php echo $order['order_id']; ?>">
|
||||
#<?php echo $order['order_id']; ?>
|
||||
</a>
|
||||
</td>
|
||||
<td><?php echo date('M j, Y', strtotime($order['order_date'])); ?></td>
|
||||
<td>$<?php echo number_format($order['total_amount'], 2); ?></td>
|
||||
<td>
|
||||
<?php
|
||||
$status_class = '';
|
||||
switch ($order['status']) {
|
||||
case 'pending':
|
||||
$status_class = 'status-pending';
|
||||
break;
|
||||
case 'processing':
|
||||
$status_class = 'status-processing';
|
||||
break;
|
||||
case 'ready_for_pickup':
|
||||
$status_class = 'status-ready';
|
||||
break;
|
||||
case 'completed':
|
||||
$status_class = 'status-completed';
|
||||
break;
|
||||
case 'cancelled':
|
||||
$status_class = 'status-cancelled';
|
||||
break;
|
||||
}
|
||||
?>
|
||||
<span class="order-status <?php echo $status_class; ?>">
|
||||
<?php echo ucfirst(str_replace('_', ' ', $order['status'])); ?>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ($order['pickup_schedule']): ?>
|
||||
<?php echo date('M j, Y g:i A', strtotime($order['pickup_schedule'])); ?>
|
||||
<?php else: ?>
|
||||
Not scheduled
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<?php if ($total_pages > 1): ?>
|
||||
<div class="pagination">
|
||||
<?php if ($current_page > 1): ?>
|
||||
<a href="?page=1">First</a>
|
||||
<a href="?page=<?php echo $current_page - 1; ?>">Prev</a>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php for ($i = max(1, $current_page - 2); $i <= min($current_page + 2, $total_pages); $i++): ?>
|
||||
<?php if ($i == $current_page): ?>
|
||||
<span class="current"><?php echo $i; ?></span>
|
||||
<?php else: ?>
|
||||
<a href="?page=<?php echo $i; ?>"><?php echo $i; ?></a>
|
||||
<?php endif; ?>
|
||||
<?php endfor; ?>
|
||||
|
||||
<?php if ($current_page < $total_pages): ?>
|
||||
<a href="?page=<?php echo $current_page + 1; ?>">Next</a>
|
||||
<a href="?page=<?php echo $total_pages; ?>">Last</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php include '../../includes/footer.php'; ?>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,533 @@
|
||||
<?php
|
||||
require_once '../../includes/auth_functions.php';
|
||||
redirectIfNotLoggedIn();
|
||||
redirectIfNotCustomer();
|
||||
|
||||
require_once '../../config/database.php';
|
||||
|
||||
// Get order ID from URL
|
||||
if (!isset($_GET['order_id'])) {
|
||||
header("Location: /unimarket/customer/orders/list.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
$order_id = (int)$_GET['order_id'];
|
||||
|
||||
// Get order details first
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT o.*, u.username, u.first_name, u.last_name, u.email
|
||||
FROM orders o
|
||||
JOIN users u ON o.customer_id = u.user_id
|
||||
WHERE o.order_id = ?
|
||||
");
|
||||
$stmt->execute([$order_id]);
|
||||
$order = $stmt->fetch();
|
||||
|
||||
// Verify order belongs to current user
|
||||
if (!$order || $order['customer_id'] != $_SESSION['user_id']) {
|
||||
header("Location: /unimarket/customer/orders/list.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
// Handle pickup confirmation and cancellation
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
if (isset($_POST['confirm_pickup'])) {
|
||||
try {
|
||||
$stmt = $pdo->prepare("UPDATE orders SET status = 'completed' WHERE order_id = ? AND customer_id = ? AND status = 'ready'");
|
||||
$stmt->execute([$order_id, $_SESSION['user_id']]);
|
||||
|
||||
// Refresh order data
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT o.order_id, o.order_date, o.total_amount, o.status, o.pickup_schedule
|
||||
FROM orders o
|
||||
WHERE o.order_id = ?
|
||||
");
|
||||
$stmt->execute([$order_id]);
|
||||
$order = $stmt->fetch();
|
||||
|
||||
$success_message = 'Order pickup confirmed! Thank you for your purchase.';
|
||||
} catch (PDOException $e) {
|
||||
$error_message = 'Failed to confirm pickup. Please try again.';
|
||||
}
|
||||
} elseif (isset($_POST['cancel_order'])) {
|
||||
try {
|
||||
// Only allow cancellation if order is not completed or cancelled
|
||||
if ($order['status'] !== 'completed' && $order['status'] !== 'cancelled') {
|
||||
$stmt = $pdo->prepare("UPDATE orders SET status = 'cancelled' WHERE order_id = ? AND customer_id = ?");
|
||||
$stmt->execute([$order_id, $_SESSION['user_id']]);
|
||||
|
||||
// Refresh order data
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT o.order_id, o.order_date, o.total_amount, o.status, o.pickup_schedule
|
||||
FROM orders o
|
||||
WHERE o.order_id = ?
|
||||
");
|
||||
$stmt->execute([$order_id]);
|
||||
$order = $stmt->fetch();
|
||||
|
||||
$success_message = 'Order has been cancelled successfully.';
|
||||
} else {
|
||||
$error_message = 'This order cannot be cancelled.';
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$error_message = 'Failed to cancel order. Please try again.';
|
||||
}
|
||||
} elseif (isset($_POST['delete_order'])) {
|
||||
try {
|
||||
// Start transaction
|
||||
$pdo->beginTransaction();
|
||||
|
||||
// Update order status to deleted
|
||||
$stmt = $pdo->prepare("UPDATE orders SET status = 'deleted' WHERE order_id = ? AND customer_id = ?");
|
||||
$stmt->execute([$order_id, $_SESSION['user_id']]);
|
||||
|
||||
// Log the deletion
|
||||
error_log("Deleting order ID: " . $order_id . " for user ID: " . $_SESSION['user_id']);
|
||||
|
||||
// Commit transaction
|
||||
$pdo->commit();
|
||||
|
||||
// Redirect to orders list
|
||||
header("Location: /unimarket/customer/orders/list.php");
|
||||
exit();
|
||||
} catch (PDOException $e) {
|
||||
// Rollback transaction on error
|
||||
$pdo->rollBack();
|
||||
error_log("Error deleting order: " . $e->getMessage());
|
||||
$error_message = 'Failed to delete order. Please try again.';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get order items with seller information
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT oi.*, p.name, p.image_path, p.price,
|
||||
u.username as seller_username, u.first_name as seller_first_name, u.last_name as seller_last_name
|
||||
FROM order_items oi
|
||||
JOIN products p ON oi.product_id = p.product_id
|
||||
JOIN users u ON p.owner_id = u.user_id
|
||||
WHERE oi.order_id = ?
|
||||
");
|
||||
$stmt->execute([$order_id]);
|
||||
$order_items = $stmt->fetchAll();
|
||||
|
||||
// Calculate total items
|
||||
$total_items = array_sum(array_column($order_items, 'quantity'));
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Order Details - UniMarket</title>
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/style.css">
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/responsive.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||
<style>
|
||||
header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 1000;
|
||||
background: rgba(46, 125, 50, 0.95);
|
||||
backdrop-filter: blur(10px);
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.order-details-container {
|
||||
margin-top: 100px; /* Add margin to prevent content from hiding under fixed header */
|
||||
}
|
||||
|
||||
.order-details-container {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.order-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.order-info {
|
||||
background-color: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
padding: 20px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.info-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
background-color: #f8f9fa;
|
||||
padding: 15px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
font-size: 0.9rem;
|
||||
color: #666;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.order-status {
|
||||
display: inline-block;
|
||||
padding: 8px 15px;
|
||||
border-radius: 4px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.status-pending {
|
||||
background-color: #fff3cd;
|
||||
color: #856404;
|
||||
}
|
||||
|
||||
.status-processing {
|
||||
background-color: #cce5ff;
|
||||
color: #004085;
|
||||
}
|
||||
|
||||
.status-ready {
|
||||
background-color: #d4edda;
|
||||
color: #155724;
|
||||
}
|
||||
|
||||
.status-completed {
|
||||
background-color: #e2e3e5;
|
||||
color: #383d41;
|
||||
}
|
||||
|
||||
.status-cancelled {
|
||||
background-color: #f8d7da;
|
||||
color: #721c24;
|
||||
}
|
||||
|
||||
.order-items {
|
||||
background-color: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.items-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.items-table th, .items-table td {
|
||||
padding: 12px 15px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.items-table th {
|
||||
background-color: #f5f5f5;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.product-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.product-image {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
background-color: #f8f9fa;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.product-image img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.product-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.product-name {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.order-total {
|
||||
text-align: right;
|
||||
margin-top: 20px;
|
||||
font-size: 1.2rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.back-link {
|
||||
display: inline-block;
|
||||
margin-bottom: 20px;
|
||||
color: var(--primary-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.back-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.pickup-confirmation-form {
|
||||
margin-top: 20px;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
|
||||
.confirm-pickup-btn {
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
padding: 12px 24px;
|
||||
font-size: 1.1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.confirm-pickup-btn:hover {
|
||||
background-color: #218838;
|
||||
}
|
||||
|
||||
.confirm-pickup-btn i {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.order-actions {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.cancel-order-form {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.cancel-order-btn {
|
||||
background-color: #dc3545;
|
||||
color: white;
|
||||
padding: 12px 24px;
|
||||
font-size: 1.1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.cancel-order-btn:hover {
|
||||
background-color: #c82333;
|
||||
}
|
||||
|
||||
.cancel-order-btn i {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.seller-username {
|
||||
font-size: 0.9rem;
|
||||
color: #666;
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.info-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.items-table {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.product-cell {
|
||||
min-width: 200px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<?php include '../../includes/header.php'; ?>
|
||||
|
||||
<div class="container order-details-container">
|
||||
<a href="/unimarket/customer/profile.php" class="back-link">
|
||||
<i class="fas fa-arrow-left"></i> Back to Profile
|
||||
</a>
|
||||
|
||||
<div class="order-header">
|
||||
<h1>Order #<?php echo $order['order_id']; ?></h1>
|
||||
<?php
|
||||
$status_class = '';
|
||||
switch ($order['status']) {
|
||||
case 'pending':
|
||||
$status_class = 'status-pending';
|
||||
break;
|
||||
case 'processing':
|
||||
$status_class = 'status-processing';
|
||||
break;
|
||||
case 'ready':
|
||||
$status_class = 'status-ready';
|
||||
break;
|
||||
case 'completed':
|
||||
$status_class = 'status-completed';
|
||||
break;
|
||||
case 'cancelled':
|
||||
$status_class = 'status-cancelled';
|
||||
break;
|
||||
}
|
||||
?>
|
||||
<span class="order-status <?php echo $status_class; ?>">
|
||||
<?php echo ucfirst(str_replace('_', ' ', $order['status'])); ?>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="order-info card">
|
||||
<h2>Order Information</h2>
|
||||
<div class="info-grid">
|
||||
<div class="info-item">
|
||||
<div class="info-label">Order Number</div>
|
||||
<div class="info-value">#<?php echo $order['order_id']; ?></div>
|
||||
</div>
|
||||
|
||||
<div class="info-item">
|
||||
<div class="info-label">Order Date</div>
|
||||
<div class="info-value"><?php echo date('F j, Y g:i A', strtotime($order['order_date'])); ?></div>
|
||||
</div>
|
||||
|
||||
<div class="info-item">
|
||||
<div class="info-label">Order Status</div>
|
||||
<div class="info-value">
|
||||
<span class="order-status <?php echo $status_class; ?>">
|
||||
<?php echo ucfirst(str_replace('_', ' ', $order['status'])); ?>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-item">
|
||||
<div class="info-label">Total Items</div>
|
||||
<div class="info-value"><?php echo $total_items; ?> items</div>
|
||||
</div>
|
||||
|
||||
<div class="info-item">
|
||||
<div class="info-label">Total Amount</div>
|
||||
<div class="info-value">₱<?php echo number_format($order['total_amount'], 2); ?></div>
|
||||
</div>
|
||||
|
||||
<div class="info-item">
|
||||
<div class="info-label">Payment Method</div>
|
||||
<div class="info-value">Pay on Pickup</div>
|
||||
</div>
|
||||
|
||||
<div class="info-item">
|
||||
<div class="info-label">Pickup Schedule</div>
|
||||
<div class="info-value">
|
||||
<?php if ($order['pickup_schedule']): ?>
|
||||
<?php echo date('F j, Y g:i A', strtotime($order['pickup_schedule'])); ?>
|
||||
<?php else: ?>
|
||||
<span style="color: #666;">Waiting for seller to schedule pickup time</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="order-actions">
|
||||
<?php if ($order['status'] === 'ready'): ?>
|
||||
<form method="POST" class="pickup-confirmation-form" onsubmit="return confirm('Have you received your items and completed the payment?');">
|
||||
<button type="submit" name="confirm_pickup" class="btn confirm-pickup-btn">
|
||||
<i class="fas fa-check-circle"></i> Confirm Pickup
|
||||
</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($order['status'] !== 'completed' && $order['status'] !== 'cancelled'): ?>
|
||||
<form method="POST" class="cancel-order-form" onsubmit="return confirm('Are you sure you want to cancel this order? This action cannot be undone.');">
|
||||
<button type="submit" name="cancel_order" class="btn cancel-order-btn">
|
||||
<i class="fas fa-times-circle"></i> Cancel Order
|
||||
</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="order-items card">
|
||||
<h2>Order Items</h2>
|
||||
<table class="items-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Product</th>
|
||||
<th>Seller</th>
|
||||
<th>Price</th>
|
||||
<th>Quantity</th>
|
||||
<th>Subtotal</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($order_items as $item): ?>
|
||||
<tr>
|
||||
<td class="product-cell">
|
||||
<?php if ($item['image_path']): ?>
|
||||
<div class="product-image">
|
||||
<img src="/unimarket/assets/images/products/<?php echo htmlspecialchars($item['image_path']); ?>"
|
||||
alt="<?php echo htmlspecialchars($item['name']); ?>">
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="product-image">
|
||||
<i class="fas fa-box"></i>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="product-info">
|
||||
<div class="product-name"><?php echo htmlspecialchars($item['name']); ?></div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<?php echo htmlspecialchars($item['seller_first_name'] . ' ' . $item['seller_last_name']); ?>
|
||||
<div class="seller-username">@<?php echo htmlspecialchars($item['seller_username']); ?></div>
|
||||
</td>
|
||||
<td>₱<?php echo number_format($item['price'], 2); ?></td>
|
||||
<td><?php echo $item['quantity']; ?></td>
|
||||
<td>₱<?php echo number_format($item['price'] * $item['quantity'], 2); ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="order-total">
|
||||
<div style="margin-bottom: 10px;">Subtotal: ₱<?php echo number_format($order['total_amount'], 2); ?></div>
|
||||
<div style="margin-bottom: 10px;">Shipping: Free</div>
|
||||
<div style="font-size: 1.4rem;">Total: ₱<?php echo number_format($order['total_amount'], 2); ?></div>
|
||||
</div>
|
||||
|
||||
<?php if ($order['status'] === 'completed' || $order['status'] === 'cancelled'): ?>
|
||||
<form method="POST" style="margin-top: 20px; text-align: right;">
|
||||
<button type="submit" name="delete_order" class="btn btn-danger" onclick="return confirm('Are you sure you want to delete this order? This action cannot be undone.')">
|
||||
<i class="fas fa-trash"></i> Delete Order
|
||||
</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include '../../includes/footer.php'; ?>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,335 @@
|
||||
<?php
|
||||
require_once '../../includes/auth_functions.php';
|
||||
redirectIfNotLoggedIn();
|
||||
redirectIfNotCustomer();
|
||||
|
||||
require_once '../../config/database.php';
|
||||
|
||||
// Pagination variables
|
||||
$current_page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
|
||||
$per_page = 12;
|
||||
$offset = ($current_page - 1) * $per_page;
|
||||
|
||||
// Search and filter variables
|
||||
$search_query = isset($_GET['search']) ? trim($_GET['search']) : '';
|
||||
$category_filter = isset($_GET['category']) ? trim($_GET['category']) : '';
|
||||
|
||||
// Base query
|
||||
$query = "SELECT * FROM products WHERE stock_quantity > 0";
|
||||
$count_query = "SELECT COUNT(*) FROM products WHERE stock_quantity > 0";
|
||||
$params = [];
|
||||
|
||||
// Add search condition
|
||||
if (!empty($search_query)) {
|
||||
$query .= " AND (name LIKE ? OR description LIKE ?)";
|
||||
$count_query .= " AND (name LIKE ? OR description LIKE ?)";
|
||||
$search_param = "%$search_query%";
|
||||
array_push($params, $search_param, $search_param);
|
||||
}
|
||||
|
||||
// Add category filter
|
||||
if (!empty($category_filter)) {
|
||||
$query .= " AND category = ?";
|
||||
$count_query .= " AND category = ?";
|
||||
array_push($params, $category_filter);
|
||||
}
|
||||
|
||||
// Add sorting
|
||||
$sort = isset($_GET['sort']) ? $_GET['sort'] : 'newest';
|
||||
switch ($sort) {
|
||||
case 'price_low':
|
||||
$query .= " ORDER BY price ASC";
|
||||
break;
|
||||
case 'price_high':
|
||||
$query .= " ORDER BY price DESC";
|
||||
break;
|
||||
case 'name':
|
||||
$query .= " ORDER BY name ASC";
|
||||
break;
|
||||
default:
|
||||
$query .= " ORDER BY created_at DESC";
|
||||
break;
|
||||
}
|
||||
|
||||
// Add pagination
|
||||
$query .= " LIMIT ? OFFSET ?";
|
||||
array_push($params, $per_page, $offset);
|
||||
|
||||
// Prepare and execute the query
|
||||
$stmt = $pdo->prepare($query);
|
||||
foreach ($params as $key => $value) {
|
||||
$paramType = is_int($value) ? PDO::PARAM_INT : PDO::PARAM_STR;
|
||||
$stmt->bindValue($key + 1, $value, $paramType);
|
||||
}
|
||||
$stmt->execute();
|
||||
$products = $stmt->fetchAll();
|
||||
|
||||
// Get total count for pagination
|
||||
$count_stmt = $pdo->prepare($count_query);
|
||||
foreach (array_slice($params, 0, count($params) - 2) as $key => $value) {
|
||||
$paramType = is_int($value) ? PDO::PARAM_INT : PDO::PARAM_STR;
|
||||
$count_stmt->bindValue($key + 1, $value, $paramType);
|
||||
}
|
||||
$count_stmt->execute();
|
||||
$total_products = $count_stmt->fetchColumn();
|
||||
|
||||
// Get all categories for filter dropdown
|
||||
$categories = $pdo->query("SELECT DISTINCT category FROM products WHERE category IS NOT NULL AND category != '' ORDER BY category")->fetchAll();
|
||||
|
||||
// Calculate total pages
|
||||
$total_pages = ceil($total_products / $per_page);
|
||||
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Browse Products - UniMarket</title>
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/style.css">
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/responsive.css">
|
||||
<style>
|
||||
.browse-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.search-filter-container {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
margin-bottom: 15px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.search-box {
|
||||
flex: 1;
|
||||
min-width: 250px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.search-box input {
|
||||
width: 100%;
|
||||
padding: 10px 15px;
|
||||
padding-right: 40px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.search-box button {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.filter-dropdown {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.filter-dropdown select {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.sort-dropdown {
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 30px;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.pagination a, .pagination span {
|
||||
display: inline-block;
|
||||
padding: 8px 15px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
text-decoration: none;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.pagination a:hover {
|
||||
background-color: var(--primary-color);
|
||||
color: white;
|
||||
border-color: var(--primary-color);
|
||||
}
|
||||
|
||||
.pagination .current {
|
||||
background-color: var(--primary-color);
|
||||
color: white;
|
||||
border-color: var(--primary-color);
|
||||
}
|
||||
|
||||
.no-products {
|
||||
text-align: center;
|
||||
padding: 40px;
|
||||
background-color: #f9f9f9;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.product-card .stock-info {
|
||||
color: #666;
|
||||
font-size: 0.9rem;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.product-card .stock-low {
|
||||
color: #e53935;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<?php include '../../includes/header.php'; ?>
|
||||
|
||||
<div class="container">
|
||||
<div class="browse-header">
|
||||
<h1>Browse Products</h1>
|
||||
<div class="search-filter-container">
|
||||
<form method="GET" class="search-box">
|
||||
<input type="text" name="search" placeholder="Search products..." value="<?php echo htmlspecialchars($search_query); ?>">
|
||||
<button type="submit"><i class="fas fa-search"></i></button>
|
||||
</form>
|
||||
|
||||
<div class="filter-dropdown">
|
||||
<select name="category" onchange="this.form.submit()" form="filter-form">
|
||||
<option value="">All Categories</option>
|
||||
<?php foreach ($categories as $category): ?>
|
||||
<option value="<?php echo htmlspecialchars($category['category']); ?>" <?php echo $category_filter === $category['category'] ? 'selected' : ''; ?>>
|
||||
<?php echo htmlspecialchars($category['category']); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="sort-dropdown">
|
||||
<select name="sort" onchange="this.form.submit()" form="filter-form">
|
||||
<option value="newest" <?php echo $sort === 'newest' ? 'selected' : ''; ?>>Newest First</option>
|
||||
<option value="price_low" <?php echo $sort === 'price_low' ? 'selected' : ''; ?>>Price: Low to High</option>
|
||||
<option value="price_high" <?php echo $sort === 'price_high' ? 'selected' : ''; ?>>Price: High to Low</option>
|
||||
<option value="name" <?php echo $sort === 'name' ? 'selected' : ''; ?>>Name: A-Z</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<form id="filter-form" method="GET" style="display: none;">
|
||||
<input type="hidden" name="search" value="<?php echo htmlspecialchars($search_query); ?>">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if (empty($products)): ?>
|
||||
<div class="no-products card">
|
||||
<h3>No products found</h3>
|
||||
<p>Try adjusting your search or filter criteria</p>
|
||||
<a href="/unimarket/customer/products/browse.php" class="btn">Reset Filters</a>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="product-grid">
|
||||
<?php foreach ($products as $product): ?>
|
||||
<div class="product-card card">
|
||||
<a style="color: black; text-decoration: none;" href="/unimarket/customer/products/view.php?id=<?php echo $product['product_id']; ?>">
|
||||
<div class="product-image">
|
||||
<?php if ($product['image_path']): ?>
|
||||
<img src="/unimarket/uploads/products/<?php echo $product['image_path']; ?>" alt="<?php echo htmlspecialchars($product['name']); ?>">
|
||||
<?php else: ?>
|
||||
<div style="display: flex; align-items: center; justify-content: center; height: 100%; color: #999;">
|
||||
<i class="fas fa-box-open" style="font-size: 3rem;"></i>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="product-info">
|
||||
<h3 class="product-title"><?php echo htmlspecialchars($product['name']); ?></h3>
|
||||
<p class="product-price">₱<?php echo number_format($product['price'], 2); ?></p>
|
||||
<p class="stock-info <?php echo $product['stock_quantity'] < 5 ? 'stock-low' : ''; ?>">
|
||||
<?php echo $product['stock_quantity'] < 5 ? 'Only ' . $product['stock_quantity'] . ' left!' : 'In stock'; ?>
|
||||
</p>
|
||||
<a href="/unimarket/customer/products/view.php?id=<?php echo $product['product_id']; ?>" class="btn">
|
||||
<i class="fas fa-eye"></i> View Details
|
||||
</a>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<?php if ($total_pages > 1): ?>
|
||||
<div class="pagination">
|
||||
<?php if ($current_page > 1): ?>
|
||||
<a href="?<?php echo buildQueryString(['page' => 1]); ?>">First</a>
|
||||
<a href="?<?php echo buildQueryString(['page' => $current_page - 1]); ?>">Prev</a>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php for ($i = max(1, $current_page - 2); $i <= min($current_page + 2, $total_pages); $i++): ?>
|
||||
<?php if ($i == $current_page): ?>
|
||||
<span class="current"><?php echo $i; ?></span>
|
||||
<?php else: ?>
|
||||
<a href="?<?php echo buildQueryString(['page' => $i]); ?>"><?php echo $i; ?></a>
|
||||
<?php endif; ?>
|
||||
<?php endfor; ?>
|
||||
|
||||
<?php if ($current_page < $total_pages): ?>
|
||||
<a href="?<?php echo buildQueryString(['page' => $current_page + 1]); ?>">Next</a>
|
||||
<a href="?<?php echo buildQueryString(['page' => $total_pages]); ?>">Last</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php include '../../includes/footer.php'; ?>
|
||||
|
||||
<script>
|
||||
// Add to cart with quantity validation
|
||||
document.querySelectorAll('form[action="/unimarket/customer/cart.php"]').forEach(form => {
|
||||
form.addEventListener('submit', function(e) {
|
||||
const quantityInput = this.querySelector('input[name="quantity"]');
|
||||
const max = parseInt(quantityInput.getAttribute('max'));
|
||||
const value = parseInt(quantityInput.value);
|
||||
|
||||
if (value < 1) {
|
||||
e.preventDefault();
|
||||
alert('Quantity must be at least 1');
|
||||
quantityInput.focus();
|
||||
} else if (value > max) {
|
||||
e.preventDefault();
|
||||
alert(`Only ${max} available in stock`);
|
||||
quantityInput.focus();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Helper function to build query string from current URL parameters
|
||||
function buildQueryString(params) {
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
for (const key in params) {
|
||||
if (params[key] !== undefined) {
|
||||
searchParams.set(key, params[key]);
|
||||
}
|
||||
}
|
||||
return searchParams.toString();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<?php
|
||||
/**
|
||||
* Helper function to build query string while preserving existing parameters
|
||||
*/
|
||||
function buildQueryString($new_params) {
|
||||
$params = array_merge($_GET, $new_params);
|
||||
return http_build_query($params);
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,546 @@
|
||||
<?php
|
||||
require_once '../../includes/auth_functions.php';
|
||||
redirectIfNotLoggedIn();
|
||||
redirectIfNotCustomer();
|
||||
|
||||
require_once '../../config/database.php';
|
||||
|
||||
// Check if product ID is provided
|
||||
if (!isset($_GET['id'])) {
|
||||
header("Location: /unimarket/customer/products/browse.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
$product_id = (int)$_GET['id'];
|
||||
|
||||
// Get product details
|
||||
$stmt = $pdo->prepare("SELECT p.*, u.username as seller_name
|
||||
FROM products p
|
||||
JOIN users u ON p.owner_id = u.user_id
|
||||
WHERE p.product_id = ? AND p.stock_quantity > 0");
|
||||
$stmt->execute([$product_id]);
|
||||
$product = $stmt->fetch();
|
||||
|
||||
if (!$product) {
|
||||
header("Location: /unimarket/customer/products/browse.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
// Handle add to cart
|
||||
$error_message = '';
|
||||
$success_message = '';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_to_cart'])) {
|
||||
$quantity = (int)$_POST['quantity'];
|
||||
|
||||
if ($quantity < 1) {
|
||||
$error_message = 'Quantity must be at least 1.';
|
||||
} elseif ($quantity > $product['stock_quantity']) {
|
||||
$error_message = "Only {$product['stock_quantity']} available in stock.";
|
||||
} else {
|
||||
try {
|
||||
// Get or create cart for user
|
||||
$stmt = $pdo->prepare("SELECT cart_id FROM cart WHERE user_id = ?");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
$cart = $stmt->fetch();
|
||||
|
||||
if (!$cart) {
|
||||
$stmt = $pdo->prepare("INSERT INTO cart (user_id) VALUES (?)");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
$cart_id = $pdo->lastInsertId();
|
||||
} else {
|
||||
$cart_id = $cart['cart_id'];
|
||||
}
|
||||
|
||||
// Check if product already in cart
|
||||
$stmt = $pdo->prepare("SELECT * FROM cart_items WHERE cart_id = ? AND product_id = ?");
|
||||
$stmt->execute([$cart_id, $product_id]);
|
||||
$existing_item = $stmt->fetch();
|
||||
|
||||
if ($existing_item) {
|
||||
// Update quantity if already in cart
|
||||
$new_quantity = $existing_item['quantity'] + $quantity;
|
||||
if ($new_quantity > $product['stock_quantity']) {
|
||||
$error_message = "Cannot add more than available stock.";
|
||||
} else {
|
||||
$stmt = $pdo->prepare("UPDATE cart_items SET quantity = ? WHERE cart_item_id = ?");
|
||||
$stmt->execute([$new_quantity, $existing_item['cart_item_id']]);
|
||||
$success_message = 'Product quantity updated in cart!';
|
||||
}
|
||||
} else {
|
||||
// Add new item to cart
|
||||
$stmt = $pdo->prepare("INSERT INTO cart_items (cart_id, product_id, quantity) VALUES (?, ?, ?)");
|
||||
$stmt->execute([$cart_id, $product_id, $quantity]);
|
||||
$success_message = 'Product added to cart!';
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$error_message = 'Failed to add product to cart. Please try again.';
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title><?php echo htmlspecialchars($product['name']); ?> - UniMarket</title>
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/style.css">
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/responsive.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||
<script src="/unimarket/assets/js/notifications.js"></script>
|
||||
<style>
|
||||
.product-detail-container {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.product-main {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 30px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.product-main {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.product-gallery {
|
||||
background-color: #f9f9f9;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.product-image {
|
||||
max-width: 100%;
|
||||
max-height: 400px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.product-info {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.product-title {
|
||||
font-size: 2rem;
|
||||
margin-bottom: 10px;
|
||||
color: var(--primary-dark);
|
||||
}
|
||||
|
||||
.product-seller {
|
||||
color: #666;
|
||||
margin-bottom: 20px;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.product-price {
|
||||
font-size: 1.8rem;
|
||||
font-weight: bold;
|
||||
color: var(--primary-color);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.product-stock {
|
||||
margin-bottom: 20px;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.stock-high {
|
||||
color: #2e7d32;
|
||||
}
|
||||
|
||||
.stock-low {
|
||||
color: #e53935;
|
||||
}
|
||||
|
||||
.product-description {
|
||||
margin-bottom: 30px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.add-to-cart-form {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.quantity-input {
|
||||
width: 80px;
|
||||
padding: 10px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.back-link {
|
||||
display: inline-block;
|
||||
margin-bottom: 20px;
|
||||
color: var(--primary-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.back-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.product-meta {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 20px;
|
||||
margin-top: 30px;
|
||||
padding-top: 30px;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
|
||||
.meta-item {
|
||||
background-color: #f5f5f5;
|
||||
padding: 15px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.meta-label {
|
||||
font-weight: 600;
|
||||
color: #666;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.product-sizes {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.size-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
|
||||
gap: 10px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.size-item {
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
padding: 8px;
|
||||
text-align: center;
|
||||
background-color: #f9f9f9;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.size-item.in-stock {
|
||||
border-color: #2e7d32;
|
||||
background-color: #e8f5e9;
|
||||
}
|
||||
|
||||
.size-item.in-stock:hover {
|
||||
background-color: #c8e6c9;
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.size-item.selected {
|
||||
background-color: #2e7d32;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.size-item.out-of-stock {
|
||||
border-color: #c62828;
|
||||
background-color: #ffebee;
|
||||
opacity: 0.7;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.size-label {
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.size-quantity {
|
||||
display: block;
|
||||
font-size: 0.9em;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.size-selection {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.size-selection label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.size-selection select {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
font-size: 1rem;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
/* Add to cart modal styles */
|
||||
.cart-modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 2000;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.cart-modal-content {
|
||||
background: white;
|
||||
padding: 30px;
|
||||
border-radius: 8px;
|
||||
text-align: center;
|
||||
max-width: 400px;
|
||||
width: 90%;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.cart-modal h2 {
|
||||
margin-bottom: 20px;
|
||||
color: var(--primary-dark);
|
||||
}
|
||||
|
||||
.cart-modal-buttons {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 15px;
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
.cart-modal-buttons button {
|
||||
padding: 10px 25px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.cart-modal-buttons .btn-cancel {
|
||||
background: #e0e0e0;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.cart-modal-buttons .btn-cancel:hover {
|
||||
background: #d0d0d0;
|
||||
}
|
||||
|
||||
.cart-modal-buttons .btn-confirm {
|
||||
background: var(--primary-color);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.cart-modal-buttons .btn-confirm:hover {
|
||||
background: var(--primary-dark);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Add to cart modal HTML -->
|
||||
<div class="cart-modal" id="cartModal">
|
||||
<div class="cart-modal-content">
|
||||
<h2>Add to Cart</h2>
|
||||
<p>Are you sure you want to add this item to your cart?</p>
|
||||
<div class="cart-modal-buttons">
|
||||
<button class="btn-cancel" onclick="closeCartModal()">Cancel</button>
|
||||
<button class="btn-confirm" onclick="confirmAddToCart()">Add to Cart</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include '../../includes/header.php'; ?>
|
||||
|
||||
<div class="container product-detail-container">
|
||||
<a href="/unimarket/customer/products/browse.php" class="back-link">
|
||||
<i class="fas fa-arrow-left"></i> Back to Products
|
||||
</a>
|
||||
|
||||
<?php if ($success_message): ?>
|
||||
<div class="alert alert-success"><?php echo $success_message; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($error_message): ?>
|
||||
<div class="alert alert-error"><?php echo $error_message; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="product-main card">
|
||||
<div class="product-gallery">
|
||||
<?php if ($product['image_path']): ?>
|
||||
<img src="/unimarket/uploads/products/<?php echo $product['image_path']; ?>"
|
||||
alt="<?php echo htmlspecialchars($product['name']); ?>"
|
||||
class="product-image">
|
||||
<?php else: ?>
|
||||
<div style="height: 400px; display: flex; align-items: center; justify-content: center;">
|
||||
<i class="fas fa-box-open" style="font-size: 5rem; color: #ccc;"></i>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="product-info">
|
||||
<h1 class="product-title"><?php echo htmlspecialchars($product['name']); ?></h1>
|
||||
<p class="product-seller">Sold by <?php echo htmlspecialchars($product['seller_name']); ?></p>
|
||||
|
||||
<p class="product-price">₱<?php echo number_format($product['price'], 2); ?></p>
|
||||
|
||||
<?php if ($product['category'] === 'clothes' && isset($product['size_data']) && $product['size_data']): ?>
|
||||
<?php
|
||||
$size_data = json_decode($product['size_data'], true);
|
||||
if ($size_data && is_array($size_data)):
|
||||
?>
|
||||
<div class="product-sizes">
|
||||
<h3>Available Sizes</h3>
|
||||
<div class="size-grid">
|
||||
<?php foreach ($size_data as $size => $quantity): ?>
|
||||
<div class="size-item <?php echo $quantity > 0 ? 'in-stock' : 'out-of-stock'; ?>"
|
||||
data-size="<?php echo htmlspecialchars($size); ?>"
|
||||
onclick="<?php echo $quantity > 0 ? 'selectSize(this)' : ''; ?>">
|
||||
<span class="size-label"><?php echo htmlspecialchars($size); ?></span>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<p class="product-stock <?php echo $product['stock_quantity'] < 5 ? 'stock-low' : 'stock-high'; ?>">
|
||||
<?php if ($product['stock_quantity'] < 5): ?>
|
||||
Only <?php echo $product['stock_quantity']; ?> left in stock!
|
||||
<?php else: ?>
|
||||
In stock (<?php echo $product['stock_quantity']; ?> available)
|
||||
<?php endif; ?>
|
||||
</p>
|
||||
|
||||
<div class="product-description">
|
||||
<h3>Description</h3>
|
||||
<p><?php echo nl2br(htmlspecialchars($product['description'])); ?></p>
|
||||
</div>
|
||||
|
||||
<form method="POST" action="../../ajax/add_to_cart.php" class="add-to-cart-form" id="addToCartForm">
|
||||
<input type="hidden" name="product_id" value="<?php echo $product['product_id']; ?>">
|
||||
<?php if ($product['category'] === 'clothes' && isset($product['size_data']) && $product['size_data']): ?>
|
||||
<input type="hidden" name="size" id="selectedSize" required>
|
||||
<?php endif; ?>
|
||||
<input type="number" name="quantity" value="1" min="1" max="<?php echo $product['stock_quantity']; ?>"
|
||||
class="quantity-input">
|
||||
<button type="button" onclick="openCartModal()" class="btn">
|
||||
<i class="fas fa-shopping-cart"></i> Add to Cart
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="product-meta">
|
||||
<div class="meta-item card">
|
||||
<div class="meta-label">Category</div>
|
||||
<div><?php echo $product['category'] ? htmlspecialchars($product['category']) : 'No category specified'; ?></div>
|
||||
</div>
|
||||
|
||||
<div class="meta-item card">
|
||||
<div class="meta-label">Pickup Information</div>
|
||||
<div>Available for on-campus pickup</div>
|
||||
</div>
|
||||
|
||||
<div class="meta-item card">
|
||||
<div class="meta-label">Payment</div>
|
||||
<div>Pay when you pickup</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include '../../includes/footer.php'; ?>
|
||||
|
||||
<script>
|
||||
// Add to cart modal functions
|
||||
function openCartModal() {
|
||||
const form = document.getElementById('addToCartForm');
|
||||
const sizeInput = document.getElementById('selectedSize');
|
||||
|
||||
if (sizeInput && !sizeInput.value) {
|
||||
showToast('Please select a size', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
document.getElementById('cartModal').style.display = 'flex';
|
||||
}
|
||||
|
||||
function closeCartModal() {
|
||||
document.getElementById('cartModal').style.display = 'none';
|
||||
}
|
||||
|
||||
function confirmAddToCart() {
|
||||
const form = document.getElementById('addToCartForm');
|
||||
const formData = new FormData(form);
|
||||
|
||||
fetch(form.action, {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
// Update cart count in header
|
||||
const cartCount = document.querySelector('.cart-count');
|
||||
if (cartCount) {
|
||||
cartCount.textContent = data.cart_count;
|
||||
}
|
||||
// Show success message
|
||||
showToast('Item added to cart successfully!', 'success');
|
||||
closeCartModal();
|
||||
} else {
|
||||
showToast(data.message || 'Failed to add item to cart', 'error');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
showToast('An error occurred while adding to cart', 'error');
|
||||
});
|
||||
}
|
||||
|
||||
// Close modal when clicking outside
|
||||
document.getElementById('cartModal').addEventListener('click', function(e) {
|
||||
if (e.target === this) {
|
||||
closeCartModal();
|
||||
}
|
||||
});
|
||||
|
||||
// Quantity input validation
|
||||
const quantityInput = document.querySelector('.quantity-input');
|
||||
quantityInput.addEventListener('change', function() {
|
||||
const max = parseInt(this.getAttribute('max'));
|
||||
const value = parseInt(this.value);
|
||||
|
||||
if (value < 1) {
|
||||
this.value = 1;
|
||||
} else if (value > max) {
|
||||
this.value = max;
|
||||
alert(`Only ${max} available in stock`);
|
||||
}
|
||||
});
|
||||
|
||||
function selectSize(element) {
|
||||
// Remove selected class from all size items
|
||||
document.querySelectorAll('.size-item').forEach(item => {
|
||||
item.classList.remove('selected');
|
||||
});
|
||||
|
||||
// Add selected class to clicked item
|
||||
element.classList.add('selected');
|
||||
|
||||
// Update hidden input value
|
||||
document.getElementById('selectedSize').value = element.dataset.size;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,848 @@
|
||||
<?php
|
||||
require_once '../includes/auth_functions.php';
|
||||
redirectIfNotLoggedIn();
|
||||
redirectIfNotCustomer();
|
||||
|
||||
require_once '../config/database.php';
|
||||
|
||||
// Initialize variables
|
||||
$success_message = '';
|
||||
$error_message = '';
|
||||
$user = [];
|
||||
$orders = [];
|
||||
|
||||
// Get user details
|
||||
$stmt = $pdo->prepare("SELECT * FROM users WHERE user_id = ?");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
$user = $stmt->fetch();
|
||||
|
||||
// Get recent orders
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT o.order_id, o.order_date, o.total_amount, o.status, o.pickup_schedule
|
||||
FROM orders o
|
||||
WHERE o.customer_id = ?
|
||||
ORDER BY o.order_date DESC
|
||||
LIMIT 5
|
||||
");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
$orders = $stmt->fetchAll();
|
||||
|
||||
// Handle profile updates
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_profile'])) {
|
||||
$first_name = trim($_POST['first_name']);
|
||||
$last_name = trim($_POST['last_name']);
|
||||
$email = trim($_POST['email']);
|
||||
$phone = trim($_POST['phone']);
|
||||
$university_id = trim($_POST['university_id']);
|
||||
|
||||
// Validate inputs
|
||||
if (empty($first_name) || empty($last_name) || empty($email) || empty($university_id)) {
|
||||
$error_message = 'Please fill in all required fields.';
|
||||
} elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
$error_message = 'Please enter a valid email address.';
|
||||
} else {
|
||||
try {
|
||||
// Check if email is already taken by another user
|
||||
$stmt = $pdo->prepare("SELECT user_id FROM users WHERE email = ? AND user_id != ?");
|
||||
$stmt->execute([$email, $_SESSION['user_id']]);
|
||||
|
||||
if ($stmt->fetch()) {
|
||||
$error_message = 'This email is already registered to another account.';
|
||||
} else {
|
||||
// Update profile
|
||||
$stmt = $pdo->prepare("
|
||||
UPDATE users
|
||||
SET first_name = ?, last_name = ?, email = ?, phone = ?, university_id = ?
|
||||
WHERE user_id = ?
|
||||
");
|
||||
$stmt->execute([
|
||||
$first_name,
|
||||
$last_name,
|
||||
$email,
|
||||
$phone,
|
||||
$university_id,
|
||||
$_SESSION['user_id']
|
||||
]);
|
||||
|
||||
$success_message = 'Profile updated successfully!';
|
||||
// Refresh user data
|
||||
$stmt = $pdo->prepare("SELECT * FROM users WHERE user_id = ?");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
$user = $stmt->fetch();
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$error_message = 'An error occurred while updating your profile. Please try again.';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle password changes
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['change_password'])) {
|
||||
$current_password = $_POST['current_password'];
|
||||
$new_password = $_POST['new_password'];
|
||||
$confirm_password = $_POST['confirm_password'];
|
||||
|
||||
if (empty($current_password)) {
|
||||
$error_message = 'Please enter your current password.';
|
||||
} elseif (empty($new_password) || empty($confirm_password)) {
|
||||
$error_message = 'Please enter and confirm your new password.';
|
||||
} elseif ($new_password !== $confirm_password) {
|
||||
$error_message = 'New passwords do not match.';
|
||||
} elseif (strlen($new_password) < 8) {
|
||||
$error_message = 'Password must be at least 8 characters long.';
|
||||
} else {
|
||||
// Verify current password
|
||||
$stmt = $pdo->prepare("SELECT password FROM users WHERE user_id = ?");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
$db_password = $stmt->fetchColumn();
|
||||
|
||||
if (password_verify($current_password, $db_password)) {
|
||||
// Update password
|
||||
$hashed_password = password_hash($new_password, PASSWORD_DEFAULT);
|
||||
$stmt = $pdo->prepare("UPDATE users SET password = ? WHERE user_id = ?");
|
||||
$stmt->execute([$hashed_password, $_SESSION['user_id']]);
|
||||
|
||||
$success_message = 'Password changed successfully!';
|
||||
} else {
|
||||
$error_message = 'Current password is incorrect.';
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>My Profile - UniMarket</title>
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/style.css">
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/responsive.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||
<style>
|
||||
.profile-container {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 30px;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.profile-container {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.profile-section {
|
||||
background-color: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
padding: 25px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 20px;
|
||||
color: var(--primary-color);
|
||||
border-bottom: 2px solid var(--primary-light);
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.profile-info {
|
||||
display: grid;
|
||||
grid-template-columns: 100px 1fr;
|
||||
gap: 15px;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.profile-avatar {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border-radius: 50%;
|
||||
background-color: var(--primary-light);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
|
||||
.profile-details h3 {
|
||||
margin-bottom: 5px;
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
.profile-details p {
|
||||
color: #666;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.form-group input {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.btn-update {
|
||||
display: inline-block;
|
||||
padding: 12px 24px;
|
||||
background: var(--primary-color);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
font-size: 1rem;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s ease;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.btn-update::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(45deg, transparent, rgba(255, 255, 255, 0.1), transparent);
|
||||
transform: translateX(-100%);
|
||||
transition: transform 0.6s ease;
|
||||
}
|
||||
|
||||
.btn-update:hover {
|
||||
background: var(--primary-dark);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(46, 125, 50, 0.2);
|
||||
}
|
||||
|
||||
.btn-update:hover::after {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background-color: #757575;
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background-color: #616161;
|
||||
}
|
||||
|
||||
.orders-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.orders-table th, .orders-table td {
|
||||
padding: 12px 15px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.orders-table th {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.order-status {
|
||||
display: inline-block;
|
||||
padding: 5px 10px;
|
||||
border-radius: 4px;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
#orders-ids{
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#orders-ids:hover{
|
||||
color: green;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.status-pending {
|
||||
background-color: #fff3cd;
|
||||
color: #856404;
|
||||
}
|
||||
|
||||
.status-processing {
|
||||
background-color: #cce5ff;
|
||||
color: #004085;
|
||||
}
|
||||
|
||||
.status-ready {
|
||||
background-color: #d4edda;
|
||||
color: #155724;
|
||||
}
|
||||
|
||||
.status-completed {
|
||||
background-color: #e2e3e5;
|
||||
color: #383d41;
|
||||
}
|
||||
|
||||
.status-cancelled {
|
||||
background-color: #f8d7da;
|
||||
color: #721c24;
|
||||
}
|
||||
|
||||
.view-all {
|
||||
display: block;
|
||||
text-align: right;
|
||||
margin-top: 15px;
|
||||
color: var(--primary-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.view-all:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.password-strength {
|
||||
height: 5px;
|
||||
background-color: #eee;
|
||||
margin-top: 5px;
|
||||
border-radius: 3px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.password-strength-bar {
|
||||
height: 100%;
|
||||
width: 0%;
|
||||
background-color: #ff0000;
|
||||
transition: width 0.3s, background-color 0.3s;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.profile-info {
|
||||
grid-template-columns: 1fr;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.profile-avatar {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.orders-table {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
}
|
||||
}
|
||||
|
||||
/* Modal Styles */
|
||||
.modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
z-index: 1000;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0,0,0,0.5);
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background-color: #fefefe;
|
||||
margin: 15% auto;
|
||||
padding: 20px;
|
||||
border: 1px solid #888;
|
||||
width: 80%;
|
||||
max-width: 500px;
|
||||
border-radius: 8px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.close {
|
||||
color: #aaa;
|
||||
float: right;
|
||||
font-size: 28px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.close:hover,
|
||||
.close:focus {
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.profile-field {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-bottom: 15px;
|
||||
padding: 10px;
|
||||
border-radius: 8px;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.profile-field:hover {
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
.field-label {
|
||||
font-weight: 500;
|
||||
min-width: 120px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.field-value {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.edit-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--primary-color);
|
||||
cursor: pointer;
|
||||
padding: 5px;
|
||||
border-radius: 4px;
|
||||
transition: all 0.3s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.edit-btn:hover {
|
||||
background: rgba(46, 125, 50, 0.1);
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.edit-btn i {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.field-input {
|
||||
display: none;
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.field-input.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.field-value.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.save-btn {
|
||||
display: none;
|
||||
background: var(--primary-color);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 5px 10px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 0.9rem;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.save-btn.active {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.save-btn:hover {
|
||||
background: var(--primary-dark);
|
||||
}
|
||||
|
||||
.view-all-orders {
|
||||
display: inline-block;
|
||||
margin-top: 20px;
|
||||
padding: 12px 24px;
|
||||
background: var(--primary-color);
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
font-size: 1rem;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s ease;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.view-all-orders::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(45deg, transparent, rgba(255, 255, 255, 0.1), transparent);
|
||||
transform: translateX(-100%);
|
||||
transition: transform 0.6s ease;
|
||||
}
|
||||
|
||||
.view-all-orders:hover {
|
||||
background: var(--primary-dark);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(46, 125, 50, 0.2);
|
||||
}
|
||||
|
||||
.view-all-orders:hover::after {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
|
||||
/* Add update profile modal styles */
|
||||
.update-modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 2000;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.update-modal-content {
|
||||
background: white;
|
||||
padding: 30px;
|
||||
border-radius: 8px;
|
||||
text-align: center;
|
||||
max-width: 400px;
|
||||
width: 90%;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.update-modal h2 {
|
||||
margin-bottom: 20px;
|
||||
color: var(--primary-dark);
|
||||
}
|
||||
|
||||
.update-modal-buttons {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 15px;
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
.update-modal-buttons button {
|
||||
padding: 10px 25px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.update-modal-buttons .btn-cancel {
|
||||
background: #e0e0e0;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.update-modal-buttons .btn-cancel:hover {
|
||||
background: #d0d0d0;
|
||||
}
|
||||
|
||||
.update-modal-buttons .btn-confirm {
|
||||
background: var(--primary-color);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.update-modal-buttons .btn-confirm:hover {
|
||||
background: var(--primary-dark);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Add update profile modal HTML -->
|
||||
<div class="update-modal" id="updateModal">
|
||||
<div class="update-modal-content">
|
||||
<h2>Confirm Profile Update</h2>
|
||||
<p>Are you sure you want to update your profile information?</p>
|
||||
<div class="update-modal-buttons">
|
||||
<button class="btn-cancel" onclick="closeUpdateModal()">Cancel</button>
|
||||
<button class="btn-confirm" onclick="confirmUpdate()">Update Profile</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include '../includes/header.php'; ?>
|
||||
|
||||
<div class="container">
|
||||
<h1>My Profile</h1>
|
||||
|
||||
<?php if ($success_message): ?>
|
||||
<div class="alert alert-success"><?php echo $success_message; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($error_message): ?>
|
||||
<div class="alert alert-error"><?php echo $error_message; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="profile-container">
|
||||
<div class="profile-section">
|
||||
<h2 class="section-title">Profile Information</h2>
|
||||
|
||||
<div class="profile-info">
|
||||
<div class="profile-avatar">
|
||||
<i class="fas fa-user"></i>
|
||||
</div>
|
||||
<div class="profile-details">
|
||||
<h3><?php echo htmlspecialchars($user['first_name'] . ' ' . htmlspecialchars($user['last_name'])); ?></h3>
|
||||
<p><?php echo htmlspecialchars($user['email']); ?></p>
|
||||
<p>Member since <?php echo date('F Y', strtotime($user['created_at'])); ?></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form method="POST" id="profileForm">
|
||||
<div class="profile-field">
|
||||
<span class="field-label">First Name</span>
|
||||
<span class="field-value"><?php echo htmlspecialchars($user['first_name']); ?></span>
|
||||
<input type="text" name="first_name" class="field-input" value="<?php echo htmlspecialchars($user['first_name']); ?>" required>
|
||||
<button type="button" class="edit-btn" onclick="toggleEdit(this)">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
<button type="button" class="save-btn" onclick="saveField(this)">Save</button>
|
||||
</div>
|
||||
|
||||
<div class="profile-field">
|
||||
<span class="field-label">Last Name</span>
|
||||
<span class="field-value"><?php echo htmlspecialchars($user['last_name']); ?></span>
|
||||
<input type="text" name="last_name" class="field-input" value="<?php echo htmlspecialchars($user['last_name']); ?>" required>
|
||||
<button type="button" class="edit-btn" onclick="toggleEdit(this)">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
<button type="button" class="save-btn" onclick="saveField(this)">Save</button>
|
||||
</div>
|
||||
|
||||
<div class="profile-field">
|
||||
<span class="field-label">Email</span>
|
||||
<span class="field-value"><?php echo htmlspecialchars($user['email']); ?></span>
|
||||
<input type="email" name="email" class="field-input" value="<?php echo htmlspecialchars($user['email']); ?>" required>
|
||||
<button type="button" class="edit-btn" onclick="toggleEdit(this)">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
<button type="button" class="save-btn" onclick="saveField(this)">Save</button>
|
||||
</div>
|
||||
|
||||
<div class="profile-field">
|
||||
<span class="field-label">Phone Number</span>
|
||||
<span class="field-value"><?php echo htmlspecialchars($user['phone']); ?></span>
|
||||
<input type="tel" name="phone" class="field-input" value="<?php echo htmlspecialchars($user['phone']); ?>">
|
||||
<button type="button" class="edit-btn" onclick="toggleEdit(this)">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
<button type="button" class="save-btn" onclick="saveField(this)">Save</button>
|
||||
</div>
|
||||
|
||||
<div class="profile-field">
|
||||
<span class="field-label">University ID</span>
|
||||
<span class="field-value"><?php echo htmlspecialchars($user['university_id']); ?></span>
|
||||
<input type="text" name="university_id" class="field-input" value="<?php echo htmlspecialchars($user['university_id']); ?>" required>
|
||||
<button type="button" class="edit-btn" onclick="toggleEdit(this)">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
<button type="button" class="save-btn" onclick="saveField(this)">Save</button>
|
||||
</div>
|
||||
|
||||
<div class="button-group">
|
||||
<button type="button" class="btn-update" onclick="openUpdateModal()">Update Profile</button>
|
||||
<button type="button" class="btn-update btn-secondary" onclick="openPasswordModal()">Change Password</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="profile-section">
|
||||
<h2 class="section-title">Recent Orders</h2>
|
||||
|
||||
<?php if (empty($orders)): ?>
|
||||
<p>You haven't placed any orders yet.</p>
|
||||
<?php else: ?>
|
||||
<table class="orders-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Order ID</th>
|
||||
<th>Date</th>
|
||||
<th>Amount</th>
|
||||
<th>Status</th>
|
||||
<th>Pickup Schedule</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($orders as $order): ?>
|
||||
<tr>
|
||||
<td><a href="order_details.php?id=<?php echo $order['order_id']; ?>" id="orders-ids">#<?php echo $order['order_id']; ?></a></td>
|
||||
<td><?php echo date('M d, Y', strtotime($order['order_date'])); ?></td>
|
||||
<td>₱<?php echo number_format($order['total_amount'], 2); ?></td>
|
||||
<td>
|
||||
<span class="order-status status-<?php echo strtolower($order['status']); ?>">
|
||||
<?php echo ucfirst($order['status']); ?>
|
||||
</span>
|
||||
</td>
|
||||
<td><?php echo date('M d, Y h:i A', strtotime($order['pickup_schedule'])); ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<a href="/unimarket/customer/orders/list.php" class="view-all-orders">
|
||||
<i class="fas fa-list"></i> View All Orders
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Password Change Modal -->
|
||||
<div id="passwordModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<span class="close">×</span>
|
||||
<h2>Change Password</h2>
|
||||
<form method="POST" id="passwordForm">
|
||||
<div class="form-group">
|
||||
<label for="current_password">Current Password</label>
|
||||
<input type="password" id="current_password" name="current_password" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="new_password">New Password</label>
|
||||
<input type="password" id="new_password" name="new_password" required>
|
||||
<div class="password-strength">
|
||||
<div class="password-strength-bar" id="passwordStrengthBar"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="confirm_password">Confirm New Password</label>
|
||||
<input type="password" id="confirm_password" name="confirm_password" required>
|
||||
</div>
|
||||
|
||||
<button type="submit" name="change_password" class="btn-update">Change Password</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Modal functionality
|
||||
const modal = document.getElementById('passwordModal');
|
||||
const closeBtn = document.getElementsByClassName('close')[0];
|
||||
|
||||
function openPasswordModal() {
|
||||
modal.style.display = "block";
|
||||
}
|
||||
|
||||
closeBtn.onclick = function() {
|
||||
modal.style.display = "none";
|
||||
}
|
||||
|
||||
window.onclick = function(event) {
|
||||
if (event.target == modal) {
|
||||
modal.style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
// Profile field editing functionality
|
||||
function toggleEdit(button) {
|
||||
const field = button.closest('.profile-field');
|
||||
const value = field.querySelector('.field-value');
|
||||
const input = field.querySelector('.field-input');
|
||||
const saveBtn = field.querySelector('.save-btn');
|
||||
|
||||
value.classList.add('hidden');
|
||||
input.classList.add('active');
|
||||
saveBtn.classList.add('active');
|
||||
button.style.display = 'none';
|
||||
}
|
||||
|
||||
function saveField(button) {
|
||||
const field = button.closest('.profile-field');
|
||||
const value = field.querySelector('.field-value');
|
||||
const input = field.querySelector('.field-input');
|
||||
const editBtn = field.querySelector('.edit-btn');
|
||||
|
||||
// Update the displayed value
|
||||
value.textContent = input.value;
|
||||
|
||||
// Hide input and save button, show value and edit button
|
||||
value.classList.remove('hidden');
|
||||
input.classList.remove('active');
|
||||
button.classList.remove('active');
|
||||
editBtn.style.display = 'flex';
|
||||
}
|
||||
|
||||
// Password strength indicator
|
||||
const passwordInput = document.getElementById('new_password');
|
||||
const strengthBar = document.getElementById('passwordStrengthBar');
|
||||
|
||||
passwordInput.addEventListener('input', function() {
|
||||
const password = this.value;
|
||||
let strength = 0;
|
||||
|
||||
if (password.length >= 8) strength += 1;
|
||||
if (password.match(/[a-z]/)) strength += 1;
|
||||
if (password.match(/[A-Z]/)) strength += 1;
|
||||
if (password.match(/[0-9]/)) strength += 1;
|
||||
if (password.match(/[^a-zA-Z0-9]/)) strength += 1;
|
||||
|
||||
const width = strength * 20;
|
||||
let color;
|
||||
|
||||
if (strength <= 1) color = '#ff0000';
|
||||
else if (strength <= 3) color = '#ff9900';
|
||||
else color = '#00aa00';
|
||||
|
||||
strengthBar.style.width = width + '%';
|
||||
strengthBar.style.backgroundColor = color;
|
||||
});
|
||||
|
||||
// Form validation
|
||||
document.getElementById('passwordForm').addEventListener('submit', function(e) {
|
||||
const newPassword = document.getElementById('new_password').value;
|
||||
const confirmPassword = document.getElementById('confirm_password').value;
|
||||
|
||||
if (newPassword !== confirmPassword) {
|
||||
e.preventDefault();
|
||||
alert('Passwords do not match!');
|
||||
}
|
||||
});
|
||||
|
||||
// Add update profile modal functions
|
||||
function openUpdateModal() {
|
||||
document.getElementById('updateModal').style.display = 'flex';
|
||||
}
|
||||
|
||||
function closeUpdateModal() {
|
||||
document.getElementById('updateModal').style.display = 'none';
|
||||
}
|
||||
|
||||
function confirmUpdate() {
|
||||
document.getElementById('profileForm').submit();
|
||||
}
|
||||
|
||||
// Close modal when clicking outside
|
||||
document.getElementById('updateModal').addEventListener('click', function(e) {
|
||||
if (e.target === this) {
|
||||
closeUpdateModal();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,7 @@
|
||||
-- Truncate orders table and reset auto-increment
|
||||
TRUNCATE TABLE orders;
|
||||
TRUNCATE TABLE order_items;
|
||||
ALTER TABLE orders AUTO_INCREMENT = 1;
|
||||
ALTER TABLE order_items AUTO_INCREMENT = 1;
|
||||
|
||||
ALTER TABLE cart_items ADD COLUMN size VARCHAR(10) DEFAULT NULL;
|
||||
@@ -0,0 +1,44 @@
|
||||
/unimarket
|
||||
│
|
||||
├── assets/
|
||||
│ ├── css/
|
||||
│ │ ├── style.css okay na
|
||||
│ │ └── responsive.css okay na
|
||||
│ ├── js/
|
||||
│ │ └── script.js okay na
|
||||
│ └── images/
|
||||
│ └── logo.png
|
||||
│
|
||||
├── config/
|
||||
│ └── database.php okay na
|
||||
│
|
||||
├── includes/
|
||||
│ ├── header.php okay na
|
||||
│ ├── footer.php okay na
|
||||
│ └── auth_functions.php okay na
|
||||
│
|
||||
├── owner/
|
||||
│ ├── dashboard.php okay na
|
||||
│ ├── products/
|
||||
│ │ ├── add.php
|
||||
│ │ ├── edit.php
|
||||
│ │ └── list.php
|
||||
│ └── orders/
|
||||
│ ├── list.php
|
||||
│ └── schedule_pickup.php
|
||||
│
|
||||
├── customer/
|
||||
│ ├── profile.php okay na
|
||||
│ ├── cart.php okay na
|
||||
│ ├── orders/
|
||||
│ │ ├── list.php
|
||||
│ │ └── view.php
|
||||
│ └── products/
|
||||
│ └── browse.php okay na
|
||||
│
|
||||
├── auth/
|
||||
│ ├── login.php okay na
|
||||
│ ├── register.php okay na
|
||||
│ └── logout.php okay na
|
||||
│
|
||||
└── index.php okay na
|
||||
@@ -0,0 +1,260 @@
|
||||
<?php
|
||||
if (session_status() === PHP_SESSION_NONE) {
|
||||
session_start();
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/../config/database.php';
|
||||
|
||||
/**
|
||||
* Check if a user is logged in
|
||||
* @return bool True if user is logged in, false otherwise
|
||||
*/
|
||||
function isLoggedIn() {
|
||||
return isset($_SESSION['user_id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the logged in user is an owner
|
||||
* @return bool True if user is an owner, false otherwise
|
||||
*/
|
||||
function isOwner() {
|
||||
return isLoggedIn() && $_SESSION['role'] === 'owner';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the logged in user is a customer
|
||||
* @return bool True if user is a customer, false otherwise
|
||||
*/
|
||||
function isCustomer() {
|
||||
return isLoggedIn() && $_SESSION['role'] === 'customer';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the logged in user is an admin
|
||||
* @return bool True if user is an admin, false otherwise
|
||||
*/
|
||||
function isAdmin() {
|
||||
return isLoggedIn() && $_SESSION['role'] === 'admin';
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect to login page if not logged in
|
||||
*/
|
||||
function redirectIfNotLoggedIn() {
|
||||
if (!isLoggedIn()) {
|
||||
$_SESSION['redirect_url'] = $_SERVER['REQUEST_URI'];
|
||||
header("Location: /unimarket/auth/login.php");
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect to homepage if not an owner
|
||||
*/
|
||||
function redirectIfNotOwner() {
|
||||
if (!isOwner()) {
|
||||
header("Location: /unimarket/index.php");
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect to homepage if not a customer
|
||||
*/
|
||||
function redirectIfNotCustomer() {
|
||||
if (!isCustomer()) {
|
||||
header("Location: /unimarket/index.php");
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect to homepage if not an admin
|
||||
*/
|
||||
function redirectIfNotAdmin() {
|
||||
if (!isAdmin()) {
|
||||
header("Location: /unimarket/index.php");
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current user's ID
|
||||
* @return int|null User ID if logged in, null otherwise
|
||||
*/
|
||||
function getUserId() {
|
||||
return $_SESSION['user_id'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current user's role
|
||||
* @return string|null User role if logged in, null otherwise
|
||||
*/
|
||||
function getUserRole() {
|
||||
return $_SESSION['role'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current user's username
|
||||
* @return string|null Username if logged in, null otherwise
|
||||
*/
|
||||
function getUsername() {
|
||||
return $_SESSION['username'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify if the provided password matches the user's password
|
||||
* @param int $user_id User ID to verify
|
||||
* @param string $password Password to verify
|
||||
* @return bool True if password matches, false otherwise
|
||||
*/
|
||||
function verifyPassword($user_id, $password) {
|
||||
global $pdo;
|
||||
|
||||
try {
|
||||
$stmt = $pdo->prepare("SELECT password FROM users WHERE user_id = ?");
|
||||
$stmt->execute([$user_id]);
|
||||
$user = $stmt->fetch();
|
||||
|
||||
return $user && password_verify($password, $user['password']);
|
||||
} catch (PDOException $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user's password
|
||||
* @param int $user_id User ID
|
||||
* @param string $new_password New password
|
||||
* @return bool True if update was successful, false otherwise
|
||||
*/
|
||||
function updatePassword($user_id, $new_password) {
|
||||
global $pdo;
|
||||
|
||||
try {
|
||||
$hashed_password = password_hash($new_password, PASSWORD_DEFAULT);
|
||||
$stmt = $pdo->prepare("UPDATE users SET password = ? WHERE user_id = ?");
|
||||
return $stmt->execute([$hashed_password, $user_id]);
|
||||
} catch (PDOException $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a CSRF token and store it in session
|
||||
* @return string Generated CSRF token
|
||||
*/
|
||||
function generateCsrfToken() {
|
||||
if (empty($_SESSION['csrf_token'])) {
|
||||
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
|
||||
}
|
||||
return $_SESSION['csrf_token'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify a CSRF token
|
||||
* @param string $token Token to verify
|
||||
* @return bool True if token is valid, false otherwise
|
||||
*/
|
||||
function verifyCsrfToken($token) {
|
||||
return isset($_SESSION['csrf_token']) && hash_equals($_SESSION['csrf_token'], $token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the current user owns a specific product
|
||||
* @param int $product_id Product ID to check
|
||||
* @return bool True if user owns the product, false otherwise
|
||||
*/
|
||||
function ownsProduct($product_id) {
|
||||
if (!isOwner()) return false;
|
||||
|
||||
global $pdo;
|
||||
|
||||
try {
|
||||
$stmt = $pdo->prepare("SELECT product_id FROM products WHERE product_id = ? AND owner_id = ?");
|
||||
$stmt->execute([$product_id, getUserId()]);
|
||||
return (bool)$stmt->fetch();
|
||||
} catch (PDOException $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the current user placed a specific order
|
||||
* @param int $order_id Order ID to check
|
||||
* @return bool True if user placed the order, false otherwise
|
||||
*/
|
||||
function placedOrder($order_id) {
|
||||
if (!isCustomer()) return false;
|
||||
|
||||
global $pdo;
|
||||
|
||||
try {
|
||||
$stmt = $pdo->prepare("SELECT order_id FROM orders WHERE order_id = ? AND customer_id = ?");
|
||||
$stmt->execute([$order_id, getUserId()]);
|
||||
return (bool)$stmt->fetch();
|
||||
} catch (PDOException $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flash a message to display on the next page load
|
||||
* @param string $key Message key
|
||||
* @param string $message Message content
|
||||
*/
|
||||
function flashMessage($key, $message) {
|
||||
$_SESSION['flash_messages'][$key] = $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get and clear a flashed message
|
||||
* @param string $key Message key
|
||||
* @return string|null Message content if exists, null otherwise
|
||||
*/
|
||||
function getFlashMessage($key) {
|
||||
if (isset($_SESSION['flash_messages'][$key])) {
|
||||
$message = $_SESSION['flash_messages'][$key];
|
||||
unset($_SESSION['flash_messages'][$key]);
|
||||
return $message;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a user session after login
|
||||
* @param array $user User data array (must contain user_id, username, and role)
|
||||
*/
|
||||
function initUserSession($user) {
|
||||
$_SESSION['user_id'] = $user['user_id'];
|
||||
$_SESSION['username'] = $user['username'];
|
||||
$_SESSION['role'] = $user['role'];
|
||||
|
||||
// Regenerate session ID to prevent fixation
|
||||
session_regenerate_id(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the current user session
|
||||
*/
|
||||
function destroySession() {
|
||||
// Unset all session variables
|
||||
$_SESSION = array();
|
||||
|
||||
// Delete session cookie
|
||||
if (ini_get("session.use_cookies")) {
|
||||
$params = session_get_cookie_params();
|
||||
setcookie(
|
||||
session_name(),
|
||||
'',
|
||||
time() - 42000,
|
||||
$params["path"],
|
||||
$params["domain"],
|
||||
$params["secure"],
|
||||
$params["httponly"]
|
||||
);
|
||||
}
|
||||
|
||||
// Destroy the session
|
||||
session_destroy();
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
</main>
|
||||
|
||||
<footer style="background-color: var(--primary-dark); color: var(--light-text); padding: 40px 0; margin-top: 40px;">
|
||||
<div class="container" style="background: transparent; box-shadow: none; backdrop-filter: none; -webkit-backdrop-filter: none; border: none; margin: 0 auto; padding: 0 30px;">
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 30px;">
|
||||
<div>
|
||||
<h3 style="margin-bottom: 15px; color: var(--light-text);">UniMarket</h3>
|
||||
<p>Your university's premier marketplace for buying and selling products within the campus community.</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 style="margin-bottom: 15px; color: var(--light-text);">Quick Links</h3>
|
||||
<ul style="list-style: none;">
|
||||
<li style="margin-bottom: 8px;"><a href="/unimarket/index.php" style="color: var(--light-text); text-decoration: none;">Home</a></li>
|
||||
<?php if (!isLoggedIn()): ?>
|
||||
<li style="margin-bottom: 8px;"><a href="/unimarket/auth/login.php" style="color: var(--light-text); text-decoration: none;">Login</a></li>
|
||||
<li style="margin-bottom: 8px;"><a href="/unimarket/auth/register.php" style="color: var(--light-text); text-decoration: none;">Register</a></li>
|
||||
<?php else: ?>
|
||||
<?php if (isCustomer()): ?>
|
||||
<li style="margin-bottom: 8px;"><a href="/unimarket/customer/products/browse.php" style="color: var(--light-text); text-decoration: none;">Browse Products</a></li>
|
||||
<li style="margin-bottom: 8px;"><a href="/unimarket/customer/profile.php" style="color: var(--light-text); text-decoration: none;">My Profile</a></li>
|
||||
<?php else: ?>
|
||||
<li style="margin-bottom: 8px;"><a href="/unimarket/owner/dashboard.php" style="color: var(--light-text); text-decoration: none;">Dashboard</a></li>
|
||||
<li style="margin-bottom: 8px;"><a href="/unimarket/owner/products/add.php" style="color: var(--light-text); text-decoration: none;">Add Product</a></li>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 style="margin-bottom: 15px; color: var(--light-text);">Contact</h3>
|
||||
<ul style="list-style: none;">
|
||||
<li style="margin-bottom: 8px;"><i class="fas fa-envelope" style="margin-right: 8px;"></i> contact@unimarket.edu</li>
|
||||
<li style="margin-bottom: 8px;"><i class="fas fa-phone" style="margin-right: 8px;"></i> (123) 456-7890</li>
|
||||
<li style="margin-bottom: 8px;"><i class="fas fa-map-marker-alt" style="margin-right: 8px;"></i> University Campus</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="border-top: 1px solid rgba(255,255,255,0.1); margin-top: 30px; padding-top: 20px; text-align: center;">
|
||||
<p>© <?php echo date('Y'); ?> UniMarket. All rights reserved.</p>
|
||||
<div style="margin-top: 15px;">
|
||||
<a href="#" style="color: var(--light-text); margin: 0 10px; font-size: 1.2rem;"><i class="fab fa-facebook"></i></a>
|
||||
<a href="#" style="color: var(--light-text); margin: 0 10px; font-size: 1.2rem;"><i class="fab fa-twitter"></i></a>
|
||||
<a href="#" style="color: var(--light-text); margin: 0 10px; font-size: 1.2rem;"><i class="fab fa-instagram"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="/unimarket/assets/js/script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,794 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/auth_functions.php';
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title><?php echo isset($page_title) ? $page_title . ' - ' : ''; ?>UniMarket - University Marketplace</title>
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/style.css">
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/responsive.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||
<style>
|
||||
.logo{
|
||||
text-decoration: none;
|
||||
color: var(--light-text);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.logo img {
|
||||
height: 30px;
|
||||
width: auto;
|
||||
filter: brightness(0) invert(1);
|
||||
}
|
||||
|
||||
/* Sticky header styles */
|
||||
header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 1000;
|
||||
background: rgba(46, 125, 50, 0.95);
|
||||
backdrop-filter: blur(10px);
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
max-width: 100%;
|
||||
color: var(--light-text);
|
||||
padding: 15px 0;
|
||||
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
header .container {
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
backdrop-filter: none;
|
||||
-webkit-backdrop-filter: none;
|
||||
border: none;
|
||||
margin: 0 auto;
|
||||
padding: 0 30px;
|
||||
}
|
||||
|
||||
body {
|
||||
padding-top: 60px !important;
|
||||
}
|
||||
|
||||
/* Adjust mobile menu for fixed header */
|
||||
.mobile-menu {
|
||||
position: fixed;
|
||||
top: 60px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 999;
|
||||
background: rgba(46, 125, 50, 0.95);
|
||||
backdrop-filter: blur(10px);
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.header-content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
nav ul {
|
||||
display: flex;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
nav ul li {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
nav ul li a {
|
||||
color: var(--light-text);
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
padding: 8px 12px;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
transition: background-color 0.3s ease;
|
||||
height: 40px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
nav ul li a:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
nav ul li a i {
|
||||
width: 20px;
|
||||
text-align: center;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.mobile-menu-toggle {
|
||||
display: none;
|
||||
color: var(--light-text);
|
||||
font-size: 1.5rem;
|
||||
cursor: pointer;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.header-content nav ul {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mobile-menu-toggle {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.mobile-menu {
|
||||
display: none;
|
||||
padding: 15px 0;
|
||||
}
|
||||
|
||||
.mobile-menu ul {
|
||||
list-style: none;
|
||||
text-align: center;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.mobile-menu ul li {
|
||||
margin: 0;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.mobile-menu ul li a {
|
||||
display: block;
|
||||
padding: 8px 15px;
|
||||
color: var(--light-text);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.mobile-menu ul li a:hover {
|
||||
background: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add logout modal styles */
|
||||
.logout-modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 2000;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.logout-modal-content {
|
||||
background: white;
|
||||
padding: 30px;
|
||||
border-radius: 8px;
|
||||
text-align: center;
|
||||
max-width: 400px;
|
||||
width: 90%;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.logout-modal h2 {
|
||||
margin-bottom: 20px;
|
||||
color: var(--primary-dark);
|
||||
}
|
||||
|
||||
.logout-modal-buttons {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 15px;
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
.logout-modal-buttons button {
|
||||
padding: 10px 25px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.logout-modal-buttons .btn-cancel {
|
||||
background: #e0e0e0;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.logout-modal-buttons .btn-cancel:hover {
|
||||
background: #d0d0d0;
|
||||
}
|
||||
|
||||
.logout-modal-buttons .btn-confirm {
|
||||
background: #ff4444;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.logout-modal-buttons .btn-confirm:hover {
|
||||
background: #ff0000;
|
||||
}
|
||||
|
||||
/* Update notification styles */
|
||||
.notification-btn {
|
||||
position: relative;
|
||||
color: var(--light-text);
|
||||
text-decoration: none;
|
||||
padding: 8px 12px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
height: 40px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.notification-btn:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.notification-btn i {
|
||||
width: 20px;
|
||||
text-align: center;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.notification-badge {
|
||||
position: absolute;
|
||||
top: -5px;
|
||||
right: -5px;
|
||||
background-color: #ff4444;
|
||||
color: white;
|
||||
border-radius: 50%;
|
||||
padding: 2px 6px;
|
||||
font-size: 0.7rem;
|
||||
display: none;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
.notification-badge.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.notification-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.notification-modal {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: calc(100% + 10px);
|
||||
right: 0;
|
||||
width: 350px;
|
||||
max-height: 80vh;
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
z-index: 2000;
|
||||
animation: slideDown 0.2s ease;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@keyframes slideDown {
|
||||
from {
|
||||
transform: translateY(-10px);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.notification-modal::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -8px;
|
||||
right: 20px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background: white;
|
||||
transform: rotate(45deg);
|
||||
box-shadow: -2px -2px 5px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.notification-modal-content {
|
||||
background: white;
|
||||
padding: 0;
|
||||
border-radius: 8px;
|
||||
max-height: 80vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.notification-modal-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 15px;
|
||||
background: var(--primary-color);
|
||||
color: white;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.notification-modal-header h2 {
|
||||
margin: 0;
|
||||
font-size: 1.1rem;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.notification-modal-close {
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 1.2rem;
|
||||
cursor: pointer;
|
||||
color: white;
|
||||
opacity: 0.8;
|
||||
transition: opacity 0.3s;
|
||||
padding: 5px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.notification-modal-close:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.notification-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.notification-list::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
|
||||
.notification-list::-webkit-scrollbar-track {
|
||||
background: #f1f1f1;
|
||||
}
|
||||
|
||||
.notification-list::-webkit-scrollbar-thumb {
|
||||
background: #888;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.notification-list::-webkit-scrollbar-thumb:hover {
|
||||
background: #666;
|
||||
}
|
||||
|
||||
.notification-item {
|
||||
padding: 12px 15px;
|
||||
border-bottom: 1px solid #eee;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.notification-item:hover {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.notification-item.unread {
|
||||
background-color: #f0f7ff;
|
||||
}
|
||||
|
||||
.notification-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.notification-icon.ready {
|
||||
background-color: #d4edda;
|
||||
color: #155724;
|
||||
}
|
||||
|
||||
.notification-icon.completed {
|
||||
background-color: #e2e3e5;
|
||||
color: #383d41;
|
||||
}
|
||||
|
||||
.notification-icon.cancelled {
|
||||
background-color: #f8d7da;
|
||||
color: #721c24;
|
||||
}
|
||||
|
||||
.notification-content {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.notification-title {
|
||||
font-weight: 500;
|
||||
margin-bottom: 4px;
|
||||
color: #333;
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.notification-time {
|
||||
font-size: 0.8rem;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.notification-status {
|
||||
display: inline-block;
|
||||
padding: 2px 6px;
|
||||
border-radius: 10px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.status-ready {
|
||||
background-color: #d4edda;
|
||||
color: #155724;
|
||||
}
|
||||
|
||||
.status-completed {
|
||||
background-color: #e2e3e5;
|
||||
color: #383d41;
|
||||
}
|
||||
|
||||
.status-cancelled {
|
||||
background-color: #f8d7da;
|
||||
color: #721c24;
|
||||
}
|
||||
|
||||
.no-notifications {
|
||||
text-align: center;
|
||||
padding: 30px 20px;
|
||||
color: #666;
|
||||
background: #f8f9fa;
|
||||
}
|
||||
|
||||
.no-notifications i {
|
||||
font-size: 1.8rem;
|
||||
color: #ccc;
|
||||
margin-bottom: 8px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.no-notifications p {
|
||||
margin: 0;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.notification-modal {
|
||||
position: fixed;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
max-height: calc(100vh - 60px);
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.notification-modal::before {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.logout-link {
|
||||
color: var(--light-text) !important;
|
||||
transition: all 0.3s ease !important;
|
||||
background: none !important;
|
||||
background-color: transparent !important;
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
height: 40px !important;
|
||||
white-space: nowrap !important;
|
||||
}
|
||||
|
||||
.logout-link:hover {
|
||||
background-color: rgba(255, 68, 68, 0.1) !important;
|
||||
color: #ff4444 !important;
|
||||
}
|
||||
|
||||
.logout-link i {
|
||||
width: 20px !important;
|
||||
text-align: center !important;
|
||||
font-size: 1rem !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Add logout modal HTML -->
|
||||
<div class="logout-modal" id="logoutModal">
|
||||
<div class="logout-modal-content">
|
||||
<h2>Confirm Logout</h2>
|
||||
<p>Are you sure you want to logout?</p>
|
||||
<div class="logout-modal-buttons">
|
||||
<button class="btn-cancel" onclick="closeLogoutModal()">Cancel</button>
|
||||
<button class="btn-confirm" onclick="confirmLogout()">Logout</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<header>
|
||||
<div class="container header-content">
|
||||
<a href="/unimarket/index.php" class="logo">
|
||||
<img src="/unimarket/assets/images/logo/logo.png" alt="UniMarket Logo">
|
||||
</a>
|
||||
|
||||
<nav>
|
||||
<ul>
|
||||
<?php if (isLoggedIn()): ?>
|
||||
<?php if (isCustomer()): ?>
|
||||
<li><a href="/unimarket/customer/products/browse.php"><i class="fas fa-search"></i> Browse</a></li>
|
||||
<li><a href="/unimarket/customer/cart.php"><i class="fas fa-shopping-cart"></i> Cart</a></li>
|
||||
<li class="notification-container">
|
||||
<a href="#" onclick="openNotificationModal(); return false;" class="notification-btn">
|
||||
<i class="fas fa-bell"></i> Notifications
|
||||
<span class="notification-badge" id="notificationBadge"></span>
|
||||
</a>
|
||||
<div class="notification-modal" id="notificationModal">
|
||||
<div class="notification-modal-content">
|
||||
<div class="notification-modal-header">
|
||||
<h2><i class="fas fa-bell"></i> Notifications</h2>
|
||||
<button class="notification-modal-close" onclick="closeNotificationModal()">×</button>
|
||||
</div>
|
||||
<div class="notification-list" id="notificationList">
|
||||
<div class="no-notifications">
|
||||
<i class="fas fa-bell-slash"></i>
|
||||
<p>No notifications yet</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li><a href="/unimarket/customer/profile.php"><i class="fas fa-user"></i> Profile</a></li>
|
||||
<?php elseif (isAdmin()): ?>
|
||||
<li><a href="/unimarket/admin/dashboard.php"><i class="fas fa-tachometer-alt"></i> Admin Dashboard</a></li>
|
||||
<li><a href="/unimarket/admin/users/manage.php"><i class="fas fa-users"></i> Users</a></li>
|
||||
<li><a href="/unimarket/admin/products/index.php"><i class="fas fa-box"></i> Products</a></li>
|
||||
<li><a href="/unimarket/admin/orders/manage.php"><i class="fas fa-shopping-cart"></i> Orders</a></li>
|
||||
<?php else: ?>
|
||||
<li><a href="/unimarket/owner/dashboard.php"><i class="fas fa-tachometer-alt"></i> Dashboard</a></li>
|
||||
<li><a href="/unimarket/owner/products/list.php"><i class="fas fa-box-open"></i> Products</a></li>
|
||||
<?php endif; ?>
|
||||
<li><a href="#" onclick="openLogoutModal(); return false;" class="logout-link"><i class="fas fa-sign-out-alt"></i> Logout</a></li>
|
||||
<?php else: ?>
|
||||
<li><a href="/unimarket/index.php"><i class="fas fa-home"></i> Home</a></li>
|
||||
<li><a href="/unimarket/auth/login.php"><i class="fas fa-sign-in-alt"></i> Login</a></li>
|
||||
<li><a href="/unimarket/auth/register.php"><i class="fas fa-user-plus"></i> Register</a></li>
|
||||
<?php endif; ?>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<?php if (isLoggedIn()): ?>
|
||||
<div class="mobile-menu-toggle" style="display: none;">
|
||||
<i class="fas fa-bars"></i>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<?php if (isLoggedIn()): ?>
|
||||
<style>
|
||||
.mobile-menu {
|
||||
display: none;
|
||||
background-color: var(--primary-dark);
|
||||
padding: 15px 0;
|
||||
}
|
||||
|
||||
.mobile-menu ul {
|
||||
list-style: none;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.mobile-menu ul li {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.mobile-menu ul li a {
|
||||
color: var(--light-text);
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
.mobile-menu-toggle {
|
||||
color: var(--light-text);
|
||||
font-size: 1.5rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.header-content nav ul {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mobile-menu-toggle {
|
||||
display: block !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="mobile-menu" id="mobileMenu">
|
||||
<div class="container">
|
||||
<ul>
|
||||
<?php if (isCustomer()): ?>
|
||||
<li><a href="/unimarket/customer/products/browse.php"><i class="fas fa-search"></i> Browse</a></li>
|
||||
<li><a href="/unimarket/customer/cart.php"><i class="fas fa-shopping-cart"></i> Cart</a></li>
|
||||
<li class="notification-container">
|
||||
<a href="#" onclick="openNotificationModal(); return false;" class="notification-btn">
|
||||
<i class="fas fa-bell"></i> Notifications
|
||||
<span class="notification-badge" id="notificationBadge"></span>
|
||||
</a>
|
||||
<div class="notification-modal" id="notificationModal">
|
||||
<div class="notification-modal-content">
|
||||
<div class="notification-modal-header">
|
||||
<h2><i class="fas fa-bell"></i> Notifications</h2>
|
||||
<button class="notification-modal-close" onclick="closeNotificationModal()">×</button>
|
||||
</div>
|
||||
<div class="notification-list" id="notificationList">
|
||||
<div class="no-notifications">
|
||||
<i class="fas fa-bell-slash"></i>
|
||||
<p>No notifications yet</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li><a href="/unimarket/customer/profile.php"><i class="fas fa-user"></i> Profile</a></li>
|
||||
<?php elseif (isAdmin()): ?>
|
||||
<li><a href="/unimarket/admin/dashboard.php"><i class="fas fa-tachometer-alt"></i> Admin Dashboard</a></li>
|
||||
<li><a href="/unimarket/admin/users/manage.php"><i class="fas fa-users"></i> Users</a></li>
|
||||
<li><a href="/unimarket/admin/products/index.php"><i class="fas fa-box"></i> Products</a></li>
|
||||
<li><a href="/unimarket/admin/orders/manage.php"><i class="fas fa-shopping-cart"></i> Orders</a></li>
|
||||
<?php else: ?>
|
||||
<li><a href="/unimarket/owner/dashboard.php"><i class="fas fa-tachometer-alt"></i> Dashboard</a></li>
|
||||
<li><a href="/unimarket/owner/products/list.php"><i class="fas fa-box-open"></i> Products</a></li>
|
||||
<?php endif; ?>
|
||||
<li><a href="#" onclick="openLogoutModal(); return false;" class="logout-link"><i class="fas fa-sign-out-alt"></i> Logout</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.querySelector('.mobile-menu-toggle').addEventListener('click', function() {
|
||||
const menu = document.getElementById('mobileMenu');
|
||||
menu.style.display = menu.style.display === 'block' ? 'none' : 'block';
|
||||
});
|
||||
|
||||
// Add logout modal functions
|
||||
function openLogoutModal() {
|
||||
document.getElementById('logoutModal').style.display = 'flex';
|
||||
}
|
||||
|
||||
function closeLogoutModal() {
|
||||
document.getElementById('logoutModal').style.display = 'none';
|
||||
}
|
||||
|
||||
function confirmLogout() {
|
||||
window.location.href = '/unimarket/auth/logout.php';
|
||||
}
|
||||
|
||||
// Close modal when clicking outside
|
||||
document.getElementById('logoutModal').addEventListener('click', function(e) {
|
||||
if (e.target === this) {
|
||||
closeLogoutModal();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
|
||||
<main class="container">
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Remove the scroll event listener that was causing the hover effect
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
// Notification Modal Functions
|
||||
function openNotificationModal() {
|
||||
const modal = document.getElementById('notificationModal');
|
||||
modal.style.display = 'block';
|
||||
loadNotifications();
|
||||
|
||||
// Close modal when clicking outside
|
||||
document.addEventListener('click', function closeModal(e) {
|
||||
if (!modal.contains(e.target) && !e.target.closest('.notification-btn')) {
|
||||
modal.style.display = 'none';
|
||||
document.removeEventListener('click', closeModal);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function closeNotificationModal() {
|
||||
document.getElementById('notificationModal').style.display = 'none';
|
||||
}
|
||||
|
||||
function loadNotifications() {
|
||||
const notificationList = document.getElementById('notificationList');
|
||||
const badge = document.getElementById('notificationBadge');
|
||||
|
||||
fetch('/unimarket/customer/notifications.php')
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error('Network response was not ok');
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
if (data.error) {
|
||||
throw new Error(data.error);
|
||||
}
|
||||
|
||||
if (data.notifications.length === 0) {
|
||||
notificationList.innerHTML = `
|
||||
<div class="no-notifications">
|
||||
<i class="fas fa-bell-slash"></i>
|
||||
<p>No notifications yet</p>
|
||||
</div>
|
||||
`;
|
||||
} else {
|
||||
notificationList.innerHTML = data.notifications.map(notification => `
|
||||
<div class="notification-item ${notification.unread ? 'unread' : ''}">
|
||||
<div class="notification-icon ${notification.status}">
|
||||
<i class="fas ${notification.status === 'ready' ? 'fa-check-circle' :
|
||||
notification.status === 'completed' ? 'fa-check-double' :
|
||||
'fa-times-circle'}"></i>
|
||||
</div>
|
||||
<div class="notification-content">
|
||||
<div class="notification-title">${notification.title}</div>
|
||||
<div class="notification-time">${notification.time}</div>
|
||||
<span class="notification-status status-${notification.status}">
|
||||
${notification.status.charAt(0).toUpperCase() + notification.status.slice(1)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
// Update badge
|
||||
if (data.unread_count > 0) {
|
||||
badge.textContent = data.unread_count;
|
||||
badge.classList.add('show');
|
||||
} else {
|
||||
badge.classList.remove('show');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
notificationList.innerHTML = `
|
||||
<div class="no-notifications">
|
||||
<i class="fas fa-exclamation-circle"></i>
|
||||
<p>Error loading notifications: ${error.message}</p>
|
||||
<p>Please try again later</p>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
}
|
||||
|
||||
// Load notifications every 30 seconds if user is logged in
|
||||
<?php if (isLoggedIn()): ?>
|
||||
setInterval(loadNotifications, 30000);
|
||||
<?php endif; ?>
|
||||
</script>
|
||||
@@ -0,0 +1,20 @@
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo BASE_URL; ?>owner/products/list.php">
|
||||
<i class="fas fa-box me-2"></i>Products
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo BASE_URL; ?>owner/orders/list.php">
|
||||
<i class="fas fa-shopping-cart me-2"></i>Orders
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?php echo BASE_URL; ?>owner/reports.php">
|
||||
<i class="fas fa-chart-bar me-2"></i>Reports
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,248 @@
|
||||
<?php
|
||||
require_once 'includes/auth_functions.php';
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>UniMarket - University Marketplace</title>
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/style.css">
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/responsive.css">
|
||||
<style>
|
||||
header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 1000;
|
||||
background: rgba(46, 125, 50, 0.95);
|
||||
backdrop-filter: blur(10px);
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.hero {
|
||||
background: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url('/unimarket/assets/images/hero/hero-bg.jpg');
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
color: var(--light-text);
|
||||
padding: 120px 0;
|
||||
text-align: center;
|
||||
margin-bottom: 40px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.hero .container {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
backdrop-filter: none;
|
||||
-webkit-backdrop-filter: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.hero h1 {
|
||||
font-size: 3.5rem;
|
||||
margin-bottom: 20px;
|
||||
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.hero p {
|
||||
font-size: 1.3rem;
|
||||
max-width: 800px;
|
||||
margin: 0 auto 30px;
|
||||
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.hero .btn {
|
||||
padding: 12px 30px;
|
||||
font-size: 1.1rem;
|
||||
margin: 0 10px;
|
||||
transition: all 0.3s ease;
|
||||
background-color: transparent;
|
||||
border: 2px solid var(--light-text);
|
||||
color: var(--light-text);
|
||||
}
|
||||
|
||||
.hero .btn:hover {
|
||||
background-color: var(--light-text);
|
||||
color: var(--primary-color);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.hero .btn-secondary {
|
||||
background-color: transparent;
|
||||
border: 2px solid var(--light-text);
|
||||
}
|
||||
|
||||
.hero .btn-secondary:hover {
|
||||
background-color: var(--light-text);
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.features {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 30px;
|
||||
margin: 40px 0;
|
||||
}
|
||||
|
||||
.feature-card {
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 30px;
|
||||
text-align: center;
|
||||
box-shadow: 0 5px 15px rgba(0,0,0,0.05);
|
||||
transition: transform 0.3s;
|
||||
}
|
||||
|
||||
.feature-card:hover {
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
|
||||
.feature-icon {
|
||||
font-size: 3rem;
|
||||
color: var(--primary-color);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.feature-card h3 {
|
||||
margin-bottom: 15px;
|
||||
color: var(--primary-dark);
|
||||
}
|
||||
|
||||
.cta-section {
|
||||
background-color: #f5f5f5;
|
||||
padding: 60px 0;
|
||||
text-align: center;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.trending-products {
|
||||
margin: 60px 0;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
text-align: center;
|
||||
margin-bottom: 40px;
|
||||
color: var(--primary-dark);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<?php include 'includes/header.php'; ?>
|
||||
|
||||
<div class="hero">
|
||||
<div class="container">
|
||||
<h1>Welcome to UniMarket</h1>
|
||||
<p>The University Marketplace for Affordable Student Essentials, Books, Supplies & Campus Merchandise.</p>
|
||||
<?php if (!isLoggedIn()): ?>
|
||||
<div>
|
||||
<a href="/unimarket/auth/register.php" class="btn" style="margin-right: 10px;">Join Now</a>
|
||||
<a href="/unimarket/auth/login.php" class="btn btn-secondary">Sign In</a>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div>
|
||||
<?php if (isCustomer()): ?>
|
||||
<a href="/unimarket/customer/products/browse.php" class="btn">Browse Products</a>
|
||||
<?php else: ?>
|
||||
<a href="/unimarket/owner/dashboard.php" class="btn">Go to Dashboard</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="features">
|
||||
<div class="feature-card">
|
||||
<div class="feature-icon">🛍️</div>
|
||||
<h3>Campus Marketplace</h3>
|
||||
<p>Buy and sell products exclusively within your university community.</p>
|
||||
</div>
|
||||
|
||||
<div class="feature-card">
|
||||
<div class="feature-icon">🔄</div>
|
||||
<h3>Easy Pickup</h3>
|
||||
<p>Schedule convenient on-campus pickup times for your orders.</p>
|
||||
</div>
|
||||
|
||||
<div class="feature-card">
|
||||
<div class="feature-icon">🛒</div>
|
||||
<h3>Secure Transactions</h3>
|
||||
<p>Safe and reliable transactions between students and campus vendors.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
// Display trending products (only for customers or guests)
|
||||
if (!isLoggedIn() || isCustomer()) {
|
||||
require_once 'config/database.php';
|
||||
|
||||
$stmt = $pdo->query("SELECT * FROM products ORDER BY created_at DESC LIMIT 6");
|
||||
$trending_products = $stmt->fetchAll();
|
||||
|
||||
if (!empty($trending_products)) {
|
||||
echo '<div class="trending-products">';
|
||||
echo '<h2 class="section-title">Trending Products</h2>';
|
||||
echo '<div class="product-grid">';
|
||||
|
||||
foreach ($trending_products as $product) {
|
||||
echo '<div class="product-card"">';
|
||||
echo '<div class="product-image">';
|
||||
if ($product['image_path']) {
|
||||
echo '<img src="/unimarket/uploads/products/'.$product['image_path'].'" alt="'.htmlspecialchars($product['name']).'">';
|
||||
} else {
|
||||
echo '<div style="display: flex; align-items: center; justify-content: center; height: 100%; color: #999;">No Image</div>';
|
||||
}
|
||||
echo '</div>';
|
||||
echo '<div class="product-info">';
|
||||
echo '<h3 class="product-title">'.htmlspecialchars($product['name']).'</h3>';
|
||||
echo '<p class="product-price">₱'.number_format($product['price'], 2).'</p>';
|
||||
|
||||
if (isLoggedIn()) {
|
||||
echo '<a href="/unimarket/customer/products/view.php?id='.$product['product_id'].'" class="btn" style="display: block; text-align: center;">';
|
||||
echo '<i class="fas fa-eye"></i> View Details';
|
||||
echo '</a>';
|
||||
} else {
|
||||
echo '<a href="/unimarket/auth/login.php" class="btn" style="display: block; text-align: center;">Login to Purchase</a>';
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
echo '<div style="text-align: center; margin-top: 30px;">';
|
||||
echo '<a href="/unimarket/customer/products/browse.php" class="btn">View All Products</a>';
|
||||
echo '</div>';
|
||||
echo '</div>';
|
||||
}
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
|
||||
<div class="cta-section">
|
||||
<div class="container">
|
||||
<h2>Ready to join the campus marketplace?</h2>
|
||||
<p style="max-width: 600px; margin: 0 auto 30px;">Whether you're looking to buy or sell, UniMarket connects you with your university community.</p>
|
||||
<?php if (!isLoggedIn()): ?>
|
||||
<a href="/unimarket/auth/register.php" class="btn">Get Started</a>
|
||||
<?php else: ?>
|
||||
<?php if (isCustomer()): ?>
|
||||
<a href="/unimarket/customer/products/browse.php" class="btn">Browse Products</a>
|
||||
<?php else: ?>
|
||||
<a href="/unimarket/owner/products/add.php" class="btn">Add New Product</a>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include 'includes/footer.php'; ?>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,566 @@
|
||||
<?php
|
||||
require_once '../includes/auth_functions.php';
|
||||
redirectIfNotLoggedIn();
|
||||
redirectIfNotOwner();
|
||||
|
||||
require_once '../config/database.php';
|
||||
|
||||
// Get owner's products count
|
||||
$stmt = $pdo->prepare("SELECT COUNT(*) FROM products WHERE owner_id = ?");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
$products_count = $stmt->fetchColumn();
|
||||
|
||||
// Get pending orders count
|
||||
$stmt = $pdo->prepare("SELECT COUNT(*) FROM orders o
|
||||
JOIN order_items oi ON o.order_id = oi.order_id
|
||||
JOIN products p ON oi.product_id = p.product_id
|
||||
WHERE p.owner_id = ? AND o.status = 'pending'");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
$pending_orders_count = $stmt->fetchColumn();
|
||||
|
||||
// Get recent orders
|
||||
$stmt = $pdo->prepare("SELECT o.order_id, o.order_date, o.total_amount, o.status, u.username
|
||||
FROM orders o
|
||||
JOIN order_items oi ON o.order_id = oi.order_id
|
||||
JOIN products p ON oi.product_id = p.product_id
|
||||
JOIN users u ON o.customer_id = u.user_id
|
||||
WHERE p.owner_id = ?
|
||||
GROUP BY o.order_id
|
||||
ORDER BY o.order_date DESC
|
||||
LIMIT 5");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
$recent_orders = $stmt->fetchAll();
|
||||
|
||||
// Get vendor information
|
||||
$vendor_stmt = $pdo->prepare("SELECT * FROM users WHERE user_id = ? AND role = 'owner'");
|
||||
$vendor_stmt->execute([$_SESSION['user_id']]);
|
||||
$vendor = $vendor_stmt->fetch();
|
||||
|
||||
// Get total products count
|
||||
$products_stmt = $pdo->prepare("SELECT COUNT(*) FROM products WHERE owner_id = ?");
|
||||
$products_stmt->execute([$_SESSION['user_id']]);
|
||||
$total_products = $products_stmt->fetchColumn();
|
||||
|
||||
// Get total orders count
|
||||
$orders_stmt = $pdo->prepare("
|
||||
SELECT COUNT(*)
|
||||
FROM orders o
|
||||
JOIN order_items oi ON o.order_id = oi.order_id
|
||||
JOIN products p ON oi.product_id = p.product_id
|
||||
WHERE p.owner_id = ?
|
||||
");
|
||||
$orders_stmt->execute([$_SESSION['user_id']]);
|
||||
$total_orders = $orders_stmt->fetchColumn();
|
||||
|
||||
// Get total revenue
|
||||
$revenue_stmt = $pdo->prepare("
|
||||
SELECT COALESCE(SUM(oi.quantity * oi.price), 0) as total_revenue
|
||||
FROM orders o
|
||||
JOIN order_items oi ON o.order_id = oi.order_id
|
||||
JOIN products p ON oi.product_id = p.product_id
|
||||
WHERE p.owner_id = ? AND o.status = 'completed'
|
||||
");
|
||||
$revenue_stmt->execute([$_SESSION['user_id']]);
|
||||
$total_revenue = $revenue_stmt->fetchColumn();
|
||||
|
||||
// Get recent orders
|
||||
$recent_orders_stmt = $pdo->prepare("
|
||||
SELECT o.order_id, o.order_date, o.status, o.total_amount,
|
||||
u.first_name, u.last_name
|
||||
FROM orders o
|
||||
JOIN order_items oi ON o.order_id = oi.order_id
|
||||
JOIN products p ON oi.product_id = p.product_id
|
||||
JOIN users u ON o.customer_id = u.user_id
|
||||
WHERE p.owner_id = ?
|
||||
GROUP BY o.order_id
|
||||
ORDER BY o.order_date DESC
|
||||
LIMIT 4
|
||||
");
|
||||
$recent_orders_stmt->execute([$_SESSION['user_id']]);
|
||||
$recent_orders = $recent_orders_stmt->fetchAll();
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Owner Dashboard - UniMarket</title>
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/style.css">
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/responsive.css">
|
||||
<style>
|
||||
/* Sidebar Styles */
|
||||
.sidebar {
|
||||
width: 250px;
|
||||
background: #ffffff;
|
||||
color: #333;
|
||||
padding: 20px 0;
|
||||
height: 100vh;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
box-shadow: 2px 0 10px rgba(0,0,0,0.1);
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.sidebar-header {
|
||||
padding: 0 20px 20px;
|
||||
border-bottom: 1px solid #eee;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.sidebar-header h2 {
|
||||
color: #333;
|
||||
font-size: 1.5rem;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.sidebar-header p {
|
||||
color: #666;
|
||||
margin: 5px 0 0;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.nav-menu {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 12px 20px;
|
||||
color: #333;
|
||||
text-decoration: none;
|
||||
transition: all 0.3s ease;
|
||||
border-left: 3px solid transparent;
|
||||
}
|
||||
|
||||
.nav-link:hover {
|
||||
background: #e8f5e9;
|
||||
color: #2e7d32;
|
||||
border-left-color: #2e7d32;
|
||||
}
|
||||
|
||||
.nav-link.active {
|
||||
background: #e8f5e9;
|
||||
color: #2e7d32;
|
||||
border-left-color: #2e7d32;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.nav-link i {
|
||||
width: 20px;
|
||||
margin-right: 10px;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.nav-link span {
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.logout-link {
|
||||
margin-top: auto;
|
||||
border-top: 1px solid #eee;
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.logout-link a {
|
||||
color: var(--light-text);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 12px 20px;
|
||||
text-decoration: none;
|
||||
transition: all 0.3s ease;
|
||||
height: 40px;
|
||||
white-space: nowrap;
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.logout-link a:hover {
|
||||
background: rgba(255, 68, 68, 0.1);
|
||||
color: #ff4444;
|
||||
}
|
||||
|
||||
.logout-link i {
|
||||
width: 20px;
|
||||
text-align: center;
|
||||
font-size: 1rem;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
/* Main Content Styles */
|
||||
.main-content {
|
||||
margin-left: 250px;
|
||||
padding: 40px;
|
||||
min-height: 100vh;
|
||||
background: #f5f6fa;
|
||||
width: calc(100% - 250px);
|
||||
}
|
||||
|
||||
.dashboard-container {
|
||||
max-width: 1800px;
|
||||
margin: 0 auto;
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.dashboard-header {
|
||||
margin-bottom: 40px;
|
||||
padding: 20px 0;
|
||||
border-bottom: 2px solid #f0f0f0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.dashboard-header h1 {
|
||||
font-size: 2rem;
|
||||
color: #2e7d32;
|
||||
margin: 0;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.dashboard-header h1::before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
width: 4px;
|
||||
height: 24px;
|
||||
background-color: #2e7d32;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.dashboard-header p {
|
||||
margin: 8px 0 0 0;
|
||||
color: #666;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 20px;
|
||||
margin-bottom: 50px;
|
||||
max-width: 1200px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
background: white;
|
||||
padding: 25px;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||
text-align: center;
|
||||
transition: transform 0.2s ease;
|
||||
aspect-ratio: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.stat-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
||||
}
|
||||
|
||||
.stat-card h3 {
|
||||
margin: 0 0 15px 0;
|
||||
color: #666;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.stat-card .value {
|
||||
font-size: 2.5rem;
|
||||
font-weight: bold;
|
||||
color: #2e7d32;
|
||||
}
|
||||
|
||||
.recent-orders {
|
||||
background: white;
|
||||
padding: 25px 40px;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||
width: fit-content;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.recent-orders h2 {
|
||||
margin: 0 0 20px 0;
|
||||
color: #333;
|
||||
font-size: 1.4rem;
|
||||
font-weight: 600;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 2px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.view-all-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 6px 12px;
|
||||
background-color: #2e7d32;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 4px;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s ease;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.view-all-btn:hover {
|
||||
background-color: #1b5e20;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.table {
|
||||
width: 100%;
|
||||
border-collapse: separate;
|
||||
border-spacing: 0;
|
||||
margin-top: 10px;
|
||||
min-width: 600px;
|
||||
}
|
||||
|
||||
.table th,
|
||||
.table td {
|
||||
padding: 16px 20px;
|
||||
vertical-align: middle;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.table th {
|
||||
background-color: #f8f9fa;
|
||||
font-weight: 600;
|
||||
color: #555;
|
||||
text-transform: uppercase;
|
||||
font-size: 0.85rem;
|
||||
letter-spacing: 0.5px;
|
||||
white-space: nowrap;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
.table th:first-child {
|
||||
border-top-left-radius: 8px;
|
||||
min-width: 80px;
|
||||
}
|
||||
|
||||
.table th:nth-child(2) {
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
.table th:nth-child(3) {
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
.table th:last-child {
|
||||
border-top-right-radius: 8px;
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.table td {
|
||||
white-space: nowrap;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
.table tr:hover {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.table tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
display: inline-block;
|
||||
padding: 6px 12px;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 500;
|
||||
line-height: 1;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
vertical-align: baseline;
|
||||
border-radius: 6px;
|
||||
background-color: #e9ecef;
|
||||
color: #495057;
|
||||
}
|
||||
|
||||
.status-badge.pending {
|
||||
background-color: #fff3cd;
|
||||
color: #856404;
|
||||
}
|
||||
|
||||
.status-badge.processing {
|
||||
background-color: #cce5ff;
|
||||
color: #004085;
|
||||
}
|
||||
|
||||
.status-badge.ready {
|
||||
background-color: #d4edda;
|
||||
color: #155724;
|
||||
}
|
||||
|
||||
.status-badge.completed {
|
||||
background-color: #e2e3e5;
|
||||
color: #383d41;
|
||||
}
|
||||
|
||||
.status-badge.cancelled {
|
||||
background-color: #f8d7da;
|
||||
color: #721c24;
|
||||
}
|
||||
|
||||
#order-number {
|
||||
color: #2e7d32;
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
font-size: 0.95rem;
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
|
||||
#order-number:hover {
|
||||
color: #1b5e20;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@media (max-width: 1600px) {
|
||||
.stats-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.stats-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.recent-orders {
|
||||
margin: 0 -20px;
|
||||
border-radius: 0;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.table {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<?php include '../includes/header.php'; ?>
|
||||
|
||||
<div class="container dashboard-container">
|
||||
<div class="sidebar">
|
||||
<div class="sidebar-header">
|
||||
<h2>Vendor Dashboard</h2>
|
||||
<p>Welcome, <?php echo htmlspecialchars($vendor['first_name'] . ' ' . $vendor['last_name']); ?></p>
|
||||
</div>
|
||||
|
||||
<ul class="nav-menu">
|
||||
<li class="nav-item">
|
||||
<a href="dashboard.php" class="nav-link active">
|
||||
<i class="fas fa-chart-line"></i>
|
||||
<span>Dashboard</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="products/list.php" class="nav-link">
|
||||
<i class="fas fa-box"></i>
|
||||
<span>Products</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="orders/list.php" class="nav-link">
|
||||
<i class="fas fa-shopping-cart"></i>
|
||||
<span>Orders</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="reports.php" class="nav-link">
|
||||
<i class="fas fa-chart-bar"></i>
|
||||
<span>Reports</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="logout-link">
|
||||
<a href="/unimarket/auth/logout.php">
|
||||
<i class="fas fa-sign-out-alt"></i>
|
||||
<span>Logout</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="main-content">
|
||||
<div class="dashboard-container">
|
||||
<div class="dashboard-header">
|
||||
<h1>Dashboard Overview</h1>
|
||||
<p>Welcome to your vendor dashboard</p>
|
||||
</div>
|
||||
|
||||
<div class="stats-grid">
|
||||
<div class="stat-card">
|
||||
<h3>Total Products</h3>
|
||||
<div class="value"><?php echo $total_products; ?></div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<h3>Total Orders</h3>
|
||||
<div class="value"><?php echo $total_orders; ?></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="recent-orders">
|
||||
<h2>Recent Orders</h2>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Order ID</th>
|
||||
<th>Customer</th>
|
||||
<th>Amount</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($recent_orders as $order): ?>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="/unimarket/owner/orders/view.php?order_id=<?php echo $order['order_id']; ?>" id="order-number">
|
||||
#<?php echo $order['order_id']; ?>
|
||||
</a>
|
||||
</td>
|
||||
<td><?php echo htmlspecialchars($order['first_name'] . ' ' . $order['last_name']); ?></td>
|
||||
<td>₱<?php echo number_format($order['total_amount'], 2); ?></td>
|
||||
<td>
|
||||
<span class="status-badge <?php echo strtolower(str_replace('_', '', $order['status'])); ?>">
|
||||
<?php echo ucfirst(str_replace('_', ' ', $order['status'])); ?>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<a href="/unimarket/owner/orders/list.php" class="view-all-btn">
|
||||
<i class="fas fa-list"></i>
|
||||
View All Orders
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Remove modal-related JavaScript
|
||||
</script>
|
||||
|
||||
<?php include '../includes/footer.php'; ?>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,10 @@
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h1 class="h3 mb-0">Manage Orders</h1>
|
||||
<a href="dashboard.php" class="btn btn-outline-secondary">
|
||||
<i class="fas fa-arrow-left me-2"></i>Back to Dashboard
|
||||
</a>
|
||||
</div>
|
||||
<div class="card">
|
||||
@@ -0,0 +1,301 @@
|
||||
<?php
|
||||
require_once '../../includes/auth_functions.php';
|
||||
redirectIfNotLoggedIn();
|
||||
redirectIfNotOwner();
|
||||
|
||||
require_once '../../config/database.php';
|
||||
|
||||
// Debug query to check order items with sizes
|
||||
$debug_stmt = $pdo->prepare("
|
||||
SELECT oi.order_id, oi.product_id, oi.size, p.name, p.category
|
||||
FROM order_items oi
|
||||
JOIN products p ON oi.product_id = p.product_id
|
||||
WHERE p.owner_id = ?
|
||||
ORDER BY oi.order_id DESC
|
||||
LIMIT 5
|
||||
");
|
||||
$debug_stmt->execute([$_SESSION['user_id']]);
|
||||
$debug_items = $debug_stmt->fetchAll();
|
||||
error_log("Recent order items with sizes: " . print_r($debug_items, true));
|
||||
|
||||
// Get all orders with customer info for products owned by this owner
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT o.order_id, o.order_date, o.total_amount, o.status, o.pickup_schedule,
|
||||
u.username AS customer_username, u.first_name, u.last_name,
|
||||
GROUP_CONCAT(
|
||||
CONCAT(
|
||||
p.name,
|
||||
CASE
|
||||
WHEN p.category = 'clothes' AND oi.size IS NOT NULL AND oi.size != ''
|
||||
THEN CONCAT(' (Size: ', oi.size, ')')
|
||||
ELSE ''
|
||||
END,
|
||||
' x', oi.quantity
|
||||
) ORDER BY p.name SEPARATOR ', '
|
||||
) as order_items,
|
||||
COUNT(DISTINCT oi.product_id) as item_count
|
||||
FROM orders o
|
||||
JOIN order_items oi ON o.order_id = oi.order_id
|
||||
JOIN products p ON oi.product_id = p.product_id
|
||||
JOIN users u ON o.customer_id = u.user_id
|
||||
WHERE p.owner_id = ?
|
||||
GROUP BY o.order_id, o.order_date, o.total_amount, o.status, o.pickup_schedule,
|
||||
u.username, u.first_name, u.last_name
|
||||
ORDER BY o.order_date DESC
|
||||
");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
$orders = $stmt->fetchAll();
|
||||
|
||||
// For debugging
|
||||
error_log("Orders query result: " . print_r($orders, true));
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Manage Orders - UniMarket</title>
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/style.css">
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/responsive.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||
<style>
|
||||
.orders-container {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.orders-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.orders-table th, .orders-table td {
|
||||
padding: 12px 15px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.orders-table th {
|
||||
background-color: #f5f5f5;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.order-items {
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
.order-item {
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.order-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.item-name {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.item-size {
|
||||
color: #666;
|
||||
font-size: 0.9em;
|
||||
background-color: #f8f9fa;
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.item-quantity {
|
||||
color: #666;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.order-status {
|
||||
display: inline-block;
|
||||
padding: 5px 10px;
|
||||
border-radius: 4px;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.status-pending {
|
||||
background-color: #fff3cd;
|
||||
color: #856404;
|
||||
}
|
||||
|
||||
.status-processing {
|
||||
background-color: #cce5ff;
|
||||
color: #004085;
|
||||
}
|
||||
|
||||
.status-ready {
|
||||
background-color: #d4edda;
|
||||
color: #155724;
|
||||
}
|
||||
|
||||
.status-completed {
|
||||
background-color: #e2e3e5;
|
||||
color: #383d41;
|
||||
}
|
||||
|
||||
.status-cancelled {
|
||||
background-color: #f8d7da;
|
||||
color: #721c24;
|
||||
}
|
||||
|
||||
.action-link {
|
||||
color: var(--primary-color);
|
||||
text-decoration: none;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.action-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.empty-orders {
|
||||
text-align: center;
|
||||
padding: 50px;
|
||||
background-color: #f9f9f9;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.orders-table {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<?php include '../../includes/header.php'; ?>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h1 class="h3 mb-0">Manage Orders</h1>
|
||||
<a href="../dashboard.php" class="btn btn-outline-secondary">
|
||||
<i class="fas fa-arrow-left me-2"></i>Back to Dashboard
|
||||
</a>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="container orders-container">
|
||||
<?php if (empty($orders)): ?>
|
||||
<div class="empty-orders card">
|
||||
<i class="fas fa-box-open" style="font-size: 3em; color: #ccc; margin-bottom: 20px;"></i>
|
||||
<h3>No orders yet</h3>
|
||||
<p>Orders for your products will appear here</p>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<table class="orders-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Order #</th>
|
||||
<th>Customer</th>
|
||||
<th>Items</th>
|
||||
<th>Date</th>
|
||||
<th>Total</th>
|
||||
<th>Status</th>
|
||||
<th>Pickup</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($orders as $order): ?>
|
||||
<tr>
|
||||
<td>#<?php echo $order['order_id']; ?></td>
|
||||
<td><?php echo htmlspecialchars($order['first_name'] . ' ' . $order['last_name']); ?></td>
|
||||
<td>
|
||||
<div class="order-items">
|
||||
<?php
|
||||
$items = explode(', ', $order['order_items']);
|
||||
foreach ($items as $item) {
|
||||
echo '<div class="order-item">';
|
||||
// Check if it's a clothing item with size
|
||||
if (strpos($item, '(Size:') !== false) {
|
||||
// Split the item into name and size+quantity
|
||||
$parts = explode(' (Size:', $item);
|
||||
$name = $parts[0];
|
||||
$sizeAndQty = $parts[1];
|
||||
|
||||
// Split size and quantity
|
||||
$sizeQtyParts = explode(') x', $sizeAndQty);
|
||||
$size = $sizeQtyParts[0];
|
||||
$quantity = $sizeQtyParts[1];
|
||||
|
||||
echo '<span class="item-name">' . htmlspecialchars($name) . '</span>';
|
||||
echo '<span class="item-size">Size: ' . htmlspecialchars($size) . '</span>';
|
||||
echo '<span class="item-quantity">x' . htmlspecialchars($quantity) . '</span>';
|
||||
} else {
|
||||
echo htmlspecialchars($item);
|
||||
}
|
||||
echo '</div>';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</td>
|
||||
<td><?php echo date('M j, Y', strtotime($order['order_date'])); ?></td>
|
||||
<td>₱<?php echo number_format($order['total_amount'], 2); ?></td>
|
||||
<td>
|
||||
<?php
|
||||
$status_class = '';
|
||||
switch ($order['status']) {
|
||||
case 'pending':
|
||||
$status_class = 'status-pending';
|
||||
break;
|
||||
case 'processing':
|
||||
$status_class = 'status-processing';
|
||||
break;
|
||||
case 'ready_for_pickup':
|
||||
$status_class = 'status-ready';
|
||||
break;
|
||||
case 'completed':
|
||||
$status_class = 'status-completed';
|
||||
break;
|
||||
case 'cancelled':
|
||||
$status_class = 'status-cancelled';
|
||||
break;
|
||||
}
|
||||
?>
|
||||
<span class="order-status <?php echo $status_class; ?>">
|
||||
<?php echo ucfirst(str_replace('_', ' ', $order['status'])); ?>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ($order['pickup_schedule']): ?>
|
||||
<?php echo date('M j, Y', strtotime($order['pickup_schedule'])); ?>
|
||||
<?php else: ?>
|
||||
Not scheduled
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ($order['status'] !== 'completed' && $order['status'] !== 'cancelled'): ?>
|
||||
<a href="/unimarket/owner/orders/schedule_pickup.php?order_id=<?php echo $order['order_id']; ?>" class="action-link">
|
||||
<i class="fas fa-calendar-alt"></i> Schedule
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<a href="/unimarket/owner/orders/view.php?order_id=<?php echo $order['order_id']; ?>" class="action-link">
|
||||
<i class="fas fa-eye"></i> View
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include '../../includes/footer.php'; ?>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,253 @@
|
||||
<?php
|
||||
require_once '../../includes/auth_functions.php';
|
||||
redirectIfNotLoggedIn();
|
||||
redirectIfNotOwner();
|
||||
|
||||
require_once '../../config/database.php';
|
||||
|
||||
// Check if order ID is provided
|
||||
if (!isset($_GET['order_id'])) {
|
||||
header("Location: /unimarket/owner/orders/list.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
$order_id = (int)$_GET['order_id'];
|
||||
|
||||
// Verify order contains owner's products
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT o.order_id
|
||||
FROM orders o
|
||||
JOIN order_items oi ON o.order_id = oi.order_id
|
||||
JOIN products p ON oi.product_id = p.product_id
|
||||
WHERE o.order_id = ? AND p.owner_id = ?
|
||||
LIMIT 1
|
||||
");
|
||||
$stmt->execute([$order_id, $_SESSION['user_id']]);
|
||||
$valid_order = $stmt->fetch();
|
||||
|
||||
if (!$valid_order) {
|
||||
header("Location: /unimarket/owner/orders/list.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
// Get order details
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT o.*, u.username, u.first_name, u.last_name
|
||||
FROM orders o
|
||||
JOIN users u ON o.customer_id = u.user_id
|
||||
WHERE o.order_id = ?
|
||||
");
|
||||
$stmt->execute([$order_id]);
|
||||
$order = $stmt->fetch();
|
||||
|
||||
// Handle form submission
|
||||
$success_message = '';
|
||||
$error_message = '';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$pickup_date = $_POST['pickup_date'];
|
||||
$pickup_time = $_POST['pickup_time'];
|
||||
|
||||
if (empty($pickup_date) || empty($pickup_time)) {
|
||||
$error_message = 'Please select both date and time.';
|
||||
} else {
|
||||
$pickup_datetime = date('Y-m-d H:i:s', strtotime("$pickup_date $pickup_time"));
|
||||
|
||||
try {
|
||||
$stmt = $pdo->prepare("UPDATE orders SET pickup_schedule = ?, status = 'ready' WHERE order_id = ?");
|
||||
$stmt->execute([$pickup_datetime, $order_id]);
|
||||
|
||||
$success_message = 'Pickup scheduled successfully!';
|
||||
$order['pickup_schedule'] = $pickup_datetime;
|
||||
$order['status'] = 'ready';
|
||||
} catch (PDOException $e) {
|
||||
$error_message = 'Failed to schedule pickup. Please try again.';
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Schedule Pickup - UniMarket</title>
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/style.css">
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/responsive.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
|
||||
<style>
|
||||
.schedule-container {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.order-card {
|
||||
background-color: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
padding: 20px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.order-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.customer-info {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.form-group input, .form-group select {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.datetime-fields {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.btn-submit {
|
||||
background-color: var(--primary-color);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 12px 20px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 1rem;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
.btn-submit:hover {
|
||||
background-color: var(--primary-dark);
|
||||
}
|
||||
|
||||
.back-link {
|
||||
display: inline-block;
|
||||
margin-bottom: 20px;
|
||||
color: var(--primary-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.back-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.datetime-fields {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<?php include '../../includes/header.php'; ?>
|
||||
|
||||
<div class="container schedule-container">
|
||||
<a href="/unimarket/owner/orders/list.php" class="back-link">
|
||||
<i class="fas fa-arrow-left"></i> Back to Orders
|
||||
</a>
|
||||
|
||||
<h1>Schedule Pickup</h1>
|
||||
|
||||
<?php if ($success_message): ?>
|
||||
<div class="alert alert-success"><?php echo $success_message; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($error_message): ?>
|
||||
<div class="alert alert-error"><?php echo $error_message; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="order-card card">
|
||||
<div class="order-header">
|
||||
<h2>Order #<?php echo $order['order_id']; ?></h2>
|
||||
<div>
|
||||
<strong>Order Date:</strong> <?php echo date('M j, Y', strtotime($order['order_date'])); ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="customer-info">
|
||||
<h3>Customer Information</h3>
|
||||
<p><strong>Name:</strong> <?php echo htmlspecialchars($order['first_name'] . ' ' . $order['last_name']); ?></p>
|
||||
<p><strong>Username:</strong> <?php echo htmlspecialchars($order['username']); ?></p>
|
||||
</div>
|
||||
|
||||
<form method="POST">
|
||||
<div class="form-group">
|
||||
<label>Current Pickup Schedule</label>
|
||||
<p>
|
||||
<?php if ($order['pickup_schedule']): ?>
|
||||
<?php echo date('F j, Y g:i A', strtotime($order['pickup_schedule'])); ?>
|
||||
<?php else: ?>
|
||||
Not scheduled yet
|
||||
<?php endif; ?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="pickup_date">Pickup Date*</label>
|
||||
<input type="date" id="pickup_date" name="pickup_date" required
|
||||
min="<?php echo date('Y-m-d'); ?>">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="pickup_time">Pickup Time*</label>
|
||||
<select id="pickup_time" name="pickup_time" required>
|
||||
<option value="">Select a time</option>
|
||||
<?php
|
||||
// Generate time slots from 9AM to 5PM in 30-minute increments
|
||||
$start = strtotime('09:00');
|
||||
$end = strtotime('17:00');
|
||||
|
||||
for ($time = $start; $time <= $end; $time += 1800) {
|
||||
$time_value = date('H:i', $time);
|
||||
$time_display = date('g:i A', $time);
|
||||
echo "<option value=\"$time_value\">$time_display</option>";
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn-submit">
|
||||
<i class="fas fa-calendar-check"></i> Schedule Pickup
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include '../../includes/footer.php'; ?>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
|
||||
<script>
|
||||
// Initialize date picker
|
||||
flatpickr("#pickup_date", {
|
||||
minDate: "today",
|
||||
dateFormat: "Y-m-d",
|
||||
disable: [
|
||||
function(date) {
|
||||
// Disable weekends
|
||||
return (date.getDay() === 0 || date.getDay() === 6);
|
||||
}
|
||||
]
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,467 @@
|
||||
<?php
|
||||
require_once '../../includes/auth_functions.php';
|
||||
redirectIfNotLoggedIn();
|
||||
redirectIfNotOwner();
|
||||
|
||||
require_once '../../config/database.php';
|
||||
|
||||
// Check if order ID is provided
|
||||
if (!isset($_GET['order_id'])) {
|
||||
header("Location: /unimarket/owner/orders/list.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
$order_id = (int)$_GET['order_id'];
|
||||
|
||||
// Verify order contains owner's products
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT o.order_id
|
||||
FROM orders o
|
||||
JOIN order_items oi ON o.order_id = oi.order_id
|
||||
JOIN products p ON oi.product_id = p.product_id
|
||||
WHERE o.order_id = ? AND p.owner_id = ?
|
||||
LIMIT 1
|
||||
");
|
||||
$stmt->execute([$order_id, $_SESSION['user_id']]);
|
||||
$valid_order = $stmt->fetch();
|
||||
|
||||
if (!$valid_order) {
|
||||
header("Location: /unimarket/owner/orders/list.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
// Get order details with proper null checks
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT o.*,
|
||||
COALESCE(u.username, 'N/A') AS username,
|
||||
COALESCE(u.first_name, '') AS first_name,
|
||||
COALESCE(u.last_name, '') AS last_name,
|
||||
COALESCE(u.email, 'Not provided') AS email,
|
||||
COALESCE(u.phone, 'Not provided') AS phone
|
||||
FROM orders o
|
||||
LEFT JOIN users u ON o.customer_id = u.user_id
|
||||
WHERE o.order_id = ?
|
||||
");
|
||||
$stmt->execute([$order_id]);
|
||||
$order = $stmt->fetch();
|
||||
|
||||
// Get order items for this owner's products
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT oi.*, p.name, p.price, p.image_path, p.category, oi.size
|
||||
FROM order_items oi
|
||||
JOIN products p ON oi.product_id = p.product_id
|
||||
WHERE oi.order_id = ? AND p.owner_id = ?
|
||||
");
|
||||
$stmt->execute([$order_id, $_SESSION['user_id']]);
|
||||
$order_items = $stmt->fetchAll();
|
||||
|
||||
// Calculate subtotal for owner's products
|
||||
$subtotal = 0;
|
||||
foreach ($order_items as $item) {
|
||||
$subtotal += $item['price'] * $item['quantity'];
|
||||
}
|
||||
|
||||
// Handle status update
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_status'])) {
|
||||
$new_status = $_POST['status'];
|
||||
|
||||
try {
|
||||
$stmt = $pdo->prepare("UPDATE orders SET status = ? WHERE order_id = ?");
|
||||
$stmt->execute([$new_status, $order_id]);
|
||||
|
||||
// Refresh order data
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT o.*,
|
||||
COALESCE(u.username, 'N/A') AS username,
|
||||
COALESCE(u.first_name, '') AS first_name,
|
||||
COALESCE(u.last_name, '') AS last_name,
|
||||
COALESCE(u.email, 'Not provided') AS email,
|
||||
COALESCE(u.phone, 'Not provided') AS phone
|
||||
FROM orders o
|
||||
LEFT JOIN users u ON o.customer_id = u.user_id
|
||||
WHERE o.order_id = ?
|
||||
");
|
||||
$stmt->execute([$order_id]);
|
||||
$order = $stmt->fetch();
|
||||
|
||||
$success_message = 'Order status updated successfully!';
|
||||
} catch (PDOException $e) {
|
||||
$error_message = 'Failed to update order status. Please try again.';
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Order #<?php echo $order_id; ?> - UniMarket</title>
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/style.css">
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/responsive.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||
<style>
|
||||
.order-detail-container {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.order-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.order-card {
|
||||
background-color: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
padding: 20px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.customer-info {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.info-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 20px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
font-weight: 600;
|
||||
color: #666;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.order-status {
|
||||
display: inline-block;
|
||||
padding: 8px 15px;
|
||||
border-radius: 4px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.status-pending {
|
||||
background-color: #fff3cd;
|
||||
color: #856404;
|
||||
}
|
||||
|
||||
.status-processing {
|
||||
background-color: #cce5ff;
|
||||
color: #004085;
|
||||
}
|
||||
|
||||
.status-ready {
|
||||
background-color: #d4edda;
|
||||
color: #155724;
|
||||
}
|
||||
|
||||
.status-completed {
|
||||
background-color: #d4edda;
|
||||
color: #155724;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.status-cancelled {
|
||||
background-color: #f8d7da;
|
||||
color: #721c24;
|
||||
}
|
||||
|
||||
.items-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.items-table th, .items-table td {
|
||||
padding: 12px 15px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.items-table th {
|
||||
background-color: #f5f5f5;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.product-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.product-image {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
margin-right: 15px;
|
||||
background-color: #f9f9f9;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.product-image img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
.item-size {
|
||||
color: #666;
|
||||
font-size: 0.9em;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.order-total {
|
||||
text-align: right;
|
||||
margin-top: 20px;
|
||||
font-size: 1.2rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.back-link {
|
||||
display: inline-block;
|
||||
margin-bottom: 20px;
|
||||
color: var(--primary-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.back-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.status-form {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.status-form select {
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.status-form select:disabled,
|
||||
.status-form button:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.status-note {
|
||||
display: inline-block;
|
||||
margin-left: 10px;
|
||||
color: #666;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.completed-note {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: #155724;
|
||||
font-weight: 500;
|
||||
padding: 8px 15px;
|
||||
background-color: #d4edda;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.completed-note i {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.items-table {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.product-cell {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.product-image {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.status-form {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<?php include '../../includes/header.php'; ?>
|
||||
|
||||
<div class="container order-detail-container">
|
||||
<a href="/unimarket/owner/orders/list.php" class="back-link">
|
||||
<i class="fas fa-arrow-left"></i> Back to Orders
|
||||
</a>
|
||||
|
||||
<div class="order-header">
|
||||
<h1>Order #<?php echo $order_id; ?></h1>
|
||||
<?php
|
||||
$status_class = '';
|
||||
switch ($order['status'] ?? '') {
|
||||
case 'pending':
|
||||
$status_class = 'status-pending';
|
||||
break;
|
||||
case 'processing':
|
||||
$status_class = 'status-processing';
|
||||
break;
|
||||
case 'ready':
|
||||
$status_class = 'status-ready';
|
||||
break;
|
||||
case 'completed':
|
||||
$status_class = 'status-completed';
|
||||
break;
|
||||
case 'cancelled':
|
||||
$status_class = 'status-cancelled';
|
||||
break;
|
||||
default:
|
||||
$status_class = 'status-pending';
|
||||
}
|
||||
?>
|
||||
<span class="order-status <?php echo $status_class; ?>">
|
||||
<?php echo ucfirst(str_replace('_', ' ', $order['status'] ?? 'pending')); ?>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<?php if (isset($success_message)): ?>
|
||||
<div class="alert alert-success"><?php echo $success_message; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (isset($error_message)): ?>
|
||||
<div class="alert alert-error"><?php echo $error_message; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="order-card card">
|
||||
<h2>Customer Information</h2>
|
||||
<div class="customer-info">
|
||||
<div class="info-grid">
|
||||
<div class="info-item">
|
||||
<div class="info-label">Name</div>
|
||||
<div class="info-value">
|
||||
<?php
|
||||
$first_name = $order['first_name'] ?? '';
|
||||
$last_name = $order['last_name'] ?? '';
|
||||
echo htmlspecialchars(trim("$first_name $last_name") ?: 'Not provided');
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-item">
|
||||
<div class="info-label">Username</div>
|
||||
<div class="info-value"><?php echo htmlspecialchars($order['username'] ?? 'N/A'); ?></div>
|
||||
</div>
|
||||
|
||||
<div class="info-item">
|
||||
<div class="info-label">Email</div>
|
||||
<div class="info-value"><?php echo htmlspecialchars($order['email'] ?? 'Not provided'); ?></div>
|
||||
</div>
|
||||
|
||||
<div class="info-item">
|
||||
<div class="info-label">Phone</div>
|
||||
<div class="info-value"><?php echo htmlspecialchars($order['phone'] ?? 'Not provided'); ?></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Order Information</h2>
|
||||
<div class="order-info">
|
||||
<p><strong>Order Date:</strong> <?php echo date('F j, Y g:i A', strtotime($order['order_date'])); ?></p>
|
||||
<p><strong>Total Amount:</strong> ₱<?php echo number_format($order['total_amount'], 2); ?></p>
|
||||
<?php if ($order['status'] !== 'ready'): ?>
|
||||
<p><strong>Pickup Schedule:</strong> <?php echo date('F j, Y g:i A', strtotime($order['pickup_schedule'])); ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<form method="POST" class="status-form">
|
||||
<?php if ($order['status'] !== 'completed'): ?>
|
||||
<label for="status">Update Status:</label>
|
||||
<select name="status" id="status">
|
||||
<option value="pending" <?php echo $order['status'] === 'pending' ? 'selected' : ''; ?>>Pending</option>
|
||||
<option value="processing" <?php echo $order['status'] === 'processing' ? 'selected' : ''; ?>>Processing</option>
|
||||
<option value="ready" <?php echo $order['status'] === 'ready' ? 'selected' : ''; ?>>Ready for Pickup</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" name="update_status" class="btn">
|
||||
<i class="fas fa-save"></i> Update
|
||||
</button>
|
||||
<?php else: ?>
|
||||
<div class="completed-note">
|
||||
<i class="fas fa-check-circle"></i> Order is completed and cannot be modified
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="order-card card">
|
||||
<h2>Order Items (Your Products)</h2>
|
||||
<table class="items-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Product</th>
|
||||
<th>Price</th>
|
||||
<th>Size</th>
|
||||
<th>Quantity</th>
|
||||
<th>Subtotal</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($order_items as $item): ?>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="product-cell">
|
||||
<div class="product-image">
|
||||
<?php if ($item['image_path']): ?>
|
||||
<img src="/unimarket/assets/images/products/<?php echo $item['image_path']; ?>" alt="<?php echo htmlspecialchars($item['name']); ?>">
|
||||
<?php else: ?>
|
||||
<i class="fas fa-box-open" style="color: #ccc;"></i>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div>
|
||||
<h4><?php echo htmlspecialchars($item['name']); ?></h4>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>₱<?php echo number_format($item['price'], 2); ?></td>
|
||||
<td>
|
||||
<?php if ($item['category'] === 'clothes' && $item['size']): ?>
|
||||
<span class="item-size"><?php echo htmlspecialchars($item['size']); ?></span>
|
||||
<?php else: ?>
|
||||
-
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?php echo $item['quantity']; ?></td>
|
||||
<td>₱<?php echo number_format($item['price'] * $item['quantity'], 2); ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="order-total">
|
||||
<div style="margin-bottom: 10px;">Subtotal: $<?php echo number_format($subtotal, 2); ?></div>
|
||||
<div style="font-size: 1.4rem;">Total: $<?php echo number_format($subtotal, 2); ?></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include '../../includes/footer.php'; ?>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,545 @@
|
||||
<?php
|
||||
require_once '../../includes/auth_functions.php';
|
||||
redirectIfNotLoggedIn();
|
||||
redirectIfNotOwner();
|
||||
|
||||
require_once '../../config/database.php';
|
||||
|
||||
$error_message = '';
|
||||
$success_message = '';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$name = trim($_POST['name']);
|
||||
$description = trim($_POST['description']);
|
||||
$price = trim($_POST['price']);
|
||||
$category = trim($_POST['category']);
|
||||
$subcategory = trim($_POST['subcategory']);
|
||||
$stock_quantity = (int)$_POST['stock_quantity'];
|
||||
|
||||
// Get size data if category is clothes
|
||||
$size_data = null;
|
||||
if ($category === 'clothes' && isset($_POST['sizes']) && isset($_POST['size_quantities'])) {
|
||||
$sizes = $_POST['sizes'];
|
||||
$quantities = $_POST['size_quantities'];
|
||||
$size_data = [];
|
||||
|
||||
for ($i = 0; $i < count($sizes); $i++) {
|
||||
if (!empty($sizes[$i]) && isset($quantities[$i]) && $quantities[$i] > 0) {
|
||||
$size_data[$sizes[$i]] = (int)$quantities[$i];
|
||||
}
|
||||
}
|
||||
|
||||
// Update stock quantity based on sizes
|
||||
$stock_quantity = array_sum($size_data);
|
||||
}
|
||||
|
||||
// Validate inputs
|
||||
if (empty($name) || empty($description) || empty($price) || empty($stock_quantity)) {
|
||||
$error_message = 'Please fill in all required fields.';
|
||||
} elseif (!is_numeric($price) || $price <= 0) {
|
||||
$error_message = 'Please enter a valid price.';
|
||||
} elseif ($stock_quantity < 0) {
|
||||
$error_message = 'Stock quantity cannot be negative.';
|
||||
} elseif ($category === 'clothes' && empty($size_data)) {
|
||||
$error_message = 'Please add at least one size with quantity.';
|
||||
} else {
|
||||
try {
|
||||
// Handle file upload
|
||||
$image_path = null;
|
||||
if (isset($_FILES['image']) && $_FILES['image']['error'] === UPLOAD_ERR_OK) {
|
||||
$upload_dir = '../../uploads/products/';
|
||||
// Create directory if it doesn't exist
|
||||
if (!file_exists($upload_dir)) {
|
||||
mkdir($upload_dir, 0777, true);
|
||||
}
|
||||
$file_extension = pathinfo($_FILES['image']['name'], PATHINFO_EXTENSION);
|
||||
$filename = uniqid() . '.' . $file_extension;
|
||||
$destination = $upload_dir . $filename;
|
||||
|
||||
// Validate image
|
||||
$allowed_types = ['jpg', 'jpeg', 'png', 'gif'];
|
||||
if (!in_array(strtolower($file_extension), $allowed_types)) {
|
||||
$error_message = 'Only JPG, JPEG, PNG, and GIF files are allowed.';
|
||||
} elseif ($_FILES['image']['size'] > 5000000) { // 5MB max
|
||||
$error_message = 'File size must be less than 5MB.';
|
||||
} elseif (move_uploaded_file($_FILES['image']['tmp_name'], $destination)) {
|
||||
$image_path = $filename;
|
||||
} else {
|
||||
$error_message = 'Failed to upload image.';
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($error_message)) {
|
||||
$pdo->beginTransaction();
|
||||
|
||||
try {
|
||||
$stmt = $pdo->prepare("
|
||||
INSERT INTO products
|
||||
(owner_id, name, description, price, category, Sub_Cat, stock_quantity, image_path, size_data)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
");
|
||||
$stmt->execute([
|
||||
$_SESSION['user_id'],
|
||||
$name,
|
||||
$description,
|
||||
$price,
|
||||
$category,
|
||||
$subcategory,
|
||||
$stock_quantity,
|
||||
$image_path,
|
||||
$size_data ? json_encode($size_data) : null
|
||||
]);
|
||||
|
||||
$pdo->commit();
|
||||
$success_message = 'Product added successfully!';
|
||||
|
||||
// Clear form
|
||||
$name = $description = $price = $category = $subcategory = '';
|
||||
$stock_quantity = 0;
|
||||
} catch (PDOException $e) {
|
||||
$pdo->rollBack();
|
||||
$error_message = 'Failed to add product: ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$pdo->rollBack();
|
||||
$error_message = 'Failed to add product. Please try again.';
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Add Product - UniMarket</title>
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/style.css">
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/responsive.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||
<style>
|
||||
.add-product-container {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.image-upload {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.image-preview {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
background-color: #f5f5f5;
|
||||
border: 1px dashed #ccc;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.image-preview.has-image {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.image-preview img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
.default-text {
|
||||
color: #999;
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.form-group input,
|
||||
.form-group textarea,
|
||||
.form-group select {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.form-group textarea {
|
||||
min-height: 100px;
|
||||
}
|
||||
|
||||
.btn-submit {
|
||||
background-color: var(--primary-color);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 12px 20px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 1rem;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
.btn-submit:hover {
|
||||
background-color: var(--primary-dark);
|
||||
}
|
||||
|
||||
.subcategory-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.subcategory-divider {
|
||||
color: #666;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
#subcategory, #customSubcategory {
|
||||
flex: 1;
|
||||
padding: 10px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
#customSubcategory {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.size-row {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-bottom: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.size-select, .size-quantity {
|
||||
padding: 8px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.size-select {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.size-quantity {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.btn-remove-size {
|
||||
background: #ff4444;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
cursor: pointer;
|
||||
font-size: 18px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.btn-add-size {
|
||||
background: var(--primary-color);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 8px 16px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.btn-add-size:hover {
|
||||
background: var(--primary-dark);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<?php include '../../includes/header.php'; ?>
|
||||
|
||||
<div class="container add-product-container">
|
||||
<h1>Add New Product</h1>
|
||||
|
||||
<?php if ($success_message): ?>
|
||||
<div class="alert alert-success"><?php echo $success_message; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($error_message): ?>
|
||||
<div class="alert alert-error"><?php echo $error_message; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="POST" enctype="multipart/form-data" class="card">
|
||||
<div class="form-group image-upload">
|
||||
<label>Product Image</label>
|
||||
<input type="file" name="image" id="productImage" accept="image/*">
|
||||
<div class="image-preview" id="imagePreview">
|
||||
<div class="default-text">No image selected</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="name">Product Name*</label>
|
||||
<input type="text" id="name" name="name" value="<?php echo htmlspecialchars($name ?? ''); ?>" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="description">Description*</label>
|
||||
<textarea id="description" name="description" required><?php echo htmlspecialchars($description ?? ''); ?></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="price">Price*</label>
|
||||
<input type="number" id="price" name="price" step="0.01" min="0.01" value="<?php echo htmlspecialchars($price ?? ''); ?>" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="category">Category*</label>
|
||||
<select id="category" name="category" required onchange="updateSubcategories()">
|
||||
<option value="">Select a category</option>
|
||||
<option value="clothes" <?php echo (isset($category) && $category === 'clothes') ? 'selected' : ''; ?>>Clothes</option>
|
||||
<option value="school_supplies" <?php echo (isset($category) && $category === 'school_supplies') ? 'selected' : ''; ?>>School Supplies</option>
|
||||
<option value="others" <?php echo (isset($category) && $category === 'others') ? 'selected' : ''; ?>>Others</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="subcategoryGroup" style="display: none;">
|
||||
<label for="subcategory">Subcategory*</label>
|
||||
<div class="subcategory-container">
|
||||
<select id="subcategory" name="subcategory" onchange="handleSubcategoryChange()">
|
||||
<option value="">Select a subcategory</option>
|
||||
</select>
|
||||
<div class="subcategory-divider">or</div>
|
||||
<input type="text" id="customSubcategory" name="customSubcategory" placeholder="Type your own subcategory">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="stock_quantity">Stock Quantity*</label>
|
||||
<input type="number" id="stock_quantity" name="stock_quantity" min="0" value="<?php echo htmlspecialchars($stock_quantity ?? 0); ?>" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="sizeGroup" style="display: none;">
|
||||
<label>Sizes and Quantities*</label>
|
||||
<div id="sizeContainer">
|
||||
<!-- Size rows will be added here dynamically -->
|
||||
</div>
|
||||
<button type="button" class="btn-add-size" onclick="addSizeRow()">
|
||||
<i class="fas fa-plus"></i> Add Size
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn-submit">Add Product</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<?php include '../../includes/footer.php'; ?>
|
||||
|
||||
<script>
|
||||
// Image preview functionality
|
||||
const productImage = document.getElementById('productImage');
|
||||
const imagePreview = document.getElementById('imagePreview');
|
||||
const defaultText = imagePreview.querySelector('.default-text');
|
||||
|
||||
productImage.addEventListener('change', function() {
|
||||
const file = this.files[0];
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = function(e) {
|
||||
imagePreview.innerHTML = '';
|
||||
const img = document.createElement('img');
|
||||
img.src = e.target.result;
|
||||
imagePreview.appendChild(img);
|
||||
imagePreview.classList.add('has-image');
|
||||
}
|
||||
|
||||
reader.readAsDataURL(file);
|
||||
} else {
|
||||
imagePreview.innerHTML = '<div class="default-text">No image selected</div>';
|
||||
imagePreview.classList.remove('has-image');
|
||||
}
|
||||
});
|
||||
|
||||
const subcategories = {
|
||||
clothes: [
|
||||
'T-Shirts',
|
||||
'Pants',
|
||||
'PE Uniform',
|
||||
'University Uniform',
|
||||
],
|
||||
school_supplies: [
|
||||
'Notebooks',
|
||||
'Pens',
|
||||
'Pencils',
|
||||
'Highlighters',
|
||||
'Markers',
|
||||
'Art Supplies',
|
||||
'Paper',
|
||||
'Folders',
|
||||
'Binders',
|
||||
'Staplers'
|
||||
],
|
||||
others: [
|
||||
'University Lace',
|
||||
'Hygiene Products',
|
||||
'Seals',
|
||||
'Calculator',
|
||||
'ID Holders'
|
||||
]
|
||||
};
|
||||
|
||||
function updateSubcategories() {
|
||||
const categorySelect = document.getElementById('category');
|
||||
const subcategorySelect = document.getElementById('subcategory');
|
||||
const subcategoryGroup = document.getElementById('subcategoryGroup');
|
||||
const customSubcategory = document.getElementById('customSubcategory');
|
||||
const sizeGroup = document.getElementById('sizeGroup');
|
||||
const stockQuantityInput = document.getElementById('stock_quantity');
|
||||
const selectedCategory = categorySelect.value;
|
||||
|
||||
// Clear current options
|
||||
subcategorySelect.innerHTML = '<option value="">Select a subcategory</option>';
|
||||
|
||||
if (selectedCategory && subcategories[selectedCategory]) {
|
||||
// Show subcategory group
|
||||
subcategoryGroup.style.display = 'block';
|
||||
subcategorySelect.style.display = 'block';
|
||||
customSubcategory.style.display = 'none';
|
||||
|
||||
// Add new options
|
||||
subcategories[selectedCategory].forEach(subcategory => {
|
||||
const option = document.createElement('option');
|
||||
option.value = subcategory.toLowerCase().replace(/\s+/g, '_');
|
||||
option.textContent = subcategory;
|
||||
subcategorySelect.appendChild(option);
|
||||
});
|
||||
|
||||
// Add custom option
|
||||
const customOption = document.createElement('option');
|
||||
customOption.value = 'custom';
|
||||
customOption.textContent = 'Other (Type your own)';
|
||||
subcategorySelect.appendChild(customOption);
|
||||
|
||||
// Show/hide size group based on category
|
||||
if (selectedCategory === 'clothes') {
|
||||
sizeGroup.style.display = 'block';
|
||||
stockQuantityInput.style.display = 'none';
|
||||
stockQuantityInput.value = calculateTotalSizeQuantity();
|
||||
} else {
|
||||
sizeGroup.style.display = 'none';
|
||||
stockQuantityInput.style.display = 'block';
|
||||
}
|
||||
} else {
|
||||
// Hide subcategory group if no category selected
|
||||
subcategoryGroup.style.display = 'none';
|
||||
sizeGroup.style.display = 'none';
|
||||
stockQuantityInput.style.display = 'block';
|
||||
}
|
||||
}
|
||||
|
||||
function handleSubcategoryChange() {
|
||||
const subcategorySelect = document.getElementById('subcategory');
|
||||
const customSubcategory = document.getElementById('customSubcategory');
|
||||
|
||||
if (subcategorySelect.value === 'custom') {
|
||||
subcategorySelect.style.display = 'none';
|
||||
customSubcategory.style.display = 'block';
|
||||
customSubcategory.focus();
|
||||
customSubcategory.required = true;
|
||||
} else {
|
||||
subcategorySelect.style.display = 'block';
|
||||
customSubcategory.style.display = 'none';
|
||||
customSubcategory.required = false;
|
||||
}
|
||||
}
|
||||
|
||||
function addSizeRow() {
|
||||
const container = document.getElementById('sizeContainer');
|
||||
const newRow = document.createElement('div');
|
||||
newRow.className = 'size-row';
|
||||
newRow.innerHTML = `
|
||||
<select name="sizes[]" class="size-select" onchange="updateTotalQuantity()">
|
||||
<option value="">Select Size</option>
|
||||
<option value="XS">XS</option>
|
||||
<option value="S">S</option>
|
||||
<option value="M">M</option>
|
||||
<option value="L">L</option>
|
||||
<option value="XL">XL</option>
|
||||
<option value="XXL">XXL</option>
|
||||
</select>
|
||||
<input type="number" name="size_quantities[]" min="0" placeholder="Quantity" class="size-quantity" onchange="updateTotalQuantity()">
|
||||
<button type="button" class="btn-remove-size" onclick="removeSizeRow(this)">×</button>
|
||||
`;
|
||||
container.appendChild(newRow);
|
||||
}
|
||||
|
||||
function removeSizeRow(button) {
|
||||
button.parentElement.remove();
|
||||
updateTotalQuantity();
|
||||
}
|
||||
|
||||
function calculateTotalSizeQuantity() {
|
||||
const quantities = document.getElementsByName('size_quantities[]');
|
||||
let total = 0;
|
||||
for (let input of quantities) {
|
||||
total += parseInt(input.value) || 0;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
function updateTotalQuantity() {
|
||||
const stockQuantityInput = document.getElementById('stock_quantity');
|
||||
stockQuantityInput.value = calculateTotalSizeQuantity();
|
||||
}
|
||||
|
||||
// Form submission validation
|
||||
document.querySelector('form').addEventListener('submit', function(e) {
|
||||
const category = document.getElementById('category').value;
|
||||
const subcategorySelect = document.getElementById('subcategory');
|
||||
const customSubcategory = document.getElementById('customSubcategory');
|
||||
|
||||
if (subcategorySelect.style.display === 'none' && !customSubcategory.value.trim()) {
|
||||
e.preventDefault();
|
||||
alert('Please enter a subcategory');
|
||||
return;
|
||||
}
|
||||
|
||||
if (category === 'clothes') {
|
||||
const sizeSelects = document.getElementsByName('sizes[]');
|
||||
const sizeQuantities = document.getElementsByName('size_quantities[]');
|
||||
let hasValidSize = false;
|
||||
|
||||
for (let i = 0; i < sizeSelects.length; i++) {
|
||||
if (sizeSelects[i].value && sizeQuantities[i].value > 0) {
|
||||
hasValidSize = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasValidSize) {
|
||||
e.preventDefault();
|
||||
alert('Please add at least one size with quantity');
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize subcategories on page load
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
updateSubcategories();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,513 @@
|
||||
<?php
|
||||
require_once '../../includes/auth_functions.php';
|
||||
redirectIfNotLoggedIn();
|
||||
redirectIfNotOwner();
|
||||
|
||||
require_once '../../config/database.php';
|
||||
|
||||
// Check if product ID is provided
|
||||
if (!isset($_GET['id'])) {
|
||||
header("Location: /unimarket/owner/products/list.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
$product_id = (int)$_GET['id'];
|
||||
|
||||
// Verify product belongs to current owner
|
||||
$stmt = $pdo->prepare("SELECT * FROM products WHERE product_id = ? AND owner_id = ?");
|
||||
$stmt->execute([$product_id, $_SESSION['user_id']]);
|
||||
$product = $stmt->fetch();
|
||||
|
||||
if (!$product) {
|
||||
header("Location: /unimarket/owner/products/list.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
$error_message = '';
|
||||
$success_message = '';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$name = trim($_POST['name']);
|
||||
$description = trim($_POST['description']);
|
||||
$price = trim($_POST['price']);
|
||||
$category = trim($_POST['category']);
|
||||
$stock_quantity = (int)$_POST['stock_quantity'];
|
||||
|
||||
// Get size data if category is clothes
|
||||
$size_data = null;
|
||||
if ($category === 'clothes' && isset($_POST['sizes']) && isset($_POST['size_quantities'])) {
|
||||
$sizes = $_POST['sizes'];
|
||||
$quantities = $_POST['size_quantities'];
|
||||
$size_data = [];
|
||||
|
||||
for ($i = 0; $i < count($sizes); $i++) {
|
||||
if (!empty($sizes[$i]) && isset($quantities[$i]) && $quantities[$i] > 0) {
|
||||
$size_data[$sizes[$i]] = (int)$quantities[$i];
|
||||
}
|
||||
}
|
||||
|
||||
// Update stock quantity based on sizes
|
||||
$stock_quantity = array_sum($size_data);
|
||||
}
|
||||
|
||||
// Validate inputs
|
||||
if (empty($name) || empty($description) || empty($price) || empty($stock_quantity)) {
|
||||
$error_message = 'Please fill in all required fields.';
|
||||
} elseif (!is_numeric($price) || $price <= 0) {
|
||||
$error_message = 'Please enter a valid price.';
|
||||
} elseif ($stock_quantity < 0) {
|
||||
$error_message = 'Stock quantity cannot be negative.';
|
||||
} elseif ($category === 'clothes' && empty($size_data)) {
|
||||
$error_message = 'Please add at least one size with quantity.';
|
||||
} else {
|
||||
try {
|
||||
$pdo->beginTransaction();
|
||||
|
||||
// Handle file upload if new image is provided
|
||||
$image_path = $product['image_path'];
|
||||
if (isset($_FILES['image']) && $_FILES['image']['error'] === UPLOAD_ERR_OK) {
|
||||
$upload_dir = '../../assets/images/products/';
|
||||
$file_extension = pathinfo($_FILES['image']['name'], PATHINFO_EXTENSION);
|
||||
$filename = uniqid() . '.' . $file_extension;
|
||||
$destination = $upload_dir . $filename;
|
||||
|
||||
// Validate image
|
||||
$allowed_types = ['jpg', 'jpeg', 'png', 'gif'];
|
||||
if (!in_array(strtolower($file_extension), $allowed_types)) {
|
||||
$error_message = 'Only JPG, JPEG, PNG, and GIF files are allowed.';
|
||||
} elseif ($_FILES['image']['size'] > 5000000) { // 5MB max
|
||||
$error_message = 'File size must be less than 5MB.';
|
||||
} else {
|
||||
// Delete old image if it exists
|
||||
if ($image_path && file_exists($upload_dir . $image_path)) {
|
||||
unlink($upload_dir . $image_path);
|
||||
}
|
||||
|
||||
if (move_uploaded_file($_FILES['image']['tmp_name'], $destination)) {
|
||||
$image_path = $filename;
|
||||
} else {
|
||||
$error_message = 'Failed to upload image.';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($error_message)) {
|
||||
$stmt = $pdo->prepare("
|
||||
UPDATE products
|
||||
SET name = ?, description = ?, price = ?, category = ?, stock_quantity = ?, image_path = ?, size_data = ?
|
||||
WHERE product_id = ? AND owner_id = ?
|
||||
");
|
||||
$stmt->execute([
|
||||
$name,
|
||||
$description,
|
||||
$price,
|
||||
$category,
|
||||
$stock_quantity,
|
||||
$image_path,
|
||||
$size_data ? json_encode($size_data) : null,
|
||||
$product_id,
|
||||
$_SESSION['user_id']
|
||||
]);
|
||||
|
||||
if ($stmt->rowCount() > 0) {
|
||||
$pdo->commit();
|
||||
$success_message = 'Product updated successfully!';
|
||||
|
||||
// Refresh product data
|
||||
$stmt = $pdo->prepare("SELECT * FROM products WHERE product_id = ?");
|
||||
$stmt->execute([$product_id]);
|
||||
$product = $stmt->fetch();
|
||||
} else {
|
||||
throw new Exception('No changes were made to the product.');
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$pdo->rollBack();
|
||||
$error_message = 'Failed to update product: ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Decode size data if exists
|
||||
$size_data = null;
|
||||
if (isset($product['size_data']) && $product['size_data']) {
|
||||
$size_data = json_decode($product['size_data'], true);
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Edit Product - UniMarket</title>
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/style.css">
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/responsive.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||
<style>
|
||||
.edit-product-container {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.image-upload {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.image-preview {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
background-color: #f5f5f5;
|
||||
border: 1px dashed #ccc;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.image-preview.has-image {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.image-preview img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
.default-text {
|
||||
color: #999;
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.form-group input,
|
||||
.form-group textarea,
|
||||
.form-group select {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.form-group textarea {
|
||||
min-height: 100px;
|
||||
}
|
||||
|
||||
.btn-submit {
|
||||
background-color: var(--primary-color);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 12px 20px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 1rem;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
.btn-submit:hover {
|
||||
background-color: var(--primary-dark);
|
||||
}
|
||||
|
||||
.btn-delete {
|
||||
background-color: #dc3545;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 12px 20px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 1rem;
|
||||
transition: background-color 0.3s;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.btn-delete:hover {
|
||||
background-color: #c82333;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.size-row {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-bottom: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.size-select, .size-quantity {
|
||||
padding: 8px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.size-select {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.size-quantity {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.btn-remove-size {
|
||||
background: #ff4444;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
cursor: pointer;
|
||||
font-size: 18px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.btn-add-size {
|
||||
background: var(--primary-color);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 8px 16px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.btn-add-size:hover {
|
||||
background: var(--primary-dark);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<?php include '../../includes/header.php'; ?>
|
||||
|
||||
<div class="container edit-product-container">
|
||||
<h1>Edit Product</h1>
|
||||
|
||||
<?php if ($success_message): ?>
|
||||
<div class="alert alert-success"><?php echo $success_message; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($error_message): ?>
|
||||
<div class="alert alert-error"><?php echo $error_message; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="POST" enctype="multipart/form-data" class="card">
|
||||
<div class="form-group image-upload">
|
||||
<label>Product Image</label>
|
||||
<input type="file" name="image" id="productImage" accept="image/*">
|
||||
<div class="image-preview" id="imagePreview">
|
||||
<?php if ($product['image_path']): ?>
|
||||
<img src="/unimarket/assets/images/products/<?php echo $product['image_path']; ?>" alt="<?php echo htmlspecialchars($product['name']); ?>">
|
||||
<?php else: ?>
|
||||
<div class="default-text">No image selected</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="name">Product Name*</label>
|
||||
<input type="text" id="name" name="name" value="<?php echo htmlspecialchars($product['name']); ?>" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="description">Description*</label>
|
||||
<textarea id="description" name="description" required><?php echo htmlspecialchars($product['description']); ?></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="price">Price*</label>
|
||||
<input type="number" id="price" name="price" step="0.01" min="0.01" value="<?php echo htmlspecialchars($product['price']); ?>" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="category">Category</label>
|
||||
<select id="category" name="category" onchange="updateSubcategories()">
|
||||
<option value="">Select a category</option>
|
||||
<option value="clothes" <?php echo $product['category'] === 'clothes' ? 'selected' : ''; ?>>Clothes</option>
|
||||
<option value="school_supplies" <?php echo $product['category'] === 'school_supplies' ? 'selected' : ''; ?>>School Supplies</option>
|
||||
<option value="others" <?php echo $product['category'] === 'others' ? 'selected' : ''; ?>>Others</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group" id="sizeGroup" style="display: <?php echo isset($product['category']) && $product['category'] === 'clothes' ? 'block' : 'none'; ?>;">
|
||||
<label>Sizes and Quantities*</label>
|
||||
<div id="sizeContainer">
|
||||
<?php if ($size_data && is_array($size_data)): ?>
|
||||
<?php foreach ($size_data as $size => $quantity): ?>
|
||||
<div class="size-row">
|
||||
<select name="sizes[]" class="size-select">
|
||||
<option value="">Select Size</option>
|
||||
<option value="XS" <?php echo $size === 'XS' ? 'selected' : ''; ?>>XS</option>
|
||||
<option value="S" <?php echo $size === 'S' ? 'selected' : ''; ?>>S</option>
|
||||
<option value="M" <?php echo $size === 'M' ? 'selected' : ''; ?>>M</option>
|
||||
<option value="L" <?php echo $size === 'L' ? 'selected' : ''; ?>>L</option>
|
||||
<option value="XL" <?php echo $size === 'XL' ? 'selected' : ''; ?>>XL</option>
|
||||
<option value="XXL" <?php echo $size === 'XXL' ? 'selected' : ''; ?>>XXL</option>
|
||||
</select>
|
||||
<input type="number" name="size_quantities[]" min="0" placeholder="Quantity" class="size-quantity" value="<?php echo $quantity; ?>">
|
||||
<button type="button" class="btn-remove-size" onclick="removeSizeRow(this)">×</button>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php else: ?>
|
||||
<div class="size-row">
|
||||
<select name="sizes[]" class="size-select">
|
||||
<option value="">Select Size</option>
|
||||
<option value="XS">XS</option>
|
||||
<option value="S">S</option>
|
||||
<option value="M">M</option>
|
||||
<option value="L">L</option>
|
||||
<option value="XL">XL</option>
|
||||
<option value="XXL">XXL</option>
|
||||
</select>
|
||||
<input type="number" name="size_quantities[]" min="0" placeholder="Quantity" class="size-quantity">
|
||||
<button type="button" class="btn-remove-size" onclick="removeSizeRow(this)">×</button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<button type="button" class="btn-add-size" onclick="addSizeRow()">Add Another Size</button>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="stock_quantity">Stock Quantity*</label>
|
||||
<input type="number" id="stock_quantity" name="stock_quantity" min="0" value="<?php echo htmlspecialchars($product['stock_quantity']); ?>" required>
|
||||
</div>
|
||||
|
||||
<div class="button-group">
|
||||
<button type="submit" class="btn-submit">Update Product</button>
|
||||
<a href="/unimarket/owner/products/delete.php?id=<?php echo $product_id; ?>" class="btn-delete" onclick="return confirm('Are you sure you want to delete this product?')">
|
||||
<i class="fas fa-trash"></i> Delete
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<?php include '../../includes/footer.php'; ?>
|
||||
|
||||
<script>
|
||||
// Image preview functionality
|
||||
const productImage = document.getElementById('productImage');
|
||||
const imagePreview = document.getElementById('imagePreview');
|
||||
|
||||
productImage.addEventListener('change', function() {
|
||||
const file = this.files[0];
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = function(e) {
|
||||
imagePreview.innerHTML = '';
|
||||
const img = document.createElement('img');
|
||||
img.src = e.target.result;
|
||||
imagePreview.appendChild(img);
|
||||
imagePreview.classList.add('has-image');
|
||||
}
|
||||
|
||||
reader.readAsDataURL(file);
|
||||
} else {
|
||||
<?php if ($product['image_path']): ?>
|
||||
imagePreview.innerHTML = '<img src="/unimarket/assets/images/products/<?php echo $product['image_path']; ?>" alt="<?php echo htmlspecialchars($product['name']); ?>">';
|
||||
<?php else: ?>
|
||||
imagePreview.innerHTML = '<div class="default-text">No image selected</div>';
|
||||
imagePreview.classList.remove('has-image');
|
||||
<?php endif; ?>
|
||||
}
|
||||
});
|
||||
|
||||
function updateSubcategories() {
|
||||
const categorySelect = document.getElementById('category');
|
||||
const sizeGroup = document.getElementById('sizeGroup');
|
||||
const stockQuantityInput = document.getElementById('stock_quantity');
|
||||
const selectedCategory = categorySelect.value;
|
||||
|
||||
if (selectedCategory === 'clothes') {
|
||||
sizeGroup.style.display = 'block';
|
||||
stockQuantityInput.style.display = 'none';
|
||||
stockQuantityInput.value = calculateTotalSizeQuantity();
|
||||
} else {
|
||||
sizeGroup.style.display = 'none';
|
||||
stockQuantityInput.style.display = 'block';
|
||||
}
|
||||
}
|
||||
|
||||
function addSizeRow() {
|
||||
const container = document.getElementById('sizeContainer');
|
||||
const newRow = document.createElement('div');
|
||||
newRow.className = 'size-row';
|
||||
newRow.innerHTML = `
|
||||
<select name="sizes[]" class="size-select" onchange="updateTotalQuantity()">
|
||||
<option value="">Select Size</option>
|
||||
<option value="XS">XS</option>
|
||||
<option value="S">S</option>
|
||||
<option value="M">M</option>
|
||||
<option value="L">L</option>
|
||||
<option value="XL">XL</option>
|
||||
<option value="XXL">XXL</option>
|
||||
</select>
|
||||
<input type="number" name="size_quantities[]" min="0" placeholder="Quantity" class="size-quantity" onchange="updateTotalQuantity()">
|
||||
<button type="button" class="btn-remove-size" onclick="removeSizeRow(this)">×</button>
|
||||
`;
|
||||
container.appendChild(newRow);
|
||||
}
|
||||
|
||||
function removeSizeRow(button) {
|
||||
button.parentElement.remove();
|
||||
updateTotalQuantity();
|
||||
}
|
||||
|
||||
function calculateTotalSizeQuantity() {
|
||||
const quantities = document.getElementsByName('size_quantities[]');
|
||||
let total = 0;
|
||||
for (let input of quantities) {
|
||||
total += parseInt(input.value) || 0;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
function updateTotalQuantity() {
|
||||
const stockQuantityInput = document.getElementById('stock_quantity');
|
||||
stockQuantityInput.value = calculateTotalSizeQuantity();
|
||||
}
|
||||
|
||||
// Form submission validation
|
||||
document.querySelector('form').addEventListener('submit', function(e) {
|
||||
const category = document.getElementById('category').value;
|
||||
|
||||
if (category === 'clothes') {
|
||||
const sizeSelects = document.getElementsByName('sizes[]');
|
||||
const sizeQuantities = document.getElementsByName('size_quantities[]');
|
||||
let hasValidSize = false;
|
||||
|
||||
for (let i = 0; i < sizeSelects.length; i++) {
|
||||
if (sizeSelects[i].value && sizeQuantities[i].value > 0) {
|
||||
hasValidSize = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasValidSize) {
|
||||
e.preventDefault();
|
||||
alert('Please add at least one size with quantity');
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize on page load
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
updateSubcategories();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,213 @@
|
||||
<?php
|
||||
require_once '../../includes/auth_functions.php';
|
||||
redirectIfNotLoggedIn();
|
||||
redirectIfNotOwner();
|
||||
|
||||
require_once '../../config/database.php';
|
||||
|
||||
// Get all products for this owner
|
||||
$stmt = $pdo->prepare("SELECT * FROM products WHERE owner_id = ? ORDER BY created_at DESC");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
$products = $stmt->fetchAll();
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>My Products - UniMarket</title>
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/style.css">
|
||||
<link rel="stylesheet" href="/unimarket/assets/css/responsive.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||
<style>
|
||||
.products-container {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.products-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.products-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.products-table th, .products-table td {
|
||||
padding: 12px 15px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.products-table th {
|
||||
background-color: #f5f5f5;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.product-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.product-image {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
margin-right: 15px;
|
||||
background-color: #f9f9f9;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.product-image img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
.stock-low {
|
||||
color: #e53935;
|
||||
}
|
||||
|
||||
.action-link {
|
||||
text-decoration: none;
|
||||
margin-right: 10px;
|
||||
padding: 5px 10px;
|
||||
border-radius: 4px;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.action-link.edit {
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.action-link.edit:hover {
|
||||
background-color: #218838;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.action-link.delete {
|
||||
background-color: #dc3545;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.action-link.delete:hover {
|
||||
background-color: #c82333;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.empty-products {
|
||||
text-align: center;
|
||||
padding: 50px;
|
||||
background-color: #f9f9f9;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.products-table {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.product-cell {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.product-image {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<?php include '../../includes/header.php'; ?>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h1 class="h3 mb-0">Manage Products</h1>
|
||||
<a href="../dashboard.php" class="btn btn-outline-secondary">
|
||||
<i class="fas fa-arrow-left me-2"></i>Back to Dashboard
|
||||
</a>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="container products-container">
|
||||
<div class="products-header">
|
||||
<h1>My Products</h1>
|
||||
<a href="/unimarket/owner/products/add.php" class="btn" style="background-color: #28a745; color: white;">
|
||||
<i class="fas fa-plus"></i> Add Product
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<?php if (empty($products)): ?>
|
||||
<div class="empty-products card">
|
||||
<i class="fas fa-box-open" style="font-size: 3em; color: #ccc; margin-bottom: 20px;"></i>
|
||||
<h3>You don't have any products yet</h3>
|
||||
<p>Add your first product to start selling</p>
|
||||
<a href="/unimarket/owner/products/add.php" class="btn">Add Product</a>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<table class="products-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Product</th>
|
||||
<th>Price</th>
|
||||
<th>Stock</th>
|
||||
<th>Category</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($products as $product): ?>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="product-cell">
|
||||
<div class="product-image">
|
||||
<?php if ($product['image_path']): ?>
|
||||
<img src="/unimarket/uploads/products/<?php echo $product['image_path']; ?>" alt="<?php echo htmlspecialchars($product['name']); ?>">
|
||||
<?php else: ?>
|
||||
<i class="fas fa-box-open" style="color: #ccc;"></i>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div>
|
||||
<h4><?php echo htmlspecialchars($product['name']); ?></h4>
|
||||
<p><?php echo substr(htmlspecialchars($product['description']), 0, 50); ?>...</p>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>₱<?php echo number_format($product['price'], 2); ?></td>
|
||||
<td class="<?php echo $product['stock_quantity'] < 5 ? 'stock-low' : ''; ?>">
|
||||
<?php echo $product['stock_quantity']; ?>
|
||||
</td>
|
||||
<td><?php echo htmlspecialchars($product['category']); ?></td>
|
||||
<td>
|
||||
<a href="/unimarket/owner/products/edit.php?id=<?php echo $product['product_id']; ?>" class="action-link edit">
|
||||
<i class="fas fa-edit"></i> Edit
|
||||
</a>
|
||||
<a href="/unimarket/owner/products/delete.php?id=<?php echo $product['product_id']; ?>" class="action-link delete" onclick="return confirm('Are you sure you want to delete this product?')">
|
||||
<i class="fas fa-trash"></i> Delete
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include '../../includes/footer.php'; ?>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 2.0 MiB |
|
After Width: | Height: | Size: 2.0 MiB |
|
After Width: | Height: | Size: 2.0 MiB |
|
After Width: | Height: | Size: 2.0 MiB |
|
After Width: | Height: | Size: 2.0 MiB |
|
After Width: | Height: | Size: 2.0 MiB |
|
After Width: | Height: | Size: 2.0 MiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 1.9 MiB |
|
After Width: | Height: | Size: 1.9 MiB |