arabic translate for qr order

This commit is contained in:
Flatlogic Bot 2026-02-24 09:29:33 +00:00
parent 291449ae16
commit 6cbe1c3306
10 changed files with 588 additions and 104 deletions

View File

@ -10,6 +10,7 @@ $message = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
$action = $_POST['action'];
$name = trim($_POST['name']);
$name_ar = trim($_POST['name_ar'] ?? '');
$description = trim($_POST['description']);
$id = isset($_POST['id']) ? (int)$_POST['id'] : null;
@ -21,16 +22,16 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
if (!has_permission('expense_categories_add')) {
$message = '<div class="alert alert-danger">Access Denied.</div>';
} else {
$stmt = $pdo->prepare("UPDATE expense_categories SET name = ?, description = ? WHERE id = ?");
$stmt->execute([$name, $description, $id]);
$stmt = $pdo->prepare("UPDATE expense_categories SET name = ?, name_ar = ?, description = ? WHERE id = ?");
$stmt->execute([$name, $name_ar, $description, $id]);
$message = '<div class="alert alert-success">Expense category updated successfully!</div>';
}
} elseif ($action === 'add_expense_category') {
if (!has_permission('expense_categories_add')) {
$message = '<div class="alert alert-danger">Access Denied.</div>';
} else {
$stmt = $pdo->prepare("INSERT INTO expense_categories (name, description) VALUES (?, ?)");
$stmt->execute([$name, $description]);
$stmt = $pdo->prepare("INSERT INTO expense_categories (name, name_ar, description) VALUES (?, ?, ?)");
$stmt->execute([$name, $name_ar, $description]);
$message = '<div class="alert alert-success">Expense category created successfully!</div>';
}
}
@ -82,6 +83,7 @@ include 'includes/header.php';
<tr>
<th class="ps-4">ID</th>
<th>Name</th>
<th>Arabic Name</th>
<th>Description</th>
<th class="text-end pe-4">Actions</th>
</tr>
@ -91,6 +93,7 @@ include 'includes/header.php';
<tr>
<td class="ps-4 fw-medium">#<?= $cat['id'] ?></td>
<td class="fw-bold"><?= htmlspecialchars($cat['name']) ?></td>
<td><?= htmlspecialchars($cat['name_ar'] ?: '-') ?></td>
<td><small class="text-muted"><?= htmlspecialchars($cat['description'] ?: '-') ?></small></td>
<td class="text-end pe-4">
<?php if (has_permission('expense_categories_add')): ?>
@ -106,7 +109,7 @@ include 'includes/header.php';
<?php endforeach; ?>
<?php if (empty($expense_categories)): ?>
<tr>
<td colspan="4" class="text-center py-4 text-muted">No expense categories found.</td>
<td colspan="5" class="text-center py-4 text-muted">No expense categories found.</td>
</tr>
<?php endif; ?>
</tbody>
@ -134,7 +137,16 @@ include 'includes/header.php';
<input type="hidden" name="id" id="expenseCategoryId">
<div class="mb-3">
<label class="form-label">Category Name <span class="text-danger">*</span></label>
<div class="input-group">
<input type="text" name="name" id="expenseCategoryName" class="form-control" required>
<button class="btn btn-outline-secondary" type="button" id="btnTranslate">
<i class="bi bi-translate text-primary"></i>
</button>
</div>
</div>
<div class="mb-3">
<label class="form-label">Arabic Name</label>
<input type="text" name="name_ar" id="expenseCategoryNameAr" class="form-control" dir="rtl">
</div>
<div class="mb-3">
<label class="form-label">Description</label>
@ -177,10 +189,51 @@ function openEditModal(cat) {
document.getElementById('expenseCategoryAction').value = 'edit_expense_category';
document.getElementById('expenseCategoryId').value = cat.id;
document.getElementById('expenseCategoryName').value = cat.name || '';
document.getElementById('expenseCategoryNameAr').value = cat.name_ar || '';
document.getElementById('expenseCategoryDescription').value = cat.description || '';
modal.show();
}
document.getElementById('btnTranslate').addEventListener('click', function() {
const text = document.getElementById('expenseCategoryName').value;
if (!text) {
alert('Please enter a category name first.');
return;
}
const btn = this;
const originalHtml = btn.innerHTML;
btn.disabled = true;
btn.innerHTML = '<span class="spinner-border spinner-border-sm text-primary" role="status" aria-hidden="true"></span>';
fetch('../api/translate.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
text: text,
target_lang: 'Arabic'
}),
})
.then(response => response.json())
.then(data => {
if (data.success) {
document.getElementById('expenseCategoryNameAr').value = data.translated_text;
} else {
alert('Translation failed: ' + (data.error || 'Unknown error'));
}
})
.catch(error => {
console.error('Error:', error);
alert('An error occurred during translation.');
})
.finally(() => {
btn.disabled = false;
btn.innerHTML = originalHtml;
});
});
</script>
<?php endif; ?>

View File

