500 lines
19 KiB
PHP
500 lines
19 KiB
PHP
<?php
|
|
require_once 'db/config.php';
|
|
require_once 'includes/functions.php';
|
|
|
|
$companySettings = get_company_settings();
|
|
$companyName = $companySettings['company_name'] ?? 'Foody';
|
|
$logoUrl = $companySettings['logo_url'] ?? '';
|
|
|
|
// Handle rating submission
|
|
$success = false;
|
|
$error = '';
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
$ratingType = $_POST['rating_type'] ?? 'staff'; // 'staff' or 'service'
|
|
$userId = $_POST['user_id'] ?? null;
|
|
$rating = $_POST['rating'] ?? null;
|
|
$comment = $_POST['comment'] ?? '';
|
|
|
|
if ($rating) {
|
|
try {
|
|
$pdo = db();
|
|
if ($ratingType === 'service') {
|
|
$stmt = $pdo->prepare("INSERT INTO service_ratings (rating, comment) VALUES (?, ?)");
|
|
$stmt->execute([$rating, $comment]);
|
|
$success = true;
|
|
} else if ($userId) {
|
|
$stmt = $pdo->prepare("INSERT INTO staff_ratings (user_id, rating, comment) VALUES (?, ?, ?)");
|
|
$stmt->execute([$userId, $rating, $comment]);
|
|
$success = true;
|
|
} else {
|
|
$error = "Please select a staff member.";
|
|
}
|
|
} catch (Exception $e) {
|
|
$error = "Error saving rating: " . $e->getMessage();
|
|
}
|
|
} else {
|
|
$error = "Please provide a rating.";
|
|
}
|
|
}
|
|
|
|
// Fetch active and ratable users with pictures
|
|
$pdo = db();
|
|
$stmt = $pdo->query("SELECT id, full_name, full_name_ar, username, profile_pic FROM users WHERE is_active = 1 AND is_ratable = 1 ORDER BY full_name ASC");
|
|
$users = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Rate Our Service - <?= htmlspecialchars($companyName) ?></title>
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css" rel="stylesheet">
|
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&family=Noto+Sans+Arabic:wght@400;600;700&display=swap" rel="stylesheet">
|
|
<style>
|
|
:root {
|
|
--primary-color: #007bff;
|
|
--secondary-color: #6c757d;
|
|
--accent-color: #ffc107;
|
|
--bg-gradient: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
|
|
}
|
|
|
|
body {
|
|
font-family: 'Inter', sans-serif;
|
|
background: var(--bg-gradient);
|
|
min-height: 100vh;
|
|
color: #333;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
body.rtl {
|
|
font-family: 'Noto Sans Arabic', sans-serif;
|
|
direction: rtl;
|
|
}
|
|
|
|
.rating-container {
|
|
max-width: 900px;
|
|
margin: 40px auto;
|
|
padding: 20px;
|
|
}
|
|
|
|
.header {
|
|
text-align: center;
|
|
margin-bottom: 40px;
|
|
position: relative;
|
|
}
|
|
|
|
.lang-toggle {
|
|
position: absolute;
|
|
top: 0;
|
|
right: 0;
|
|
z-index: 100;
|
|
}
|
|
|
|
body.rtl .lang-toggle {
|
|
right: auto;
|
|
left: 0;
|
|
}
|
|
|
|
.logo {
|
|
max-height: 60px;
|
|
margin-bottom: 15px;
|
|
}
|
|
|
|
.staff-card, .service-card {
|
|
background: white;
|
|
border-radius: 15px;
|
|
border: none;
|
|
box-shadow: 0 10px 20px rgba(0,0,0,0.05);
|
|
transition: all 0.3s ease;
|
|
cursor: pointer;
|
|
text-align: center;
|
|
padding: 20px;
|
|
height: 100%;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.service-card {
|
|
background: linear-gradient(135deg, #ffffff 0%, #f0f7ff 100%);
|
|
border: 1px solid #e0e0e0;
|
|
}
|
|
|
|
.staff-card:hover, .service-card:hover {
|
|
transform: translateY(-10px);
|
|
box-shadow: 0 15px 30px rgba(0,0,0,0.1);
|
|
border: 2px solid var(--primary-color);
|
|
}
|
|
|
|
.staff-pic {
|
|
width: 100px;
|
|
height: 100px;
|
|
border-radius: 50%;
|
|
object-fit: cover;
|
|
margin-bottom: 15px;
|
|
background: #eee;
|
|
border: 3px solid white;
|
|
box-shadow: 0 4px 10px rgba(0,0,0,0.1);
|
|
}
|
|
|
|
.service-icon {
|
|
width: 100px;
|
|
height: 100px;
|
|
border-radius: 50%;
|
|
background: var(--primary-color);
|
|
color: white;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 3rem;
|
|
margin-bottom: 15px;
|
|
box-shadow: 0 4px 10px rgba(0,0,0,0.1);
|
|
}
|
|
|
|
.staff-name, .service-name {
|
|
font-weight: 600;
|
|
font-size: 1.1rem;
|
|
margin-bottom: 5px;
|
|
}
|
|
|
|
.star-rating {
|
|
display: flex;
|
|
flex-direction: row-reverse;
|
|
justify-content: center;
|
|
gap: 5px;
|
|
margin: 20px 0;
|
|
}
|
|
|
|
.star-rating input {
|
|
display: none;
|
|
}
|
|
|
|
.star-rating label {
|
|
font-size: 2.5rem;
|
|
color: #ddd;
|
|
cursor: pointer;
|
|
transition: color 0.2s;
|
|
}
|
|
|
|
.star-rating label:hover,
|
|
.star-rating label:hover ~ label,
|
|
.star-rating input:checked ~ label {
|
|
color: var(--accent-color);
|
|
}
|
|
|
|
.btn-submit {
|
|
background: var(--primary-color);
|
|
border: none;
|
|
padding: 12px 30px;
|
|
border-radius: 30px;
|
|
font-weight: 600;
|
|
color: white;
|
|
transition: all 0.3s;
|
|
width: 100%;
|
|
margin-top: 20px;
|
|
}
|
|
|
|
.btn-submit:hover {
|
|
background: #0056b3;
|
|
transform: scale(1.02);
|
|
}
|
|
|
|
#rating-form {
|
|
display: none;
|
|
background: white;
|
|
padding: 30px;
|
|
border-radius: 20px;
|
|
box-shadow: 0 15px 40px rgba(0,0,0,0.1);
|
|
margin-top: 30px;
|
|
}
|
|
|
|
.success-animation {
|
|
text-align: center;
|
|
padding: 40px;
|
|
}
|
|
|
|
.success-icon {
|
|
font-size: 5rem;
|
|
color: #28a745;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
/* Decorative shapes */
|
|
.shape {
|
|
position: fixed;
|
|
z-index: -1;
|
|
opacity: 0.5;
|
|
}
|
|
.shape-1 { top: 10%; left: 5%; width: 100px; height: 100px; background: #007bff22; border-radius: 30% 70% 70% 30% / 30% 30% 70% 70%; }
|
|
.shape-2 { bottom: 10%; right: 5%; width: 150px; height: 150px; background: #ffc10711; border-radius: 50%; }
|
|
|
|
.name-ar {
|
|
display: block;
|
|
font-size: 0.9rem;
|
|
color: var(--secondary-color);
|
|
margin-top: 2px;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<div class="shape shape-1"></div>
|
|
<div class="shape shape-2"></div>
|
|
|
|
<div class="container rating-container">
|
|
<div class="header">
|
|
<div class="lang-toggle">
|
|
<button class="btn btn-sm btn-outline-primary rounded-pill px-3 fw-bold" onclick="toggleLanguage()">
|
|
<i class="bi bi-translate me-1"></i> <span id="lang-btn-text">العربية</span>
|
|
</button>
|
|
</div>
|
|
|
|
<?php if ($logoUrl): ?>
|
|
<img src="<?= get_base_url() . htmlspecialchars($logoUrl) ?>?v=<?= time() ?>" alt="Logo" class="logo">
|
|
<?php else: ?>
|
|
<h1 class="fw-bold"><?= htmlspecialchars($companyName) ?></h1>
|
|
<?php endif; ?>
|
|
<p class="text-muted" id="main-instruction" data-t="main_instruction">We value your feedback! What would you like to rate?</p>
|
|
</div>
|
|
|
|
<?php if ($success): ?>
|
|
<div class="success-animation card border-0 shadow-sm rounded-4">
|
|
<div class="card-body">
|
|
<i class="bi bi-check-circle-fill success-icon"></i>
|
|
<h2 data-t="thank_you">Thank You!</h2>
|
|
<p data-t="success_msg">Your rating has been submitted successfully.</p>
|
|
<a href="index.php" class="btn btn-outline-primary rounded-pill px-4 mt-3" data-t="back_home">Back to Home</a>
|
|
</div>
|
|
</div>
|
|
<?php else: ?>
|
|
<?php if ($error): ?>
|
|
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
|
<?= htmlspecialchars($error) ?>
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<div class="row g-4" id="staff-list">
|
|
<!-- Rate Us Card -->
|
|
<div class="col-12 col-md-6 offset-md-3 mb-3">
|
|
<div class="service-card" onclick="selectService()">
|
|
<div class="service-icon">
|
|
<i class="bi bi-shop"></i>
|
|
</div>
|
|
<div class="service-name fs-4" data-t="rate_services">Rate Our Services</div>
|
|
<p class="text-muted small" data-t="service_subtitle">How was your overall experience with us?</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-12 text-center mt-5 mb-2">
|
|
<h5 class="fw-bold text-muted" data-t="or_rate_staff">OR RATE OUR STAFF</h5>
|
|
</div>
|
|
|
|
<?php if (empty($users)): ?>
|
|
<div class="col-12 text-center">
|
|
<p class="text-muted" data-t="no_staff">No staff members are currently available for rating.</p>
|
|
</div>
|
|
<?php else: ?>
|
|
<?php foreach ($users as $user): ?>
|
|
<div class="col-6 col-md-3">
|
|
<div class="staff-card" onclick="selectStaff(<?= $user['id'] ?>, '<?= htmlspecialchars($user['full_name']) ?>', '<?= htmlspecialchars($user['full_name_ar'] ?: $user['full_name']) ?>', this)">
|
|
<?php if ($user['profile_pic']): ?>
|
|
<img src="<?= htmlspecialchars($user['profile_pic']) ?>" alt="<?= htmlspecialchars($user['full_name']) ?>" class="staff-pic">
|
|
<?php else: ?>
|
|
<div class="staff-pic d-flex align-items-center justify-content-center bg-primary text-white fs-2 fw-bold">
|
|
<?= strtoupper(substr($user['full_name'] ?: $user['username'], 0, 1)) ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
<div class="staff-name">
|
|
<span class="name-en"><?= htmlspecialchars($user['full_name'] ?: $user['username']) ?></span>
|
|
<?php if ($user['full_name_ar']): ?>
|
|
<span class="name-ar"><?= htmlspecialchars($user['full_name_ar']) ?></span>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<form id="rating-form" method="POST">
|
|
<input type="hidden" name="rating_type" id="rating-type" value="staff">
|
|
<input type="hidden" name="user_id" id="selected-user-id">
|
|
|
|
<div class="text-center mb-4">
|
|
<h4 id="rating-title" class="fw-bold mb-0"><span data-t="rate">Rate</span> <span id="staff-display-name"></span></h4>
|
|
<p id="rating-subtitle" class="text-muted"></p>
|
|
|
|
<div class="star-rating">
|
|
<input type="radio" id="star5" name="rating" value="5" required /><label for="star5" title="5 stars"><i class="bi bi-star-fill"></i></label>
|
|
<input type="radio" id="star4" name="rating" value="4" /><label for="star4" title="4 stars"><i class="bi bi-star-fill"></i></label>
|
|
<input type="radio" id="star3" name="rating" value="3" /><label for="star3" title="3 stars"><i class="bi bi-star-fill"></i></label>
|
|
<input type="radio" id="star2" name="rating" value="2" /><label for="star2" title="2 stars"><i class="bi bi-star-fill"></i></label>
|
|
<input type="radio" id="star1" name="rating" value="1" /><label for="star1" title="1 star"><i class="bi bi-star-fill"></i></label>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label for="comment" class="form-label fw-semibold" id="comment-label" data-t="comments_label">Any additional comments?</label>
|
|
<textarea class="form-control rounded-4 shadow-sm border-0 bg-light" name="comment" id="comment" rows="3" placeholder="Tell us about your experience..." data-tp="comment_placeholder"></textarea>
|
|
</div>
|
|
|
|
<div class="row g-3">
|
|
<div class="col-6">
|
|
<button type="button" class="btn btn-light w-100 rounded-pill py-3 fw-bold" onclick="cancelSelection()" data-t="cancel">Cancel</button>
|
|
</div>
|
|
<div class="col-6">
|
|
<button type="submit" class="btn btn-primary btn-submit m-0 py-3 fw-bold" data-t="submit">Submit Rating</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<script>
|
|
const translations = {
|
|
en: {
|
|
main_instruction: "We value your feedback! What would you like to rate?",
|
|
thank_you: "Thank You!",
|
|
success_msg: "Your rating has been submitted successfully.",
|
|
back_home: "Back to Home",
|
|
rate_services: "Rate Our Services",
|
|
service_subtitle: "How was your overall experience with us?",
|
|
or_rate_staff: "OR RATE OUR STAFF",
|
|
no_staff: "No staff members are currently available for rating.",
|
|
rate: "Rate",
|
|
rate_staff_subtitle: "Rate the service provided by this staff member.",
|
|
rate_service_subtitle: "We would love to hear how we are doing overall.",
|
|
comments_label: "Any additional comments?",
|
|
comment_placeholder: "Tell us about your experience...",
|
|
improve_label: "What can we improve?",
|
|
specific_feedback: "Any specific feedback for {name}?",
|
|
cancel: "Cancel",
|
|
submit: "Submit Rating",
|
|
lang_btn: "العربية",
|
|
our_services: "Our Services"
|
|
},
|
|
ar: {
|
|
main_instruction: "نحن نقدر رأيك! ما الذي تود تقييمه؟",
|
|
thank_you: "شكراً لك!",
|
|
success_msg: "تم إرسال تقييمك بنجاح.",
|
|
back_home: "العودة للرئيسية",
|
|
rate_services: "قيم خدماتنا",
|
|
service_subtitle: "كيف كانت تجربتك العامة معنا؟",
|
|
or_rate_staff: "أو قيم موظفينا",
|
|
no_staff: "لا يوجد موظفون متاحون للتقييم حالياً.",
|
|
rate: "تقييم",
|
|
rate_staff_subtitle: "قيم الخدمة المقدمة من قبل هذا الموظف.",
|
|
rate_service_subtitle: "نود معرفة رأيك في أدائنا العام.",
|
|
comments_label: "أي تعليقات إضافية؟",
|
|
comment_placeholder: "أخبرنا عن تجربتك...",
|
|
improve_label: "ما الذي يمكننا تحسينه؟",
|
|
specific_feedback: "أي ملاحظات محددة لـ {name}؟",
|
|
cancel: "إلغاء",
|
|
submit: "إرسال التقييم",
|
|
lang_btn: "English",
|
|
our_services: "خدماتنا"
|
|
}
|
|
};
|
|
|
|
let currentLang = localStorage.getItem('rate_lang') || 'en';
|
|
let currentStaffName = { en: '', ar: '' };
|
|
let currentMode = 'list'; // 'list' or 'form'
|
|
let currentRatingType = 'staff';
|
|
|
|
function updateUI() {
|
|
const t = translations[currentLang];
|
|
document.body.classList.toggle('rtl', currentLang === 'ar');
|
|
document.getElementById('lang-btn-text').innerText = t.lang_btn;
|
|
|
|
document.querySelectorAll('[data-t]').forEach(el => {
|
|
const key = el.getAttribute('data-t');
|
|
if (t[key]) el.innerText = t[key];
|
|
});
|
|
|
|
document.querySelectorAll('[data-tp]').forEach(el => {
|
|
const key = el.getAttribute('data-tp');
|
|
if (t[key]) el.placeholder = t[key];
|
|
});
|
|
|
|
if (currentMode === 'form') {
|
|
if (currentRatingType === 'service') {
|
|
document.getElementById('staff-display-name').innerText = t.our_services;
|
|
document.getElementById('rating-subtitle').innerText = t.rate_service_subtitle;
|
|
document.getElementById('comment-label').innerText = t.improve_label;
|
|
} else {
|
|
const name = currentLang === 'ar' ? currentStaffName.ar : currentStaffName.en;
|
|
document.getElementById('staff-display-name').innerText = name;
|
|
document.getElementById('rating-subtitle').innerText = t.rate_staff_subtitle;
|
|
document.getElementById('comment-label').innerText = t.specific_feedback.replace('{name}', name);
|
|
}
|
|
}
|
|
}
|
|
|
|
function toggleLanguage() {
|
|
currentLang = currentLang === 'en' ? 'ar' : 'en';
|
|
localStorage.setItem('rate_lang', currentLang);
|
|
updateUI();
|
|
}
|
|
|
|
function selectService() {
|
|
currentMode = 'form';
|
|
currentRatingType = 'service';
|
|
|
|
// Hide staff list
|
|
document.getElementById('staff-list').style.display = 'none';
|
|
document.getElementById('main-instruction').style.display = 'none';
|
|
|
|
// Set type to service
|
|
document.getElementById('rating-type').value = 'service';
|
|
document.getElementById('selected-user-id').value = '';
|
|
|
|
// Show rating form
|
|
document.getElementById('rating-form').style.display = 'block';
|
|
|
|
updateUI();
|
|
window.scrollTo({ top: 0, behavior: 'smooth' });
|
|
}
|
|
|
|
function selectStaff(id, nameEn, nameAr, element) {
|
|
currentMode = 'form';
|
|
currentRatingType = 'staff';
|
|
currentStaffName = { en: nameEn, ar: nameAr };
|
|
|
|
// Hide staff list
|
|
document.getElementById('staff-list').style.display = 'none';
|
|
document.getElementById('main-instruction').style.display = 'none';
|
|
|
|
// Set type to staff
|
|
document.getElementById('rating-type').value = 'staff';
|
|
document.getElementById('selected-user-id').value = id;
|
|
|
|
// Show rating form
|
|
document.getElementById('rating-form').style.display = 'block';
|
|
|
|
updateUI();
|
|
window.scrollTo({ top: 0, behavior: 'smooth' });
|
|
}
|
|
|
|
function cancelSelection() {
|
|
currentMode = 'list';
|
|
document.getElementById('rating-form').style.display = 'none';
|
|
document.getElementById('staff-list').style.display = 'flex';
|
|
document.getElementById('main-instruction').style.display = 'block';
|
|
|
|
// Clear form
|
|
document.getElementById('comment').value = '';
|
|
const radios = document.getElementsByName('rating');
|
|
for(let i=0; i<radios.length; i++) radios[i].checked = false;
|
|
|
|
updateUI();
|
|
}
|
|
|
|
// Initial UI update
|
|
updateUI();
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|