348 lines
16 KiB
PHP
348 lines
16 KiB
PHP
<?php
|
|
$title = 'ratings';
|
|
require_once __DIR__ . '/includes/header.php';
|
|
|
|
$success_msg = '';
|
|
$error_msg = '';
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'clear_ratings') {
|
|
$stmt = db()->prepare("DELETE FROM ratings");
|
|
if ($stmt->execute()) {
|
|
$success_msg = __('ratings_cleared');
|
|
} else {
|
|
$error_msg = __('error_clearing_ratings');
|
|
}
|
|
}
|
|
|
|
$from_date = $_GET['from_date'] ?? date('Y-m-01');
|
|
$to_date = $_GET['to_date'] ?? date('Y-m-t');
|
|
$type_filter = $_GET['type'] ?? 'all';
|
|
$branch_filter = $_GET['branch_id'] ?? 'all';
|
|
|
|
$where = "WHERE DATE(ratings.created_at) BETWEEN ? AND ?";
|
|
$params = [$from_date, $to_date];
|
|
|
|
if ($type_filter !== 'all') {
|
|
$where .= " AND ratings.rating_type = ?";
|
|
$params[] = $type_filter;
|
|
}
|
|
|
|
if ($branch_filter !== 'all') {
|
|
$where .= " AND ratings.branch_id = ?";
|
|
$params[] = $branch_filter;
|
|
}
|
|
|
|
// Fetch branches for filter and modal
|
|
$branches_stmt = db()->query("SELECT id, name_en, name_ar FROM branches ORDER BY name_en");
|
|
$all_branches = $branches_stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
// Summary Stats
|
|
$stmt = db()->prepare("
|
|
SELECT
|
|
COUNT(*) as total_ratings,
|
|
AVG(ratings.rating_value) as avg_rating
|
|
FROM ratings
|
|
LEFT JOIN branches b ON ratings.branch_id = b.id
|
|
$where
|
|
");
|
|
$stmt->execute($params);
|
|
$stats = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
$total_ratings = $stats['total_ratings'] ?: 0;
|
|
$avg_rating = round($stats['avg_rating'] ?: 0, 1);
|
|
|
|
// Detail Records
|
|
$stmt = db()->prepare("
|
|
SELECT ratings.*, b.name_en AS branch_name_en, b.name_ar AS branch_name_ar
|
|
FROM ratings
|
|
LEFT JOIN branches b ON ratings.branch_id = b.id
|
|
$where
|
|
ORDER BY ratings.created_at DESC
|
|
");
|
|
$stmt->execute($params);
|
|
$ratings = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
?>
|
|
|
|
<div class="container-fluid py-4">
|
|
<?php if ($success_msg): ?>
|
|
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
|
<?= htmlspecialchars($success_msg) ?>
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
|
</div>
|
|
<?php endif; ?>
|
|
<?php if ($error_msg): ?>
|
|
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
|
<?= htmlspecialchars($error_msg) ?>
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<div class="row mb-4 align-items-center">
|
|
<div class="col">
|
|
<h1 class="h3 mb-0 text-gray-800"><?= __('ratings') ?></h1>
|
|
</div>
|
|
<div class="col-auto">
|
|
<button type="button" class="btn btn-sm btn-outline-info" data-bs-toggle="modal" data-bs-target="#branchLinksModal">
|
|
<i class="bi bi-link-45deg"></i> <?= __('branch_links') ?? 'Branch Links' ?>
|
|
</button>
|
|
<form method="POST" class="d-inline" onsubmit="return confirm('<?= __('confirm_clear_ratings') ?>');">
|
|
<input type="hidden" name="action" value="clear_ratings">
|
|
<button type="submit" class="btn btn-sm btn-danger ms-2"><i class="bi bi-trash"></i> <?= __('clear_ratings') ?></button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Filter Card -->
|
|
<div class="card shadow-sm mb-4">
|
|
<div class="card-body">
|
|
<form method="GET" class="row gx-3 gy-2 align-items-center">
|
|
<div class="col-sm-2">
|
|
<label class="visually-hidden"><?= __('from_date') ?></label>
|
|
<input type="date" class="form-control" name="from_date" value="<?= htmlspecialchars($from_date) ?>">
|
|
</div>
|
|
<div class="col-sm-2">
|
|
<label class="visually-hidden"><?= __('to_date') ?></label>
|
|
<input type="date" class="form-control" name="to_date" value="<?= htmlspecialchars($to_date) ?>">
|
|
</div>
|
|
<div class="col-sm-3">
|
|
<label class="visually-hidden"><?= __('branch') ?></label>
|
|
<select class="form-select" name="branch_id">
|
|
<option value="all" <?= $branch_filter == 'all' ? 'selected' : '' ?>><?= __('all_branches') ?></option>
|
|
<?php foreach($all_branches as $br): ?>
|
|
<option value="<?= $br['id'] ?>" <?= $branch_filter == $br['id'] ? 'selected' : '' ?>>
|
|
<?= htmlspecialchars(is_arabic() ? $br['name_ar'] : $br['name_en']) ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
<div class="col-sm-3">
|
|
<label class="visually-hidden"><?= __('rating_type') ?></label>
|
|
<select class="form-select" name="type">
|
|
<option value="all" <?= $type_filter == 'all' ? 'selected' : '' ?>><?= __('all') ?></option>
|
|
<option value="staff" <?= $type_filter == 'staff' ? 'selected' : '' ?>><?= __('staff') ?></option>
|
|
<option value="service" <?= $type_filter == 'service' ? 'selected' : '' ?>><?= __('service') ?></option>
|
|
</select>
|
|
</div>
|
|
<div class="col-sm-2">
|
|
<button type="submit" class="btn btn-primary w-100"><i class="bi bi-search"></i> <?= __('filter') ?></button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Stats Cards -->
|
|
<div class="row mb-4">
|
|
<div class="col-xl-3 col-md-6 mb-4">
|
|
<div class="card border-left-primary shadow-sm h-100 py-2">
|
|
<div class="card-body">
|
|
<div class="row no-gutters align-items-center">
|
|
<div class="col mr-2">
|
|
<div class="text-xs font-weight-bold text-primary text-uppercase mb-1"><?= __('average_rating') ?></div>
|
|
<div class="h5 mb-0 font-weight-bold text-gray-800">
|
|
<?= $avg_rating ?> <i class="bi bi-star-fill text-warning"></i>
|
|
</div>
|
|
</div>
|
|
<div class="col-auto">
|
|
<i class="bi bi-star fa-2x text-gray-300" style="font-size: 2rem; color: #dddfeb;"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-xl-3 col-md-6 mb-4">
|
|
<div class="card border-left-success shadow-sm h-100 py-2">
|
|
<div class="card-body">
|
|
<div class="row no-gutters align-items-center">
|
|
<div class="col mr-2">
|
|
<div class="text-xs font-weight-bold text-success text-uppercase mb-1"><?= __('total_ratings') ?></div>
|
|
<div class="h5 mb-0 font-weight-bold text-gray-800"><?= number_format($total_ratings) ?></div>
|
|
</div>
|
|
<div class="col-auto">
|
|
<i class="bi bi-chat-left-text fa-2x text-gray-300" style="font-size: 2rem; color: #dddfeb;"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Ratings Table -->
|
|
<div class="card shadow-sm">
|
|
<div class="card-header bg-white py-3">
|
|
<h6 class="m-0 font-weight-bold text-primary"><?= __('ratings') ?></h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="table-responsive">
|
|
<table class="table table-bordered table-hover w-100">
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th><?= __('date') ?></th>
|
|
<th><?= __('branch') ?></th>
|
|
<th><?= __('rating_type') ?></th>
|
|
<th><?= __('rating') ?></th>
|
|
<th><?= __('comment') ?></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php if (empty($ratings)): ?>
|
|
<tr>
|
|
<td colspan="5" class="text-center text-muted"><?= __('no_data_available') ?? 'No data available' ?></td>
|
|
</tr>
|
|
<?php else: ?>
|
|
<?php foreach ($ratings as $r): ?>
|
|
<tr>
|
|
<td><?= date('Y-m-d H:i', strtotime($r['created_at'])) ?></td>
|
|
<td><?= htmlspecialchars(is_arabic() ? ($r['branch_name_ar'] ?? '-') : ($r['branch_name_en'] ?? '-')) ?></td>
|
|
<td>
|
|
<?php if ($r['rating_type'] === 'staff'): ?>
|
|
<span class="badge bg-info text-dark"><?= __('staff') ?></span>
|
|
<?php else: ?>
|
|
<span class="badge bg-secondary"><?= __('service') ?></span>
|
|
<?php endif; ?>
|
|
</td>
|
|
<td>
|
|
<?php for($i=1; $i<=5; $i++): ?>
|
|
<i class="bi bi-star<?= $i <= $r['rating_value'] ? '-fill text-warning' : ' text-muted' ?>"></i>
|
|
<?php endfor; ?>
|
|
</td>
|
|
<td><?= htmlspecialchars($r['comment']) ?></td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
<?php endif; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<!-- Branch Links Modal -->
|
|
<div class="modal fade" id="branchLinksModal" tabindex="-1" aria-labelledby="branchLinksModalLabel" aria-hidden="true">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="branchLinksModalLabel"><i class="bi bi-link-45deg"></i> <?= __('branch_links') ?? 'Branch Links' ?></h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<p class="text-muted small mb-4"><?= is_arabic() ? 'انسخ الرابط الخاص بكل فرع لمشاركته مع العملاء. سيتم تسجيل التقييمات تلقائياً تحت الفرع الصحيح.' : 'Copy the unique link for each branch to share with customers. Ratings will automatically be recorded under the correct branch.' ?></p>
|
|
<div class="list-group">
|
|
<?php
|
|
$base_url = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://$_SERVER[HTTP_HOST]" . dirname($_SERVER['PHP_SELF']);
|
|
if (empty($all_branches)): ?>
|
|
<div class="list-group-item text-muted text-center py-4">No branches found.</div>
|
|
<?php else: ?>
|
|
<?php foreach($all_branches as $br):
|
|
$br_name = is_arabic() ? $br['name_ar'] : $br['name_en'];
|
|
$br_link = $base_url . "/rate.php?branch_id=" . $br['id'];
|
|
?>
|
|
<div class="list-group-item d-flex justify-content-between align-items-center py-3">
|
|
<div class="me-3" style="word-break: break-all;">
|
|
<h6 class="mb-1 fw-bold"><?= htmlspecialchars($br_name) ?></h6>
|
|
<a href="<?= htmlspecialchars($br_link) ?>" target="_blank" class="text-decoration-none small text-primary"><?= htmlspecialchars($br_link) ?></a>
|
|
</div>
|
|
<div class="text-nowrap">
|
|
<button class="btn btn-sm btn-outline-secondary me-2" onclick="copyToClipboard('<?= $br_link ?>', this)">
|
|
<i class="bi bi-clipboard"></i> <span class="d-none d-sm-inline"><?= __('copy_link') ?? 'Copy Link' ?></span>
|
|
</button>
|
|
<button class="btn btn-sm btn-outline-primary" onclick="printQR('<?= $br_link ?>', '<?= addslashes(htmlspecialchars($br_name)) ?>')">
|
|
<i class="bi bi-qr-code"></i> <span class="d-none d-sm-inline"><?= __('print_qr') ?? 'Print QR' ?></span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
function printQR(url, branchName) {
|
|
let printWindow = window.open('', '_blank', 'width=400,height=600');
|
|
printWindow.document.write(`
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>Print QR - ${branchName}</title>
|
|
<style>
|
|
body { font-family: sans-serif; text-align: center; padding: 50px; background: #fff; color: #000; }
|
|
h2 { margin-bottom: 5px; font-size: 24px; }
|
|
#qrcode { display: flex; justify-content: center; margin-top: 30px; }
|
|
#qrcode img { margin: 0 auto; }
|
|
.rate-text { font-size: 20px; font-weight: bold; margin-top: 20px; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h2>${branchName}</h2>
|
|
<div id="qrcode"></div>
|
|
<div class="rate-text">Rate Us / قيمنا</div>
|
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js"><\/script>
|
|
<script>
|
|
window.onload = function() {
|
|
new QRCode(document.getElementById("qrcode"), {
|
|
text: "${url}",
|
|
width: 200,
|
|
height: 200,
|
|
colorDark : "#000000",
|
|
colorLight : "#ffffff",
|
|
correctLevel : QRCode.CorrectLevel.M
|
|
});
|
|
setTimeout(function() {
|
|
window.print();
|
|
window.close();
|
|
}, 500);
|
|
};
|
|
<\/script>
|
|
</body>
|
|
</html>
|
|
`);
|
|
printWindow.document.close();
|
|
}
|
|
|
|
function copyToClipboard(text, btn) {
|
|
if (navigator.clipboard) {
|
|
navigator.clipboard.writeText(text).then(function() {
|
|
let originalHtml = btn.innerHTML;
|
|
btn.innerHTML = '<i class="bi bi-check2"></i> <span class="d-none d-sm-inline"><?= __('link_copied') ?? 'Copied!' ?></span>';
|
|
btn.classList.remove('btn-outline-secondary');
|
|
btn.classList.add('btn-success', 'text-white');
|
|
setTimeout(function() {
|
|
btn.innerHTML = originalHtml;
|
|
btn.classList.remove('btn-success', 'text-white');
|
|
btn.classList.add('btn-outline-secondary');
|
|
}, 2000);
|
|
});
|
|
} else {
|
|
// Fallback for older browsers / http
|
|
let textArea = document.createElement("textarea");
|
|
textArea.value = text;
|
|
document.body.appendChild(textArea);
|
|
textArea.focus();
|
|
textArea.select();
|
|
try {
|
|
document.execCommand('copy');
|
|
let originalHtml = btn.innerHTML;
|
|
btn.innerHTML = '<i class="bi bi-check2"></i> <span class="d-none d-sm-inline"><?= __('link_copied') ?? 'Copied!' ?></span>';
|
|
btn.classList.remove('btn-outline-secondary');
|
|
btn.classList.add('btn-success', 'text-white');
|
|
setTimeout(function() {
|
|
btn.innerHTML = originalHtml;
|
|
btn.classList.remove('btn-success', 'text-white');
|
|
btn.classList.add('btn-outline-secondary');
|
|
}, 2000);
|
|
} catch (err) {
|
|
console.error('Unable to copy', err);
|
|
}
|
|
document.body.removeChild(textArea);
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|