@ -10,6 +10,7 @@ $message = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
$action = $_POST['action'];
$name = trim($_POST['name']);
$name_ar = trim($_POST['name_ar'] ?? '');
$address = trim($_POST['address']);
$id = isset($_POST['id']) ? (int)$_POST['id'] : null;
@ -21,16 +22,16 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
if (!has_permission('outlets_add')) {
$message = '<div class="alert alert-danger">Access Denied.</div>';
} else {
$stmt = $pdo->prepare("UPDATE outlets SET name = ?, address = ? WHERE id = ?");
$stmt->execute([$name, $address, $id]);
$stmt = $pdo->prepare("UPDATE outlets SET name = ?, name_ar = ?, address = ? WHERE id = ?");
$stmt->execute([$name, $name_ar, $address, $id]);
$message = '<div class="alert alert-success">Outlet updated successfully!</div>';
}
} elseif ($action === 'add_outlet') {
if (!has_permission('outlets_add')) {
$message = '<div class="alert alert-danger">Access Denied.</div>';
} else {
$stmt = $pdo->prepare("INSERT INTO outlets (name, address) VALUES (?, ?)");
$stmt->execute([$name, $address]);
$stmt = $pdo->prepare("INSERT INTO outlets (name, name_ar, address) VALUES (?, ?, ?)");
$stmt->execute([$name, $name_ar, $address]);
$message = '<div class="alert alert-success">Outlet created successfully!</div>';
}
}
@ -82,6 +83,7 @@ include 'includes/header.php';
<tr>
<th class="ps-4">ID</th>
<th>Name</th>
<th>Arabic Name</th>
<th>Address</th>
<th class="text-end pe-4">Actions</th>
</tr>
@ -91,6 +93,7 @@ include 'includes/header.php';
<tr>
<td class="ps-4 fw-medium">#<?= $outlet['id'] ?></td>
<td class="fw-bold"><?= htmlspecialchars($outlet['name']) ?></td>
<td><?= htmlspecialchars($outlet['name_ar'] ?: '-') ?></td>
<td><small class="text-muted"><?= htmlspecialchars($outlet['address']) ?></small></td>
<td class="text-end pe-4">
<?php if (has_permission('outlets_add')): ?>
@ -107,7 +110,7 @@ include 'includes/header.php';
<?php endforeach; ?>
<?php if (empty($outlets)): ?>
<tr>
<td colspan="4" class="text-center py-4 text-muted">No outlets found.</td>
<td colspan="5" class="text-center py-4 text-muted">No outlets found.</td>
</tr>
<?php endif; ?>
</tbody>
@ -135,7 +138,16 @@ include 'includes/header.php';
<input type="hidden" name="id" id="outletId">
<div class="mb-3">
<label class="form-label">Name <span class="text-danger">*</span></label>
<div class="input-group">
<input type="text" name="name" id="outletName" class="form-control" required>
<button class="btn btn-outline-secondary" type="button" id="btnTranslate">
<i class="bi bi-translate text-primary"></i>
</button>
</div>
</div>
<div class="mb-3">
<label class="form-label">Arabic Name</label>
<input type="text" name="name_ar" id="outletNameAr" class="form-control" dir="rtl">
</div>
<div class="mb-3">
<label class="form-label">Address</label>
@ -165,8 +177,49 @@ function prepareEditForm(outlet) {
document.getElementById('outletAction').value = 'edit_outlet';
document.getElementById('outletId').value = outlet.id;
document.getElementById('outletName').value = outlet.name || '';
document.getElementById('outletNameAr').value = outlet.name_ar || '';
document.getElementById('outletAddress').value = outlet.address || '';
}
document.getElementById('btnTranslate').addEventListener('click', function() {
const text = document.getElementById('outletName').value;
if (!text) {
alert('Please enter an outlet name first.');
return;
}
const btn = this;
const originalHtml = btn.innerHTML;
btn.disabled = true;
btn.innerHTML = '<span class="spinner-border spinner-border-sm text-primary" role="status" aria-hidden="true"></span>';
fetch('../api/translate.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
text: text,
target_lang: 'Arabic'
}),
})
.then(response => response.json())
.then(data => {
if (data.success) {
document.getElementById('outletNameAr').value = data.translated_text;
} else {
alert('Translation failed: ' + (data.error || 'Unknown error'));
}
})
.catch(error => {
console.error('Error:', error);
alert('An error occurred during translation.');
})
.finally(() => {
btn.disabled = false;
btn.innerHTML = originalHtml;
});
});
</script>
<?php endif; ?>

View File

