38929-vm/items.php
2026-03-03 18:08:33 +00:00

831 lines
39 KiB
PHP

<?php
ob_start();
session_start();
$action = $_POST['action'] ?? $_GET['action'] ?? '';
$isAjax = isset($_POST['ajax']) || isset($_GET['ajax']) || (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest');
require_once __DIR__ . '/db/config.php';
// Action handling
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
$action = $_POST['action'];
if ($action === 'add_category') {
$name_en = $_POST['cat_name_en'];
$name_ar = $_POST['cat_name_ar'];
$stmt = db()->prepare("INSERT INTO categories (name_en, name_ar) VALUES (?, ?)");
$stmt->execute([$name_en, $name_ar]);
if ($isAjax) {
header('Content-Type: application/json');
$categories = db()->query("SELECT * FROM categories ORDER BY name_en ASC")->fetchAll();
ob_start();
foreach($categories as $cat): ?>
<tr>
<td><?= $cat['name_en'] ?></td>
<td><?= $cat['name_ar'] ?></td>
<td class="text-end">
<button class="btn btn-sm btn-light p-1 me-1" onclick='editCategory(<?= json_encode($cat) ?>)'><i class="bi bi-pencil text-primary"></i></button>
<button class="btn btn-sm btn-light p-1" onclick="confirmDeleteAjax('category', <?= $cat['id'] ?>)"><i class="bi bi-trash text-danger"></i></button>
</td>
</tr>
<?php endforeach;
$html = ob_get_clean();
echo json_encode(['success' => true, 'html' => $html]);
exit;
}
header('Location: items.php?success=category_added');
exit;
} elseif ($action === 'edit_category') {
$id = $_POST['id'];
$name_en = $_POST['cat_name_en'];
$name_ar = $_POST['cat_name_ar'];
$stmt = db()->prepare("UPDATE categories SET name_en = ?, name_ar = ? WHERE id = ?");
$stmt->execute([$name_en, $name_ar, $id]);
if ($isAjax) {
header('Content-Type: application/json');
$categories = db()->query("SELECT * FROM categories ORDER BY name_en ASC")->fetchAll();
ob_start();
foreach($categories as $cat): ?>
<tr>
<td><?= $cat['name_en'] ?></td>
<td><?= $cat['name_ar'] ?></td>
<td class="text-end">
<button class="btn btn-sm btn-light p-1 me-1" onclick='editCategory(<?= json_encode($cat) ?>)'><i class="bi bi-pencil text-primary"></i></button>
<button class="btn btn-sm btn-light p-1" onclick="confirmDeleteAjax('category', <?= $cat['id'] ?>)"><i class="bi bi-trash text-danger"></i></button>
</td>
</tr>
<?php endforeach;
$html = ob_get_clean();
echo json_encode(['success' => true, 'html' => $html]);
exit;
}
header('Location: items.php?success=category_updated');
exit;
} elseif ($action === 'delete_category') {
$id = $_POST['id'];
$stmt = db()->prepare("DELETE FROM categories WHERE id = ?");
$stmt->execute([$id]);
if ($isAjax) {
header('Content-Type: application/json');
$categories = db()->query("SELECT * FROM categories ORDER BY name_en ASC")->fetchAll();
ob_start();
foreach($categories as $cat): ?>
<tr>
<td><?= $cat['name_en'] ?></td>
<td><?= $cat['name_ar'] ?></td>
<td class="text-end">
<button class="btn btn-sm btn-light p-1 me-1" onclick='editCategory(<?= json_encode($cat) ?>)'><i class="bi bi-pencil text-primary"></i></button>
<button class="btn btn-sm btn-light p-1" onclick="confirmDeleteAjax('category', <?= $cat['id'] ?>)"><i class="bi bi-trash text-danger"></i></button>
</td>
</tr>
<?php endforeach;
$html = ob_get_clean();
echo json_encode(['success' => true, 'html' => $html]);
exit;
}
header('Location: items.php?success=category_deleted');
exit;
} elseif ($action === 'add_item') {
$category_id = $_POST['category_id'] ?: null;
$name_en = $_POST['name_en'];
$name_ar = $_POST['name_ar'];
$vat_percent = $_POST['vat_percent'] ?: 0;
$image_url = null;
if (isset($_FILES['image']) && $_FILES['image']['error'] === 0) {
$ext = pathinfo($_FILES['image']['name'], PATHINFO_EXTENSION);
$filename = 'item_' . uniqid('', true) . '.' . $ext;
$upload_dir = __DIR__ . '/assets/images/items/';
if (!is_dir($upload_dir)) mkdir($upload_dir, 0777, true);
if (move_uploaded_file($_FILES['image']['tmp_name'], $upload_dir . $filename)) {
$image_url = 'assets/images/items/' . $filename;
}
}
$stmt = db()->prepare("INSERT INTO items (category_id, name_en, name_ar, vat_percent, image_url) VALUES (?, ?, ?, ?, ?)");
$stmt->execute([$category_id, $name_en, $name_ar, $vat_percent, $image_url]);
header('Location: items.php?success=item_added');
exit;
} elseif ($action === 'edit_item') {
$id = $_POST['id'];
$category_id = $_POST['category_id'] ?: null;
$name_en = $_POST['name_en'];
$name_ar = $_POST['name_ar'];
$vat_percent = $_POST['vat_percent'] ?: 0;
$image_url = null;
if (isset($_FILES['image']) && $_FILES['image']['error'] === 0) {
$ext = pathinfo($_FILES['image']['name'], PATHINFO_EXTENSION);
$filename = 'item_' . uniqid('', true) . '.' . $ext;
$upload_dir = __DIR__ . '/assets/images/items/';
if (!is_dir($upload_dir)) mkdir($upload_dir, 0777, true);
if (move_uploaded_file($_FILES['image']['tmp_name'], $upload_dir . $filename)) {
$image_url = 'assets/images/items/' . $filename;
}
}
if ($image_url) {
$stmt = db()->prepare("UPDATE items SET category_id = ?, name_en = ?, name_ar = ?, vat_percent = ?, image_url = ? WHERE id = ?");
$stmt->execute([$category_id, $name_en, $name_ar, $vat_percent, $image_url, $id]);
} else {
$stmt = db()->prepare("UPDATE items SET category_id = ?, name_en = ?, name_ar = ?, vat_percent = ? WHERE id = ?");
$stmt->execute([$category_id, $name_en, $name_ar, $vat_percent, $id]);
}
header('Location: items.php?success=item_updated');
exit;
} elseif ($action === 'delete_item') {
$id = $_POST['id'];
$stmt = db()->prepare("DELETE FROM items WHERE id = ?");
$stmt->execute([$id]);
header('Location: items.php?success=item_deleted');
exit;
} elseif ($action === 'add_service') {
$name_en = $_POST['svc_name_en'];
$name_ar = $_POST['svc_name_ar'];
$stmt = db()->prepare("INSERT INTO services (name_en, name_ar) VALUES (?, ?)");
$stmt->execute([$name_en, $name_ar]);
if ($isAjax) {
header('Content-Type: application/json');
echo json_encode(['success' => true, 'html' => renderServiceList($lang)]);
exit;
}
header('Location: items.php?success=service_added');
exit;
} elseif ($action === 'edit_service') {
$id = $_POST['id'];
$name_en = $_POST['svc_name_en'];
$name_ar = $_POST['svc_name_ar'];
$stmt = db()->prepare("UPDATE services SET name_en = ?, name_ar = ? WHERE id = ?");
$stmt->execute([$name_en, $name_ar, $id]);
if ($isAjax) {
header('Content-Type: application/json');
echo json_encode(['success' => true, 'html' => renderServiceList($lang)]);
exit;
}
header('Location: items.php?success=service_updated');
exit;
} elseif ($action === 'delete_service') {
$id = $_POST['id'];
$stmt = db()->prepare("DELETE FROM services WHERE id = ?");
$stmt->execute([$id]);
if ($isAjax) {
header('Content-Type: application/json');
echo json_encode(['success' => true, 'html' => renderServiceList($lang)]);
exit;
}
header('Location: items.php?success=service_deleted');
exit;
} elseif ($action === 'update_price') {
$item_id = $_POST['item_id'];
$service_id = $_POST['service_id'];
$price = $_POST['price'];
// Handle empty/invalid price
if ($price === '') $price = 0;
$price = str_replace(',', '.', $price); // Handle comma as decimal separator
$price = (float)$price;
// Determine branch_id from session (if available)
$branch_id = $_SESSION['branch_id'] ?? null;
if ($branch_id === 'all') $branch_id = null;
// Final sanity check for branch_id to avoid FK errors if session has stale ID
if ($branch_id) {
$chk = db()->prepare("SELECT id FROM branches WHERE id = ?");
$chk->execute([$branch_id]);
if (!$chk->fetch()) $branch_id = null;
}
try {
if ($branch_id) {
$stmt = db()->prepare("INSERT INTO prices (item_id, service_id, price, branch_id)
VALUES (?, ?, ?, ?)
ON DUPLICATE KEY UPDATE price = ?");
$stmt->execute([$item_id, $service_id, $price, $branch_id, $price]);
} else {
$stmt = db()->prepare("INSERT INTO prices (item_id, service_id, price)
VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE price = ?");
$stmt->execute([$item_id, $service_id, $price, $price]);
}
if ($isAjax) {
header('Content-Type: application/json');
echo json_encode(['success' => true]);
exit;
}
header('Location: items.php?success=price_updated');
exit;
} catch (Exception $e) {
if ($isAjax) {
header('Content-Type: application/json');
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
exit;
}
header('Location: items.php?error=save_failed');
exit;
}
}
}
// NOW Include header
$title = 'items';
require_once __DIR__ . '/includes/header.php';
// Filter logic
$search = $_GET['search'] ?? '';
$category_filter = $_GET['category_id'] ?? '';
$categories = db()->query("SELECT * FROM categories ORDER BY name_en ASC")->fetchAll();
$query = "SELECT i.*, c.name_en as cat_en, c.name_ar as cat_ar
FROM items i
LEFT JOIN categories c ON i.category_id = c.id";
$params = [];
$where = [];
if ($search) {
$where[] = "(i.name_en LIKE ? OR i.name_ar LIKE ?)";
$params[] = "%$search%";
$params[] = "%$search%";
}
if ($category_filter) {
$where[] = "i.category_id = ?";
$params[] = $category_filter;
}
if ($where) {
$query .= " WHERE " . implode(" AND ", $where);
}
$query .= " ORDER BY i.name_en ASC";
$stmt = db()->prepare($query);
$stmt->execute($params);
$items = $stmt->fetchAll();
$services = db()->query("SELECT * FROM services ORDER BY name_en ASC")->fetchAll();
$stmt = db()->prepare("SELECT * FROM prices ");
$stmt->execute();
$prices_raw = $stmt->fetchAll();
$prices = [];
foreach ($prices_raw as $p) {
$prices[$p['item_id']][$p['service_id']] = $p['price'];
}
function renderServiceList($lang) {
$services = db()->query("SELECT * FROM services ORDER BY name_en ASC")->fetchAll();
ob_start();
foreach($services as $svc): ?>
<tr>
<td><?= $svc['name_en'] ?></td>
<td><?= $svc['name_ar'] ?></td>
<td class="text-end">
<button class="btn btn-sm btn-light p-1 me-1" onclick='editService(<?= json_encode($svc) ?>)'><i class="bi bi-pencil text-primary"></i></button>
<button class="btn btn-sm btn-light p-1" onclick="confirmDeleteAjax('service', <?= $svc['id'] ?>)"><i class="bi bi-trash text-danger"></i></button>
</td>
</tr>
<?php endforeach;
return ob_get_clean();
}
?>
<div class="d-flex justify-content-between align-items-center mb-4">
<div>
<h2 class="fw-bold mb-1"><?= __('items') ?></h2>
<p class="text-muted small mb-0"><?= __('manage_items_categories_services') ?? 'Manage your items, categories and services' ?></p>
</div>
<div class="d-flex gap-2">
<button type="button" class="btn btn-light shadow-sm px-3" style="border-radius: 12px;" data-bs-toggle="modal" data-bs-target="#categoriesModal">
<i class="bi bi-tags me-2 text-primary"></i> <?= __('categories') ?>
</button>
<button type="button" class="btn btn-light shadow-sm px-3" style="border-radius: 12px;" data-bs-toggle="modal" data-bs-target="#servicesModal">
<i class="bi bi-gear me-2 text-primary"></i> <?= __('services') ?>
</button>
<?php if (has_permission('add')): ?>
<button type="button" class="btn btn-primary shadow-sm px-4" style="border-radius: 12px;" data-bs-toggle="modal" data-bs-target="#itemModal" onclick="resetForm()">
<i class="bi bi-plus-lg me-2"></i> <?= __('add_item') ?>
</button>
<?php endif; ?>
</div>
</div>
<div class="card border-0 shadow-sm mb-4" style="border-radius: 20px;">
<div class="card-body p-4">
<form method="GET" class="row g-3">
<div class="col-md-5">
<div class="input-group">
<span class="input-group-text bg-light border-0"><i class="bi bi-search"></i></span>
<input type="text" name="search" class="form-control bg-light border-0" placeholder="<?= __('search_items') ?>" value="<?= htmlspecialchars($search) ?>">
</div>
</div>
<div class="col-md-4">
<select name="category_id" class="form-select bg-light border-0">
<option value=""><?= __('all_categories') ?></option>
<?php foreach($categories as $cat): ?>
<option value="<?= $cat['id'] ?>" <?= $category_filter == $cat['id'] ? 'selected' : '' ?> >
<?= $lang === 'ar' ? $cat['name_ar'] : $cat['name_en'] ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-3">
<button type="submit" class="btn btn-dark w-100" style="border-radius: 12px;"><?= __('filter') ?></button>
</div>
</form>
</div>
</div>
<div class="row g-4">
<?php foreach($items as $item):
?><div class="col-md-6 col-lg-4 col-xl-3">
<div class="card h-100 border-0 shadow-sm item-card" style="border-radius: 20px; overflow: hidden;">
<div style="height: 180px; overflow: hidden; position: relative;">
<?php if ($item['image_url']): ?>
<img src="<?= htmlspecialchars($item['image_url']) ?>" class="card-img-top h-100 w-100 object-fit-cover" alt="<?= htmlspecialchars($item['name_en']) ?>">
<?php else:
?><div class="bg-light h-100 w-100 d-flex align-items-center justify-content-center">
<i class="bi bi-image text-muted opacity-25" style="font-size: 3rem;"></i>
</div>
<?php endif; ?>
<div class="position-absolute top-0 end-0 p-3">
<span class="badge bg-white text-dark shadow-sm py-2 px-3" style="border-radius: 10px;">
<?= htmlspecialchars($item['cat_en'] ?? __('uncategorized')) ?>
</span>
</div>
</div>
<div class="card-body p-4">
<h5 class="fw-bold mb-1"><?= htmlspecialchars($item['name_en']) ?></h5>
<p class="text-muted small mb-3"><?= htmlspecialchars($item['name_ar']) ?></p>
<div class="d-flex align-items-center justify-content-between mt-auto">
<div class="text-primary small fw-bold">
<?= count($services) ?> <?= __('services') ?>
</div>
<div class="btn-group">
<button class="btn btn-sm btn-light p-2" style="border-radius: 8px;" data-bs-toggle="modal" data-bs-target="#pricingModal<?= $item['id'] ?>">
<i class="bi bi-tag-fill text-primary"></i>
</button>
<?php if (has_permission('edit')): ?>
<button class="btn btn-sm btn-light p-2 mx-1" style="border-radius: 8px;" onclick="editItem(<?= htmlspecialchars(json_encode($item), ENT_QUOTES) ?>)">
<i class="bi bi-pencil text-primary"></i>
</button>
<?php endif; ?>
<?php if (has_permission('delete')): ?>
<button class="btn btn-sm btn-light p-2" style="border-radius: 8px;" onclick="confirmDeleteAjax('item', <?= $item['id'] ?>)">
<i class="bi bi-trash text-danger"></i>
</button>
<?php endif; ?>
</div>
</div>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
<!-- Modals -->
<!-- Item Modal -->
<div class="modal fade" id="itemModal" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content" style="border-radius: 25px;">
<div class="modal-header border-0 p-4">
<h5 class="modal-title fw-bold" id="itemModalLabel"><?= __('add_item') ?></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body p-4 pt-0">
<form id="itemForm" method="POST" enctype="multipart/form-data">
<input type="hidden" name="action" id="itemAction" value="add_item">
<input type="hidden" name="id" id="itemId">
<div class="text-center mb-4">
<div id="imagePreviewContainer" class="d-none mb-3">
<img id="imagePreview" src="" class="rounded-4 shadow-sm" style="max-height: 150px; width: auto;">
</div>
<label class="btn btn-light w-100 py-3 mb-0" style="border-radius: 15px; border: 2px dashed #dee2e6;">
<i class="bi bi-cloud-arrow-up fs-4 d-block mb-1"></i>
<span class="small text-muted"><?= __('upload_image') ?></span>
<input type="file" name="image" id="itemImageFile" class="d-none" accept="image/*">
</label>
</div>
<div class="mb-3">
<label class="form-label small fw-bold"><?= __('name_en') ?></label>
<div class="input-group">
<input type="text" name="name_en" id="itemNameEn" class="form-control" placeholder="Item Name (English)" required>
<button type="button" class="btn btn-outline-secondary" onclick="translateField('itemNameEn', 'itemNameAr', 'en-ar')">
<i class="bi bi-translate"></i>
</button>
</div>
</div>
<div class="mb-3">
<label class="form-label small fw-bold"><?= __('name_ar') ?></label>
<div class="input-group">
<input type="text" name="name_ar" id="itemNameAr" class="form-control text-end" placeholder="اسم الصنف (بالعربي)" required>
<button type="button" class="btn btn-outline-secondary" onclick="translateField('itemNameAr', 'itemNameEn', 'ar-en')">
<i class="bi bi-translate"></i>
</button>
</div>
</div>
<div class="mb-3">
<label class="form-label small fw-bold"><?= __('category') ?></label>
<select name="category_id" id="itemCategory" class="form-select" required>
<option value=""><?= __('select_category') ?></option>
<?php foreach($categories as $cat):
?><option value="<?= $cat['id'] ?>"><?= $lang === 'ar' ? $cat['name_ar'] : $cat['name_en'] ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="mb-4">
<label class="form-label small fw-bold"><?= __('vat_percent') ?> (%)</label>
<input type="number" step="0.01" name="vat_percent" id="itemVat" class="form-control" placeholder="0.00">
</div>
<div class="d-flex gap-2">
<button type="button" class="btn btn-light w-100 py-2 fw-bold" style="border-radius: 12px;" data-bs-dismiss="modal"><?= __('cancel') ?></button>
<button type="submit" class="btn btn-primary w-100 py-2 fw-bold" style="border-radius: 12px;"><?= __('save') ?></button>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- Categories Modal -->
<div class="modal fade" id="categoriesModal" tabindex="-1">
<div class="modal-dialog modal-lg modal-dialog-centered">
<div class="modal-content" style="border-radius: 25px;">
<div class="modal-header border-0 p-4">
<h5 class="modal-title fw-bold"><?= __('manage_categories') ?></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body p-4 pt-0">
<div class="row g-4">
<div class="col-md-5">
<form id="categoryForm" method="POST">
<input type="hidden" name="action" id="catAction" value="add_category">
<input type="hidden" name="id" id="catId">
<input type="hidden" name="ajax" value="1">
<div class="mb-3">
<label class="form-label small fw-bold"><?= __('name_en') ?></label>
<div class="input-group">
<input type="text" name="cat_name_en" id="catNameEn" class="form-control" required>
<button type="button" class="btn btn-outline-secondary btn-sm" onclick="translateField('catNameEn', 'catNameAr', 'en-ar')">
<i class="bi bi-translate"></i>
</button>
</div>
</div>
<div class="mb-3">
<label class="form-label small fw-bold"><?= __('name_ar') ?></label>
<div class="input-group">
<input type="text" name="cat_name_ar" id="catNameAr" class="form-control text-end" required>
<button type="button" class="btn btn-outline-secondary btn-sm" onclick="translateField('catNameAr', 'catNameEn', 'ar-en')">
<i class="bi bi-translate"></i>
</button>
</div>
</div>
<button type="submit" class="btn btn-primary w-100 fw-bold" style="border-radius: 10px;">
<span id="catSubmitBtn"><?= __('add_category') ?></span>
</button>
<button type="button" id="catCancelBtn" class="btn btn-light w-100 mt-2 d-none" onclick="resetCatForm()" style="border-radius: 10px;">
<?= __('cancel') ?>
</button>
</form>
</div>
<div class="col-md-7">
<div class="table-responsive" style="max-height: 400px; overflow-y: auto;">
<table class="table table-hover small">
<thead>
<tr>
<th><?= __('name_en') ?></th>
<th><?= __('name_ar') ?></th>
<th class="text-end"><?= __('actions') ?></th>
</tr>
</thead>
<tbody id="categoryTableBody">
<?php foreach($categories as $cat): ?>
<tr>
<td><?= $cat['name_en'] ?></td>
<td><?= $cat['name_ar'] ?></td>
<td class="text-end">
<button class="btn btn-sm btn-light p-1 me-1" onclick='editCategory(<?= json_encode($cat) ?>)'><i class="bi bi-pencil text-primary"></i></button>
<button class="btn btn-sm btn-light p-1" onclick="confirmDeleteAjax('category', <?= $cat['id'] ?>)"><i class="bi bi-trash text-danger"></i></button>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Services Modal -->
<div class="modal fade" id="servicesModal" tabindex="-1">
<div class="modal-dialog modal-lg modal-dialog-centered">
<div class="modal-content" style="border-radius: 25px;">
<div class="modal-header border-0 p-4">
<h5 class="modal-title fw-bold"><?= __('manage_services') ?></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body p-4 pt-0">
<div class="row g-4">
<div class="col-md-5">
<form id="serviceForm" method="POST">
<input type="hidden" name="action" id="svcAction" value="add_service">
<input type="hidden" name="id" id="svcId">
<input type="hidden" name="ajax" value="1">
<div class="mb-3">
<label class="form-label small fw-bold"><?= __('name_en') ?></label>
<div class="input-group">
<input type="text" name="svc_name_en" id="svcNameEn" class="form-control" required>
<button type="button" class="btn btn-outline-secondary btn-sm" onclick="translateField('svcNameEn', 'svcNameAr', 'en-ar')">
<i class="bi bi-translate"></i>
</button>
</div>
</div>
<div class="mb-3">
<label class="form-label small fw-bold"><?= __('name_ar') ?></label>
<div class="input-group">
<input type="text" name="svc_name_ar" id="svcNameAr" class="form-control text-end" required>
<button type="button" class="btn btn-outline-secondary btn-sm" onclick="translateField('svcNameAr', 'svcNameEn', 'ar-en')">
<i class="bi bi-translate"></i>
</button>
</div>
</div>
<button type="submit" class="btn btn-primary w-100 fw-bold" style="border-radius: 10px;">
<span id="svcSubmitBtn"><?= __('add_service') ?></span>
</button>
<button type="button" id="svcCancelBtn" class="btn btn-light w-100 mt-2 d-none" onclick="resetSvcForm()" style="border-radius: 10px;">
<?= __('cancel') ?>
</button>
</form>
</div>
<div class="col-md-7">
<div class="table-responsive" style="max-height: 400px; overflow-y: auto;">
<table class="table table-hover small">
<thead>
<tr>
<th><?= __('name_en') ?></th>
<th><?= __('name_ar') ?></th>
<th class="text-end"><?= __('actions') ?></th>
</tr>
</thead>
<tbody id="serviceTableBody">
<?= renderServiceList($lang) ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Pricing Modals -->
<?php foreach($items as $item): ?>
<div class="modal fade" id="pricingModal<?= $item['id'] ?>" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content" style="border-radius: 25px;">
<div class="modal-header border-0 p-4">
<h5 class="modal-title fw-bold">
<?= __('set_prices_for') ?> <?= $lang === 'ar' ? $item['name_ar'] : $item['name_en'] ?>
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body p-4 pt-0">
<div class="alert alert-light small border-0 mb-4" style="border-radius: 15px;">
<i class="bi bi-info-circle me-2"></i><?= __('prices_saved_automatically') ?>
</div>
<?php foreach($services as $svc): ?>
<div class="mb-3 d-flex align-items-center justify-content-between p-3 bg-light" style="border-radius: 15px;">
<div class="fw-bold small">
<?= $lang === 'ar' ? $svc['name_ar'] : $svc['name_en'] ?>
</div>
<div class="d-flex align-items-center" style="width: 150px;">
<input type="number" step="0.001"
class="form-control form-control-sm border-0 bg-white price-input"
style="border-radius: 10px;"
data-item-id="<?= $item['id'] ?>"
data-service-id="<?= $svc['id'] ?>"
value="<?= $prices[$item['id']][$svc['id']] ?? '' ?>"
placeholder="0.000">
<i class="bi bi-check-circle-fill text-success ms-2 success-indicator d-none"></i>
</div>
</div>
<?php endforeach; ?>
<button type="button" class="btn btn-dark w-100 py-3 fw-bold mt-3 shadow-sm" style="border-radius: 15px;" data-bs-dismiss="modal">
<?= __('done') ?>
</button>
</div>
</div>
</div>
</div>
<?php endforeach; ?>
<form id="deleteForm" method="POST" class="d-none">
<input type="hidden" name="action" id="deleteAction">
<input type="hidden" name="id" id="deleteId">
</form>
<script>
async function translateField(sourceId, targetId, direction) {
const sourceEl = document.getElementById(sourceId);
const targetEl = document.getElementById(targetId);
const text = sourceEl.value;
if (!text) return;
const btn = event.currentTarget;
const originalHtml = btn.innerHTML;
btn.disabled = true;
btn.innerHTML = '<span class="spinner-border spinner-border-sm"></span>';
try {
const response = await fetch('api/translate.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ text, direction })
});
const data = await response.json();
if (data.success) { targetEl.value = data.translated; }
} catch (e) { console.error(e); }
finally { btn.disabled = false; btn.innerHTML = originalHtml; }
}
function resetForm() {
document.getElementById('itemForm').reset();
document.getElementById('itemAction').value = 'add_item';
document.getElementById('itemModalLabel').innerText = '<?= __('add_item') ?>';
document.getElementById('imagePreviewContainer').classList.add('d-none');
}
function editItem(item) {
resetForm();
document.getElementById('itemAction').value = 'edit_item';
document.getElementById('itemId').value = item.id;
document.getElementById('itemNameEn').value = item.name_en;
document.getElementById('itemNameAr').value = item.name_ar;
document.getElementById('itemCategory').value = item.category_id || '';
document.getElementById('itemVat').value = item.vat_percent || '';
document.getElementById('itemModalLabel').innerText = '<?= __('edit_item') ?>';
if (item.image_url) {
document.getElementById('imagePreview').src = item.image_url;
document.getElementById('imagePreviewContainer').classList.remove('d-none');
}
new bootstrap.Modal(document.getElementById('itemModal')).show();
}
function confirmDeleteAjax(type, id) {
if (confirm('<?= __('confirm_delete') ?>')) {
document.getElementById('deleteAction').value = 'delete_' + type;
document.getElementById('deleteId').value = id;
document.getElementById('deleteForm').submit();
}
}
// Category AJAX
function editCategory(cat) {
document.getElementById('catAction').value = 'edit_category';
document.getElementById('catId').value = cat.id;
document.getElementById('catNameEn').value = cat.name_en;
document.getElementById('catNameAr').value = cat.name_ar;
document.getElementById('catSubmitBtn').innerText = '<?= __('save') ?>';
document.getElementById('catCancelBtn').classList.remove('d-none');
}
function resetCatForm() {
document.getElementById('categoryForm').reset();
document.getElementById('catAction').value = 'add_category';
document.getElementById('catSubmitBtn').innerText = '<?= __('add_category') ?>';
document.getElementById('catCancelBtn').classList.add('d-none');
}
document.getElementById('categoryForm').addEventListener('submit', async function(e) {
e.preventDefault();
const formData = new FormData(this);
try {
const response = await fetch('items.php', { method: 'POST', body: formData });
const data = await response.json();
if (data.success) {
document.getElementById('categoryTableBody').innerHTML = data.html;
resetCatForm();
} else {
alert(data.error || 'Failed to save category');
}
} catch (error) {
console.error('Error saving category:', error);
}
});
// Service AJAX
function editService(svc) {
document.getElementById('svcAction').value = 'edit_service';
document.getElementById('svcId').value = svc.id;
document.getElementById('svcNameEn').value = svc.name_en;
document.getElementById('svcNameAr').value = svc.name_ar;
document.getElementById('svcSubmitBtn').innerText = '<?= __('save') ?>';
document.getElementById('svcCancelBtn').classList.remove('d-none');
}
function resetSvcForm() {
document.getElementById('serviceForm').reset();
document.getElementById('svcAction').value = 'add_service';
document.getElementById('svcSubmitBtn').innerText = '<?= __('add_service') ?>';
document.getElementById('svcCancelBtn').classList.add('d-none');
}
// Service Form AJAX
document.getElementById('serviceForm').addEventListener('submit', async function(e) {
e.preventDefault();
const formData = new FormData(this);
try {
const response = await fetch('items.php', { method: 'POST', body: formData });
const data = await response.json();
if (data.success) {
document.getElementById('serviceTableBody').innerHTML = data.html;
resetSvcForm();
} else {
alert(data.error || 'Failed to save service');
}
} catch (error) {
console.error('Error saving service:', error);
}
});
// AJAX logic for prices
document.querySelectorAll('.price-input').forEach(input => {
let timeout = null;
input.addEventListener('input', function() {
if (this.readOnly || this.disabled) return;
clearTimeout(timeout);
const self = this;
timeout = setTimeout(async () => {
const formData = new FormData();
formData.append('action', 'update_price');
formData.append('ajax', '1');
formData.append('item_id', self.dataset.itemId);
formData.append('service_id', self.dataset.serviceId);
formData.append('price', self.value);
try {
const response = await fetch('items.php', {
method: 'POST',
body: formData
});
const data = await response.json();
if (data.success) {
showIndicator(self);
} else {
alert(data.error || 'Failed to update price');
}
} catch (error) {
console.error('Error updating price:', error);
alert('Error updating price: ' + error.message);
}
}, 500);
});
});
function showIndicator(input) {
const indicator = input.parentElement.querySelector('.success-indicator');
if (indicator) {
indicator.classList.remove('d-none');
setTimeout(() => {
indicator.classList.add('d-none');
}, 2000);
}
}
// Image preview logic
document.getElementById('itemImageFile').addEventListener('change', function(e) {
const file = e.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function(e) {
document.getElementById('imagePreview').src = e.target.result;
document.getElementById('imagePreviewContainer').classList.remove('d-none');
}
reader.readAsDataURL(file);
}
});
</script>
<?php require_once __DIR__ . '/includes/footer.php'; ?>