212 lines
9.6 KiB
PHP
212 lines
9.6 KiB
PHP
<?php
|
|
require_once __DIR__ . "/../includes/functions.php";
|
|
require_permission("loyalty_view");
|
|
require_once __DIR__ . '/../db/config.php';
|
|
$pdo = db();
|
|
|
|
$message = '';
|
|
|
|
// Handle Settings Update
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_settings'])) {
|
|
if (!has_permission('loyalty_add')) {
|
|
$message = '<div class="alert alert-danger">Access Denied: You do not have permission to update loyalty settings.</div>';
|
|
} else {
|
|
$points_per_order = intval($_POST['points_per_order']);
|
|
$points_for_free_meal = intval($_POST['points_for_free_meal']);
|
|
$is_enabled = isset($_POST['is_enabled']) ? 1 : 0;
|
|
|
|
$stmt = $pdo->prepare("UPDATE loyalty_settings SET points_per_order = ?, points_for_free_meal = ?, is_enabled = ? WHERE id = 1");
|
|
$stmt->execute([$points_per_order, $points_for_free_meal, $is_enabled]);
|
|
|
|
$message = '<div class="alert alert-success">Loyalty settings updated successfully!</div>';
|
|
}
|
|
}
|
|
|
|
// Fetch Settings
|
|
$stmt = $pdo->query("SELECT * FROM loyalty_settings WHERE id = 1");
|
|
$settings = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if (!$settings) {
|
|
// Default fallback if migration failed or empty
|
|
$settings = ['points_per_order' => 10, 'points_for_free_meal' => 70, 'is_enabled' => 1];
|
|
}
|
|
|
|
// Fetch Customers with Points
|
|
$page = isset($_GET['page']) ? max(1, intval($_GET['page'])) : 1;
|
|
$limit = 20;
|
|
$offset = ($page - 1) * $limit;
|
|
|
|
$count_stmt = $pdo->query("SELECT COUNT(*) FROM customers WHERE points > 0");
|
|
$total_customers = $count_stmt->fetchColumn();
|
|
$total_pages = ceil($total_customers / $limit);
|
|
|
|
$query = "SELECT * FROM customers WHERE points > 0 ORDER BY points DESC LIMIT $limit OFFSET $offset";
|
|
$stmt = $pdo->query($query);
|
|
$customers = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
include 'includes/header.php';
|
|
?>
|
|
|
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
<div class="d-flex align-items-center gap-3">
|
|
<h2 class="fw-bold mb-0">Loyalty Program</h2>
|
|
<?php if ($settings['is_enabled']): ?>
|
|
<span class="badge bg-success-subtle text-success border border-success-subtle px-3">Active</span>
|
|
<?php else: ?>
|
|
<span class="badge bg-danger-subtle text-danger border border-danger-subtle px-3">Disabled</span>
|
|
<?php endif; ?>
|
|
</div>
|
|
<?php if (has_permission('loyalty_add')): ?>
|
|
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#settingsModal">
|
|
<i class="bi bi-gear-fill me-2"></i> Configure Settings
|
|
</button>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<?= $message ?>
|
|
|
|
<div class="row mb-4">
|
|
<div class="col-md-6 col-lg-4">
|
|
<div class="card border-0 shadow-sm h-100">
|
|
<div class="card-body">
|
|
<h6 class="card-subtitle mb-2 text-muted text-uppercase small">Current Configuration</h6>
|
|
<div class="d-flex justify-content-between align-items-center mt-3">
|
|
<div>
|
|
<span class="d-block text-muted small">Points per Loyalty Product</span>
|
|
<span class="fs-4 fw-bold text-primary"><?= $settings['points_per_order'] ?> pts</span>
|
|
</div>
|
|
<div class="border-start ps-3">
|
|
<span class="d-block text-muted small">Free Product Threshold</span>
|
|
<span class="fs-4 fw-bold text-success"><?= $settings['points_for_free_meal'] ?> pts</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card border-0 shadow-sm">
|
|
<div class="card-header bg-white py-3">
|
|
<h5 class="mb-0">Loyalty Members</h5>
|
|
</div>
|
|
<div class="table-responsive">
|
|
<table class="table table-hover align-middle mb-0">
|
|
<thead class="bg-light">
|
|
<tr>
|
|
<th class="ps-4">Customer</th>
|
|
<th>Contact</th>
|
|
<th>Points Balance</th>
|
|
<th>Status</th>
|
|
<th>Joined</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($customers as $customer): ?>
|
|
<?php
|
|
$progress = min(100, ($customer['points'] / $settings['points_for_free_meal']) * 100);
|
|
$eligible = $customer['points'] >= $settings['points_for_free_meal'];
|
|
?>
|
|
<tr>
|
|
<td class="ps-4">
|
|
<div class="fw-bold"><?= htmlspecialchars($customer['name']) ?></div>
|
|
</td>
|
|
<td>
|
|
<div class="small"><?= htmlspecialchars($customer['phone'] ?? '-') ?></div>
|
|
<div class="small text-muted"><?= htmlspecialchars($customer['email'] ?? '') ?></div>
|
|
</td>
|
|
<td>
|
|
<div class="d-flex align-items-center">
|
|
<span class="badge bg-warning text-dark border border-warning me-2" style="width: 60px;">
|
|
<?= $customer['points'] ?> pts
|
|
</span>
|
|
<div class="progress flex-grow-1" style="height: 6px; max-width: 100px;">
|
|
<div class="progress-bar bg-success" role="progressbar" style="width: <?= $progress ?>%"></div>
|
|
</div>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<?php if ($eligible): ?>
|
|
<span class="badge bg-success-subtle text-success border border-success-subtle">
|
|
<i class="bi bi-gift-fill me-1"></i> Eligible for Free Product
|
|
</span>
|
|
<?php else: ?>
|
|
<span class="text-muted small">
|
|
<?= $settings['points_for_free_meal'] - $customer['points'] ?> pts to go
|
|
</span>
|
|
<?php endif; ?>
|
|
</td>
|
|
<td class="text-muted small"><?= date('M d, Y', strtotime($customer['created_at'])) ?></td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
<?php if (empty($customers)): ?>
|
|
<tr>
|
|
<td colspan="5" class="text-center py-5 text-muted">No active loyalty members found.</td>
|
|
</tr>
|
|
<?php endif; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Pagination -->
|
|
<?php if ($total_pages > 1): ?>
|
|
<div class="card-footer bg-white py-3">
|
|
<nav>
|
|
<ul class="pagination justify-content-center mb-0">
|
|
<li class="page-item <?= $page <= 1 ? 'disabled' : '' ?>">
|
|
<a class="page-link" href="?page=<?= $page - 1 ?>">Previous</a>
|
|
</li>
|
|
<?php for ($i = 1; $i <= $total_pages; $i++): ?>
|
|
<li class="page-item <?= $page == $i ? 'active' : '' ?>">
|
|
<a class="page-link" href="?page=<?= $i ?>"><?= $i ?></a>
|
|
</li>
|
|
<?php endfor; ?>
|
|
<li class="page-item <?= $page >= $total_pages ? 'disabled' : '' ?>">
|
|
<a class="page-link" href="?page=<?= $page + 1 ?>">Next</a>
|
|
</li>
|
|
</ul>
|
|
</nav>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<!-- Settings Modal -->
|
|
<?php if (has_permission('loyalty_add')): ?>
|
|
<div class="modal fade" id="settingsModal" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<form method="POST" class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">Configure Loyalty Program</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<input type="hidden" name="update_settings" value="1">
|
|
|
|
<div class="mb-4">
|
|
<div class="form-check form-switch p-0 d-flex justify-content-between align-items-center">
|
|
<label class="form-check-label fw-bold" for="is_enabled">Enable Loyalty Program</label>
|
|
<input class="form-check-input ms-0" type="checkbox" id="is_enabled" name="is_enabled" <?= $settings['is_enabled'] ? 'checked' : '' ?> style="width: 3em; height: 1.5em; cursor: pointer;">
|
|
</div>
|
|
<div class="form-text mt-1">When disabled, loyalty features will be hidden from the POS.</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label">Points per Loyalty Product</label>
|
|
<input type="number" name="points_per_order" class="form-control" value="<?= $settings['points_per_order'] ?>" min="0" required>
|
|
<div class="form-text">Points awarded for every loyalty-participating product in the order.</div>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label">Points for Free Product</label>
|
|
<input type="number" name="points_for_free_meal" class="form-control" value="<?= $settings['points_for_free_meal'] ?>" min="0" required>
|
|
<div class="form-text">Threshold points required to redeem a free product.</div>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
|
<button type="submit" class="btn btn-primary">Save Changes</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<?php include 'includes/footer.php'; ?>
|