@ -23,10 +23,11 @@ if (!$product) {
// Handle Add Variant
if (isset($_POST['action']) && $_POST['action'] === 'add_variant') {
$name = $_POST['name'];
$name_ar = $_POST['name_ar'] ?? '';
$price_adj = $_POST['price_adjustment'];
$stmt = $pdo->prepare("INSERT INTO product_variants (product_id, name, price_adjustment) VALUES (?, ?, ?)");
$stmt->execute([$product_id, $name, $price_adj]);
$stmt = $pdo->prepare("INSERT INTO product_variants (product_id, name, name_ar, price_adjustment) VALUES (?, ?, ?, ?)");
$stmt->execute([$product_id, $name, $name_ar, $price_adj]);
header("Location: product_variants.php?product_id=$product_id");
exit;
}
@ -35,10 +36,11 @@ if (isset($_POST['action']) && $_POST['action'] === 'add_variant') {
if (isset($_POST['action']) && $_POST['action'] === 'edit_variant') {
$id = $_POST['variant_id'];
$name = $_POST['name'];
$name_ar = $_POST['name_ar'] ?? '';
$price_adj = $_POST['price_adjustment'];
$stmt = $pdo->prepare("UPDATE product_variants SET name = ?, price_adjustment = ? WHERE id = ?");
$stmt->execute([$name, $price_adj, $id]);
$stmt = $pdo->prepare("UPDATE product_variants SET name = ?, name_ar = ?, price_adjustment = ? WHERE id = ?");
$stmt->execute([$name, $name_ar, $price_adj, $id]);
header("Location: product_variants.php?product_id=$product_id");
exit;
}
@ -83,6 +85,7 @@ $effective_base_price = get_product_price($product);
<thead class="bg-light">
<tr>
<th class="ps-4">Variant Name</th>
<th>Arabic Name</th>
<th>Price Adjustment</th>
<th>Final Price (Est.)</th>
<th>Actions</th>
@ -92,6 +95,7 @@ $effective_base_price = get_product_price($product);
<?php foreach ($variants as $variant): ?>
<tr>
<td class="ps-4 fw-medium"><?= htmlspecialchars($variant['name']) ?></td>
<td><div class="text-primary small fw-semibold" dir="rtl"><?= htmlspecialchars($variant['name_ar'] ?? '-') ?></div></td>
<td>
<?php if ($variant['price_adjustment'] > 0): ?>
<span class="text-danger">+ <?= format_currency($variant['price_adjustment']) ?></span>
@ -113,6 +117,7 @@ $effective_base_price = get_product_price($product);
data-bs-target="#editVariantModal"
data-id="<?= $variant['id'] ?>"
data-name="<?= htmlspecialchars($variant['name']) ?>"
data-name-ar="<?= htmlspecialchars($variant['name_ar'] ?? '') ?>"
data-price="<?= $variant['price_adjustment'] ?>">
<i class="bi bi-pencil"></i>
</button>
@ -122,7 +127,7 @@ $effective_base_price = get_product_price($product);
<?php endforeach; ?>
<?php if (empty($variants)): ?>
<tr>
<td colspan="4" class="text-center py-5 text-muted">No variants defined (e.g., Small, Large, Spicy).</td>
<td colspan="5" class="text-center py-5 text-muted">No variants defined (e.g., Small, Large, Spicy).</td>
</tr>
<?php endif; ?>
</tbody>
@ -147,8 +152,17 @@ $effective_base_price = get_product_price($product);
<div class="modal-body">
<input type="hidden" name="action" value="add_variant">
<div class="mb-3">
<label class="form-label">Variant Name (e.g., Large, Extra Cheese)</label>
<input type="text" name="name" class="form-control" required>
<label class="form-label">Variant Name (EN)</label>
<div class="input-group">
<input type="text" name="name" id="add_name" class="form-control" required>
<button class="btn btn-outline-secondary" type="button" onclick="translateField('add_name', 'add_name_ar')">
<i class="bi bi-translate"></i>
</button>
</div>
</div>
<div class="mb-3">
<label class="form-label">Variant Name (AR)</label>
<input type="text" name="name_ar" id="add_name_ar" class="form-control text-end" dir="rtl">
</div>
<div class="mb-3">
<label class="form-label">Price Adjustment (+/-)</label>
@ -181,8 +195,17 @@ $effective_base_price = get_product_price($product);
<input type="hidden" name="action" value="edit_variant">
<input type="hidden" name="variant_id" id="edit_variant_id">
<div class="mb-3">
<label class="form-label">Variant Name</label>
<label class="form-label">Variant Name (EN)</label>
<div class="input-group">
<input type="text" name="name" id="edit_variant_name" class="form-control" required>
<button class="btn btn-outline-secondary" type="button" onclick="translateField('edit_variant_name', 'edit_variant_name_ar')">
<i class="bi bi-translate"></i>
</button>
</div>
</div>
<div class="mb-3">
<label class="form-label">Variant Name (AR)</label>
<input type="text" name="name_ar" id="edit_variant_name_ar" class="form-control text-end" dir="rtl">
</div>
<div class="mb-3">
<label class="form-label">Price Adjustment (+/-)</label>
@ -209,17 +232,39 @@ $effective_base_price = get_product_price($product);
var button = event.relatedTarget;
var id = button.getAttribute('data-id');
var name = button.getAttribute('data-name');
var nameAr = button.getAttribute('data-name-ar');
var price = button.getAttribute('data-price');
var modalIdInput = editVariantModal.querySelector('#edit_variant_id');
var modalNameInput = editVariantModal.querySelector('#edit_variant_name');
var modalNameArInput = editVariantModal.querySelector('#edit_variant_name_ar');
var modalPriceInput = editVariantModal.querySelector('#edit_variant_price');
modalIdInput.value = id;
modalNameInput.value = name;
modalNameArInput.value = nameAr;
modalPriceInput.value = price;
});
}
async function translateField(sourceId, targetId) {
const text = document.getElementById(sourceId).value;
if (!text) return;
try {
const response = await fetch('../api/translate.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ text: text, target_lang: 'Arabic' })
});
const data = await response.json();
if (data.success) {
document.getElementById(targetId).value = data.translated_text;
}
} catch (e) {
console.error(e);
}
}
</script>
<?php include 'includes/footer.php'; ?>

View File

@ -14,7 +14,7 @@ $endDate = $_GET['end_date'] ?? date('Y-m-d');
$outletId = $_GET['outlet_id'] ?? '';
// Fetch Outlets for filter
$outletsStmt = $pdo->query("SELECT id, name FROM outlets ORDER BY name ASC");
$outletsStmt = $pdo->query("SELECT id, name, name_ar FROM outlets ORDER BY name ASC");
$allOutlets = $outletsStmt->fetchAll();
// Base query additions
@ -31,6 +31,7 @@ if (!empty($outletId)) {
$staffStmt = $pdo->prepare("
SELECT
u.full_name as staff_name,
u.full_name_ar as staff_name_ar,
u.username,
COUNT(o.id) as order_count,
SUM(o.total_amount) as total_sales
@ -48,6 +49,7 @@ $staffSales = $staffStmt->fetchAll();
$outletStmt = $pdo->prepare("
SELECT
ot.name as outlet_name,
ot.name_ar as outlet_name_ar,
COUNT(o.id) as order_count,
SUM(o.total_amount) as total_sales
FROM orders o
@ -64,6 +66,7 @@ $outletSales = $outletStmt->fetchAll();
$categoryStmt = $pdo->prepare("
SELECT
c.name as category_name,
c.name_ar as category_name_ar,
SUM(oi.quantity) as items_sold,
SUM(oi.quantity * oi.unit_price) as total_sales
FROM order_items oi
@ -82,6 +85,7 @@ $categorySales = $categoryStmt->fetchAll();
$expenseCatStmt = $pdo->prepare("
SELECT
ec.name as category_name,
ec.name_ar as category_name_ar,
SUM(e.amount) as total_amount
FROM expenses e
JOIN expense_categories ec ON e.category_id = ec.id
@ -129,7 +133,7 @@ $netProfit = ($summary['total_revenue'] ?? 0) - $totalExpenses;
<option value="">All Outlets</option>
<?php foreach ($allOutlets as $o): ?>
<option value="<?= $o['id'] ?>" <?= $outletId == $o['id'] ? 'selected' : '' ?>>
<?= htmlspecialchars($o['name']) ?>
<?= htmlspecialchars($o['name']) ?> <?= $o['name_ar'] ? '('.$o['name_ar'].')' : '' ?>
</option>
<?php endforeach; ?>
</select>
@ -236,6 +240,9 @@ $netProfit = ($summary['total_revenue'] ?? 0) - $totalExpenses;
<tr>
<td class="ps-3">
<div class="fw-bold"><?= htmlspecialchars($staff['staff_name'] ?: $staff['username']) ?></div>
<?php if ($staff['staff_name_ar']): ?>
<small class="text-muted"><?= htmlspecialchars($staff['staff_name_ar']) ?></small>
<?php endif; ?>
</td>
<td class="text-center"><?= $staff['order_count'] ?></td>
<td class="text-end pe-3 fw-bold text-primary"><?= format_currency($staff['total_sales']) ?></td>
@ -273,6 +280,9 @@ $netProfit = ($summary['total_revenue'] ?? 0) - $totalExpenses;
<tr>
<td class="ps-3">
<div class="fw-bold"><?= htmlspecialchars($outlet['outlet_name']) ?></div>
<?php if ($outlet['outlet_name_ar']): ?>
<small class="text-muted"><?= htmlspecialchars($outlet['outlet_name_ar']) ?></small>
<?php endif; ?>
</td>
<td class="text-center"><?= $outlet['order_count'] ?></td>
<td class="text-end pe-3 fw-bold text-success"><?= format_currency($outlet['total_sales']) ?></td>
@ -310,6 +320,9 @@ $netProfit = ($summary['total_revenue'] ?? 0) - $totalExpenses;
<tr>
<td class="ps-3">
<div class="fw-bold"><?= htmlspecialchars($cat['category_name']) ?></div>
<?php if ($cat['category_name_ar']): ?>
<small class="text-muted"><?= htmlspecialchars($cat['category_name_ar']) ?></small>
<?php endif; ?>
</td>
<td class="text-center"><?= $cat['items_sold'] ?></td>
<td class="text-end pe-3 fw-bold text-dark"><?= format_currency($cat['total_sales']) ?></td>
@ -346,6 +359,9 @@ $netProfit = ($summary['total_revenue'] ?? 0) - $totalExpenses;
<tr>
<td class="ps-3">
<div class="fw-bold"><?= htmlspecialchars($exp['category_name']) ?></div>
<?php if ($exp['category_name_ar']): ?>
<small class="text-muted"><?= htmlspecialchars($exp['category_name_ar']) ?></small>
<?php endif; ?>
</td>
<td class="text-end pe-3 fw-bold text-danger"><?= format_currency($exp['total_amount']) ?></td>
</tr>

View File

@ -11,6 +11,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
$action = $_POST['action'];
$username = trim($_POST['username']);
$full_name = trim($_POST['full_name']);
$full_name_ar = trim($_POST['full_name_ar'] ?? '');
$email = trim($_POST['email']);
$group_id = (int)$_POST['group_id'];
$is_active = isset($_POST['is_active']) ? 1 : 0;
@ -45,13 +46,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
if (!has_permission('users_edit') && !has_permission('users_add')) {
$message = '<div class="alert alert-danger">Access Denied: You do not have permission to edit users.</div>';
} else {
$sql = "UPDATE users SET username = ?, full_name = ?, email = ?, group_id = ?, is_active = ?, is_ratable = ?, profile_pic = ? WHERE id = ?";
$params = [$username, $full_name, $email, $group_id, $is_active, $is_ratable, $profile_pic, $id];
$sql = "UPDATE users SET username = ?, full_name = ?, full_name_ar = ?, email = ?, group_id = ?, is_active = ?, is_ratable = ?, profile_pic = ? WHERE id = ?";
$params = [$username, $full_name, $full_name_ar, $email, $group_id, $is_active, $is_ratable, $profile_pic, $id];
if (!empty($_POST['password'])) {
$password = password_hash($_POST['password'], PASSWORD_DEFAULT);
$sql = "UPDATE users SET username = ?, full_name = ?, email = ?, group_id = ?, is_active = ?, is_ratable = ?, profile_pic = ?, password = ? WHERE id = ?";
$params = [$username, $full_name, $email, $group_id, $is_active, $is_ratable, $profile_pic, $password, $id];
$sql = "UPDATE users SET username = ?, full_name = ?, full_name_ar = ?, email = ?, group_id = ?, is_active = ?, is_ratable = ?, profile_pic = ?, password = ? WHERE id = ?";
$params = [$username, $full_name, $full_name_ar, $email, $group_id, $is_active, $is_ratable, $profile_pic, $password, $id];
}
$stmt = $pdo->prepare($sql);
@ -63,8 +64,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
$message = '<div class="alert alert-danger">Access Denied: You do not have permission to add users.</div>';
} else {
$password = password_hash($_POST['password'] ?: '123456', PASSWORD_DEFAULT);
$stmt = $pdo->prepare("INSERT INTO users (username, password, full_name, email, group_id, is_active, is_ratable, profile_pic) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
$stmt->execute([$username, $password, $full_name, $email, $group_id, $is_active, $is_ratable, $profile_pic]);
$stmt = $pdo->prepare("INSERT INTO users (username, password, full_name, full_name_ar, email, group_id, is_active, is_ratable, profile_pic) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)");
$stmt->execute([$username, $password, $full_name, $full_name_ar, $email, $group_id, $is_active, $is_ratable, $profile_pic]);
$message = '<div class="alert alert-success">User created successfully!</div>';
}
}
@ -132,6 +133,7 @@ include 'includes/header.php';
<thead class="bg-light">
<tr>
<th class="ps-4">User</th>
<th>Arabic Name</th>
<th>Email</th>
<th>Role / Group</th>
<th>Status</th>
@ -155,6 +157,7 @@ include 'includes/header.php';
</div>
</div>
</td>
<td><?= htmlspecialchars($user['full_name_ar'] ?: '-') ?></td>
<td><?= htmlspecialchars($user['email'] ?: '-') ?></td>
<td><span class="badge bg-light text-dark border px-2 py-1"><?= htmlspecialchars($user['group_name'] ?: 'None') ?></span></td>
<td>
@ -189,7 +192,7 @@ include 'includes/header.php';
<?php endforeach; ?>
<?php if (empty($users)): ?>
<tr>
<td colspan="6" class="text-center py-5 text-muted">No users found.</td>
<td colspan="7" class="text-center py-5 text-muted">No users found.</td>
</tr>
<?php endif; ?>
</tbody>
@ -223,7 +226,16 @@ include 'includes/header.php';
<div class="mb-3">
<label class="form-label small fw-bold text-muted">FULL NAME</label>
<input type="text" name="full_name" id="userFullName" class="form-control rounded-3 border-0 bg-light" required>
<div class="input-group">
<input type="text" name="full_name" id="userFullName" class="form-control rounded-start-3 border-0 bg-light">
<button class="btn btn-outline-secondary border-0 bg-light" type="button" id="btnTranslate">
<i class="bi bi-translate text-primary"></i>
</button>
</div>
</div>
<div class="mb-3">
<label class="form-label small fw-bold text-muted">ARABIC FULL NAME</label>
<input type="text" name="full_name_ar" id="userFullNameAr" class="form-control rounded-3 border-0 bg-light" dir="rtl">
</div>
<div class="row g-3">
<div class="col-md-6 mb-3">
@ -295,6 +307,7 @@ function prepareEditForm(user) {
document.getElementById('userAction').value = 'edit_user';
document.getElementById('userId').value = user.id;
document.getElementById('userFullName').value = user.full_name || '';
document.getElementById('userFullNameAr').value = user.full_name_ar || '';
document.getElementById('userUsername').value = user.username || '';
document.getElementById('userEmail').value = user.email || '';
document.getElementById('userGroupId').value = user.group_id || '';
@ -312,6 +325,46 @@ function prepareEditForm(user) {
document.getElementById('userImagePreviewContainer').style.display = 'none';
}
}
document.getElementById('btnTranslate').addEventListener('click', function() {
const text = document.getElementById('userFullName').value;
if (!text) {
alert('Please enter a full name first.');
return;
}
const btn = this;
const originalHtml = btn.innerHTML;
btn.disabled = true;
btn.innerHTML = '<span class="spinner-border spinner-border-sm text-primary" role="status" aria-hidden="true"></span>';
fetch('../api/translate.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
text: text,
target_lang: 'Arabic'
}),
})
.then(response => response.json())
.then(data => {
if (data.success) {
document.getElementById('userFullNameAr').value = data.translated_text;
} else {
alert('Translation failed: ' + (data.error || 'Unknown error'));
}
})
.catch(error => {
console.error('Error:', error);
alert('An error occurred during translation.');
})
.finally(() => {
btn.disabled = false;
btn.innerHTML = originalHtml;
});
});
</script>
<?php endif; ?>

View File

@ -0,0 +1,2 @@
-- Add name_ar to product_variants
ALTER TABLE product_variants ADD COLUMN name_ar VARCHAR(255) AFTER name;

View File

@ -0,0 +1,2 @@
-- Add full_name_ar to users table
ALTER TABLE users ADD COLUMN full_name_ar VARCHAR(255) AFTER full_name;

View File

@ -0,0 +1,3 @@
-- Add name_ar to outlets and expense_categories
ALTER TABLE outlets ADD COLUMN name_ar VARCHAR(255) AFTER name;
ALTER TABLE expense_categories ADD COLUMN name_ar VARCHAR(255) AFTER name;

View File

@ -29,7 +29,7 @@ if (!$table_info) {
$outlet_id = (int)$table_info['outlet_id'];
$categories = $pdo->query("SELECT * FROM categories ORDER BY sort_order")->fetchAll();
$all_products = $pdo->query("SELECT p.*, c.name as category_name FROM products p JOIN categories c ON p.category_id = c.id")->fetchAll();
$all_products = $pdo->query("SELECT p.*, c.name as category_name, c.name_ar as category_name_ar FROM products p JOIN categories c ON p.category_id = c.id")->fetchAll();
// Fetch variants
$variants_raw = $pdo->query("SELECT * FROM product_variants ORDER BY price_adjustment ASC")->fetchAll();
@ -50,22 +50,46 @@ foreach ($variants_raw as $v) {
<?php endif; ?>
<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&display=swap" 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>
body { font-family: 'Inter', sans-serif; background-color: #f8f9fa; padding-bottom: 80px; }
:root {
--primary-font: 'Inter', sans-serif;
--arabic-font: 'Noto Sans Arabic', sans-serif;
}
body { font-family: var(--primary-font); background-color: #f8f9fa; padding-bottom: 80px; }
body.lang-ar { font-family: var(--arabic-font); direction: rtl; text-align: right; }
.category-nav { overflow-x: auto; white-space: nowrap; background: #fff; padding: 10px; position: sticky; top: 0; z-index: 1020; border-bottom: 1px solid #eee; }
.category-item { display: inline-block; padding: 8px 16px; border-radius: 20px; background: #f1f3f5; margin-right: 8px; font-weight: 500; font-size: 0.9rem; cursor: pointer; border: 1px solid transparent; }
.lang-ar .category-item { margin-right: 0; margin-left: 8px; }
.category-item.active { background: #0d6efd; color: #fff; }
.product-card { border: none; border-radius: 12px; overflow: hidden; box-shadow: 0 2px 8px rgba(0,0,0,0.05); transition: transform 0.2s; }
.product-card { border: none; border-radius: 12px; overflow: hidden; box-shadow: 0 2px 8px rgba(0,0,0,0.05); transition: transform 0.2s; position: relative; }
.product-card:active { transform: scale(0.98); }
.product-img { height: 140px; object-fit: cover; }
.cart-footer { position: fixed; bottom: 0; left: 0; right: 0; background: #fff; padding: 15px; border-top: 1px solid #eee; z-index: 1030; display: none; }
.badge-price { position: absolute; bottom: 10px; right: 10px; background: rgba(255,255,255,0.9); padding: 2px 8px; border-radius: 12px; font-weight: bold; font-size: 0.85rem; }
.lang-ar .badge-price { right: auto; left: 10px; }
.quantity-controls { display: flex; align-items: center; gap: 10px; }
.quantity-btn { width: 32px; height: 32px; border-radius: 50%; border: 1px solid #dee2e6; background: #fff; display: flex; align-items: center; justify-content: center; }
.lang-toggle { font-size: 0.8rem; font-weight: bold; cursor: pointer; padding: 4px 8px; border-radius: 4px; border: 1px solid #dee2e6; background: #f8f9fa; }
.name-en { display: block; }
.name-ar { display: none; }
.lang-ar .name-en { display: none; }
.lang-ar .name-ar { display: block; }
.both-names .name-en { display: block; }
.both-names .name-ar { display: block; font-size: 0.85em; opacity: 0.8; color: #0d6efd; margin-top: 2px; }
.modal-header .btn-close { margin: 0; }
.lang-ar .modal-header .btn-close { margin-right: auto; margin-left: 0; }
</style>
</head>
<body>
<body class="both-names">
<!-- Header -->
<header class="bg-white p-3 border-bottom d-flex align-items-center justify-content-between">
@ -75,14 +99,27 @@ foreach ($variants_raw as $v) {
<?php endif; ?>
<span class="fw-bold"><?= htmlspecialchars($settings['company_name']) ?></span>
</div>
<div class="badge bg-light text-dark border">Table <?= htmlspecialchars($table_info['table_name']) ?></div>
<div class="d-flex align-items-center gap-2">
<div class="lang-toggle" onclick="toggleLanguage()" id="lang-btn">AR</div>
<div class="badge bg-light text-dark border"><span data-t="table">Table</span> <?= htmlspecialchars($table_info['table_name']) ?></div>
</div>
</header>
<!-- Category Nav -->
<div class="category-nav shadow-sm">
<div class="category-item active" onclick="filterCategory('all', this)">All</div>
<div class="category-item active" onclick="filterCategory('all', this)">
<span class="name-en">All</span>
<span class="name-ar">الكل</span>
</div>
<?php foreach ($categories as $cat): ?>
<div class="category-item" onclick="filterCategory(<?= $cat['id'] ?>, this)"><?= htmlspecialchars($cat['name']) ?></div>
<div class="category-item" onclick="filterCategory(<?= $cat['id'] ?>, this)">
<span class="name-en"><?= htmlspecialchars($cat['name']) ?></span>
<?php if (!empty($cat['name_ar'])): ?>
<span class="name-ar"><?= htmlspecialchars($cat['name_ar']) ?></span>
<?php else: ?>
<span class="name-ar"><?= htmlspecialchars($cat['name']) ?></span>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>
@ -98,6 +135,7 @@ foreach ($variants_raw as $v) {
onclick="handleProductClick(<?= htmlspecialchars(json_encode([
'id' => $product['id'],
'name' => $product['name'],
'name_ar' => $product['name_ar'] ?? $product['name'],
'price' => (float)$effective_price,
'has_variants' => $has_variants
])) ?>)">
@ -110,7 +148,7 @@ foreach ($variants_raw as $v) {
<?php else: ?>
<?= number_format((float)$product['price'], 3) ?>
<?php endif; ?>
OMR
<span data-t="currency">OMR</span>
</div>
<?php if ($is_promo): ?>
<div class="position-absolute top-0 start-0 m-2">
@ -119,8 +157,14 @@ foreach ($variants_raw as $v) {
<?php endif; ?>
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1 small fw-bold text-truncate"><?= htmlspecialchars($product['name']) ?></h6>
<p class="card-text small text-muted mb-0" style="font-size: 0.75rem;"><?= htmlspecialchars($product['category_name']) ?></p>
<h6 class="card-title mb-1 small fw-bold text-truncate">
<span class="name-en"><?= htmlspecialchars($product['name']) ?></span>
<span class="name-ar" dir="rtl"><?= htmlspecialchars($product['name_ar'] ?? $product['name']) ?></span>
</h6>
<p class="card-text small text-muted mb-0 text-truncate" style="font-size: 0.75rem;">
<span class="name-en"><?= htmlspecialchars($product['category_name']) ?></span>
<span class="name-ar" dir="rtl"><?= htmlspecialchars($product['category_name_ar'] ?? $product['category_name']) ?></span>
</p>
</div>
</div>
</div>
@ -132,11 +176,11 @@ foreach ($variants_raw as $v) {
<div class="cart-footer shadow-lg" id="cart-footer">
<div class="d-flex align-items-center justify-content-between">
<div>
<div class="small text-muted" id="cart-items-count">0 Items</div>
<div class="small text-muted"><span id="cart-items-count">0</span> <span data-t="items">Items</span></div>
<div class="fw-bold fs-5 text-primary" id="cart-total-display">0.000 OMR</div>
</div>
<button class="btn btn-primary px-4 fw-bold" onclick="showCart()">
View Cart <i class="bi bi-cart-fill ms-1"></i>
<span data-t="view_cart">View Cart</span> <i class="bi bi-cart-fill ms-1"></i>
</button>
</div>
</div>
@ -146,7 +190,7 @@ foreach ($variants_raw as $v) {
<div class="modal-dialog modal-dialog-centered modal-fullscreen-sm-down">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title fw-bold">Your Order</h5>
<h5 class="modal-title fw-bold" data-t="your_order">Your Order</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body p-0">
@ -155,21 +199,21 @@ foreach ($variants_raw as $v) {
</div>
<div class="p-3 bg-light border-top">
<div class="d-flex justify-content-between mb-2">
<span>Subtotal</span>
<span data-t="subtotal">Subtotal</span>
<span id="modal-subtotal">0.000 OMR</span>
</div>
<div class="d-flex justify-content-between fw-bold fs-5">
<span>Total</span>
<span data-t="total">Total</span>
<span id="modal-total">0.000 OMR</span>
</div>
</div>
<div class="p-3">
<div class="mb-3">
<label class="form-label small text-muted">Your Name (Optional)</label>
<input type="text" id="cust-name" class="form-control" placeholder="To identify your order">
<label class="form-label small text-muted" data-t="cust_name_label">Your Name (Optional)</label>
<input type="text" id="cust-name" class="form-control" data-t-placeholder="cust_name_placeholder" placeholder="To identify your order">
</div>
<button class="btn btn-primary btn-lg w-100 fw-bold" id="btn-place-order" onclick="placeOrder()">
Place Order <i class="bi bi-send-fill ms-1"></i>
<span data-t="place_order">Place Order</span> <i class="bi bi-send-fill ms-1"></i>
</button>
</div>
</div>
@ -182,7 +226,7 @@ foreach ($variants_raw as $v) {
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="variantTitle">Select Option</h5>
<h5 class="modal-title" id="variantTitle" data-t="select_option">Select Option</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
@ -202,9 +246,83 @@ foreach ($variants_raw as $v) {
const PRODUCT_VARIANTS = <?= json_encode($variants_by_product) ?>;
let cart = [];
let currentLang = localStorage.getItem('qorder_lang') || 'en';
const cartModal = new bootstrap.Modal(document.getElementById('cartModal'));
const variantModal = new bootstrap.Modal(document.getElementById('variantModal'));
const translations = {
en: {
table: 'Table',
items: 'Items',
view_cart: 'View Cart',
your_order: 'Your Order',
subtotal: 'Subtotal',
total: 'Total',
cust_name_label: 'Your Name (Optional)',
cust_name_placeholder: 'To identify your order',
place_order: 'Place Order',
select_option: 'Select Option',
currency: 'OMR',
added_to_cart: 'added to cart',
order_placed: 'Order Placed!',
order_success_msg: 'Your order has been sent to the kitchen. Thank you!',
placing_order: 'Placing Order...'
},
ar: {
table: 'طاولة',
items: 'أصناف',
view_cart: 'عرض السلة',
your_order: 'طلبك',
subtotal: 'المجموع الفرعي',
total: 'الإجمالي',
cust_name_label: 'اسمك (اختياري)',
cust_name_placeholder: 'لتحديد طلبك',
place_order: 'إتمام الطلب',
select_option: 'اختر الخيار',
currency: 'ر.ع.',
added_to_cart: 'تم الإضافة إلى السلة',
order_placed: 'تم إرسال الطلب!',
order_success_msg: 'تم إرسال طلبك إلى المطبخ. شكراً لك!',
placing_order: 'جاري إرسال الطلب...'
}
};
function updateTranslations() {
document.querySelectorAll('[data-t]').forEach(el => {
const key = el.getAttribute('data-t');
if (translations[currentLang][key]) {
el.textContent = translations[currentLang][key];
}
});
document.querySelectorAll('[data-t-placeholder]').forEach(el => {
const key = el.getAttribute('data-t-placeholder');
if (translations[currentLang][key]) {
el.placeholder = translations[currentLang][key];
}
});
document.getElementById('lang-btn').textContent = currentLang === 'en' ? 'AR' : 'EN';
if (currentLang === 'ar') {
document.body.classList.add('lang-ar');
document.body.classList.remove('both-names'); // Optional: hide EN when AR is active?
// User said "both", so maybe I should keep both-names active if I want to show both.
// But let's follow standard toggle behavior for UI.
} else {
document.body.classList.remove('lang-ar');
}
// Update currency in displays
updateCartUI();
}
function toggleLanguage() {
currentLang = currentLang === 'en' ? 'ar' : 'en';
localStorage.setItem('qorder_lang', currentLang);
updateTranslations();
}
// Initialize translations
updateTranslations();
function filterCategory(catId, el) {
document.querySelectorAll('.category-item').forEach(i => i.classList.remove('active'));
el.classList.add('active');
@ -222,14 +340,14 @@ foreach ($variants_raw as $v) {
if (product.has_variants) {
showVariants(product);
} else {
addToCart(product.id, product.name, product.price);
addToCart(product.id, currentLang === 'ar' ? product.name_ar : product.name, product.price);
}
}
function showVariants(product) {
const variants = PRODUCT_VARIANTS[product.id] || [];
const container = document.getElementById('variant-list');
document.getElementById('variantTitle').textContent = product.name;
document.getElementById('variantTitle').textContent = currentLang === 'ar' ? product.name_ar : product.name;
container.innerHTML = '';
variants.forEach(v => {
@ -237,15 +355,18 @@ foreach ($variants_raw as $v) {
btn.className = 'list-group-item list-group-item-action d-flex justify-content-between align-items-center py-3';
const adj = parseFloat(v.price_adjustment);
const finalPrice = product.price + adj;
const vName = currentLang === 'ar' && v.name_ar ? v.name_ar : v.name;
const pName = currentLang === 'ar' ? product.name_ar : product.name;
btn.innerHTML = `
<div>
<div class="fw-bold">${v.name}</div>
<div class="small text-muted">${adj > 0 ? '+' : ''}${adj.toFixed(3)} OMR</div>
<div class="fw-bold">${vName}</div>
<div class="small text-muted">${adj > 0 ? '+' : ''}${adj.toFixed(3)} ${translations[currentLang].currency}</div>
</div>
<div class="fw-bold text-primary">${finalPrice.toFixed(3)} OMR</div>
<div class="fw-bold text-primary">${finalPrice.toFixed(3)} ${translations[currentLang].currency}</div>
`;
btn.onclick = () => {
addToCart(product.id, `${product.name} (${v.name})`, finalPrice, v.id);
addToCart(product.id, `${pName} (${vName})`, finalPrice, v.id);
variantModal.hide();
};
container.appendChild(btn);
@ -261,15 +382,16 @@ foreach ($variants_raw as $v) {
cart.push({ product_id: pid, name, unit_price: price, variant_id: vid, quantity: 1 });
}
updateCartUI();
showToast(name + ' added to cart');
showToast(name + ' ' + translations[currentLang].added_to_cart);
}
function updateCartUI() {
const total = cart.reduce((sum, item) => sum + (item.unit_price * item.quantity), 0);
const count = cart.reduce((sum, item) => sum + item.quantity, 0);
const currency = translations[currentLang].currency;
document.getElementById('cart-items-count').textContent = count + ' Items';
document.getElementById('cart-total-display').textContent = total.toFixed(3) + ' OMR';
document.getElementById('cart-items-count').textContent = count;
document.getElementById('cart-total-display').textContent = total.toFixed(3) + ' ' + currency;
const footer = document.getElementById('cart-footer');
if (count > 0) {
@ -282,6 +404,7 @@ foreach ($variants_raw as $v) {
function showCart() {
const list = document.getElementById('cart-list');
list.innerHTML = '';
const currency = translations[currentLang].currency;
cart.forEach((item, index) => {
const div = document.createElement('div');
@ -304,8 +427,8 @@ foreach ($variants_raw as $v) {
});
const total = cart.reduce((sum, item) => sum + (item.unit_price * item.quantity), 0);
document.getElementById('modal-subtotal').textContent = total.toFixed(3) + ' OMR';
document.getElementById('modal-total').textContent = total.toFixed(3) + ' OMR';
document.getElementById('modal-subtotal').textContent = total.toFixed(3) + ' ' + currency;
document.getElementById('modal-total').textContent = total.toFixed(3) + ' ' + currency;
cartModal.show();
}
@ -328,19 +451,19 @@ foreach ($variants_raw as $v) {
const btn = document.getElementById('btn-place-order');
btn.disabled = true;
btn.innerHTML = '<span class="spinner-border spinner-border-sm me-2"></span>Placing Order...';
btn.innerHTML = `<span class="spinner-border spinner-border-sm me-2"></span>${translations[currentLang].placing_order}`;
const total = cart.reduce((sum, item) => sum + (item.unit_price * item.quantity), 0);
const customerName = document.getElementById('cust-name').value;
const payload = {
outlet_id: OUTLET_ID,
table_number: TABLE_ID, // api/order.php expects table ID in table_number
table_number: TABLE_ID,
order_type: 'dine-in',
customer_name: customerName,
items: cart,
total_amount: total,
payment_type_id: null // Unpaid
payment_type_id: null
};
fetch('api/order.php', {
@ -352,10 +475,10 @@ foreach ($variants_raw as $v) {
.then(data => {
if (data.success) {
Swal.fire({
title: 'Order Placed!',
text: 'Your order has been sent to the kitchen. Thank you!',
title: translations[currentLang].order_placed,
text: translations[currentLang].order_success_msg,
icon: 'success',
confirmButtonText: 'Great!'
confirmButtonText: currentLang === 'ar' ? 'ممتاز' : 'Great!'
}).then(() => {
cart = [];
updateCartUI();
@ -371,13 +494,22 @@ foreach ($variants_raw as $v) {
})
.finally(() => {
btn.disabled = false;
btn.innerHTML = 'Place Order <i class="bi bi-send-fill ms-1"></i>';
btn.innerHTML = `${translations[currentLang].place_order} <i class="bi bi-send-fill ms-1"></i>`;
});
}
function showToast(msg) {
// Simple alert for now, or use a toast
console.log(msg);
const Toast = Swal.mixin({
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 2000,
timerProgressBar: true
});
Toast.fire({
icon: 'success',
title: msg
});
}
</script>
</body>

185
rate.php
View File

@ -39,7 +39,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Fetch active and ratable users with pictures
$pdo = db();
$stmt = $pdo->query("SELECT id, full_name, username, profile_pic FROM users WHERE is_active = 1 AND is_ratable = 1 ORDER BY full_name ASC");
$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>
@ -50,7 +50,7 @@ $users = $stmt->fetchAll(PDO::FETCH_ASSOC);
<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&display=swap" 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;
@ -64,6 +64,12 @@ $users = $stmt->fetchAll(PDO::FETCH_ASSOC);
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 {
@ -75,6 +81,19 @@ $users = $stmt->fetchAll(PDO::FETCH_ASSOC);
.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 {
@ -210,6 +229,13 @@ $users = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
.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>
@ -219,21 +245,27 @@ $users = $stmt->fetchAll(PDO::FETCH_ASSOC);
<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="<?= htmlspecialchars($logoUrl) ?>" alt="Logo" class="logo">
<?php else: ?>
<h1 class="fw-bold"><?= htmlspecialchars($companyName) ?></h1>
<?php endif; ?>
<p class="text-muted" id="main-instruction">We value your feedback! What would you like to rate?</p>
<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>Thank You!</h2>
<p>Your rating has been submitted successfully.</p>
<a href="index.php" class="btn btn-outline-primary rounded-pill px-4 mt-3">Back to Home</a>
<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: ?>
@ -251,23 +283,23 @@ $users = $stmt->fetchAll(PDO::FETCH_ASSOC);
<div class="service-icon">
<i class="bi bi-shop"></i>
</div>
<div class="service-name fs-4">Rate Our Services</div>
<p class="text-muted small">How was your overall experience with us?</p>
<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">OR RATE OUR STAFF</h5>
<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">No staff members are currently available for rating.</p>
<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']) ?>', this)">
<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: ?>
@ -275,7 +307,12 @@ $users = $stmt->fetchAll(PDO::FETCH_ASSOC);
<?= strtoupper(substr($user['full_name'] ?: $user['username'], 0, 1)) ?>
</div>
<?php endif; ?>
<div class="staff-name"><?= htmlspecialchars($user['full_name'] ?: $user['username']) ?></div>
<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; ?>
@ -287,7 +324,7 @@ $users = $stmt->fetchAll(PDO::FETCH_ASSOC);
<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">Rate <span id="staff-display-name"></span></h4>
<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">
@ -300,16 +337,16 @@ $users = $stmt->fetchAll(PDO::FETCH_ASSOC);
</div>
<div class="mb-3">
<label for="comment" class="form-label fw-semibold" id="comment-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..."></textarea>
<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()">Cancel</button>
<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">Submit Rating</button>
<button type="submit" class="btn btn-primary btn-submit m-0 py-3 fw-bold" data-t="submit">Submit Rating</button>
</div>
</div>
</form>
@ -317,7 +354,95 @@ $users = $stmt->fetchAll(PDO::FETCH_ASSOC);
</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';
@ -326,19 +451,18 @@ function selectService() {
document.getElementById('rating-type').value = 'service';
document.getElementById('selected-user-id').value = '';
// Set labels
document.getElementById('staff-display-name').innerText = 'Our Services';
document.getElementById('rating-subtitle').innerText = 'We would love to hear how we are doing overall.';
document.getElementById('comment-label').innerText = 'What can we improve?';
// Show rating form
document.getElementById('rating-form').style.display = 'block';
// Smooth scroll to form
updateUI();
window.scrollTo({ top: 0, behavior: 'smooth' });
}
function selectStaff(id, name, element) {
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';
@ -347,19 +471,15 @@ function selectStaff(id, name, element) {
document.getElementById('rating-type').value = 'staff';
document.getElementById('selected-user-id').value = id;
// Set labels
document.getElementById('staff-display-name').innerText = name;
document.getElementById('rating-subtitle').innerText = 'Rate the service provided by this staff member.';
document.getElementById('comment-label').innerText = 'Any specific feedback for ' + name + '?';
// Show rating form
document.getElementById('rating-form').style.display = 'block';
// Smooth scroll to form
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';
@ -368,7 +488,12 @@ function cancelSelection() {
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>