diff --git a/assets/js/main.js b/assets/js/main.js
index 4a595d9..7969b51 100644
--- a/assets/js/main.js
+++ b/assets/js/main.js
@@ -63,6 +63,10 @@ document.addEventListener('DOMContentLoaded', () => {
const pointsHistoryBody = document.getElementById('points-history-body');
const pointsHistoryEmpty = document.getElementById('points-history-empty');
+ const addCustomerModalEl = document.getElementById('addCustomerModal');
+ const addCustomerModal = addCustomerModalEl ? new bootstrap.Modal(addCustomerModalEl) : null;
+ const saveNewCustomerBtn = document.getElementById('save-new-customer');
+
let currentTableId = null;
let currentTableName = null;
const tableDisplay = document.getElementById('current-table-display');
@@ -288,6 +292,92 @@ document.addEventListener('DOMContentLoaded', () => {
});
}
+ if (redeemLoyaltyBtn) {
+ redeemLoyaltyBtn.addEventListener('click', () => {
+ if (!currentCustomer) return;
+ isLoyaltyRedemption = true;
+ processOrder(null, 'Loyalty Redeem');
+ });
+ }
+
+ if (viewPointsHistoryBtn) {
+ viewPointsHistoryBtn.addEventListener('click', () => {
+ if (!currentCustomer || !pointsHistoryModal) return;
+ pointsHistoryBody.innerHTML = '
';
+ pointsHistoryEmpty.classList.add('d-none');
+ pointsHistoryModal.show();
+
+ fetch(`api/customer_loyalty_history.php?customer_id=${currentCustomer.id}`)
+ .then(res => res.json())
+ .then(data => {
+ pointsHistoryBody.innerHTML = '';
+ if (data.success && data.history.length > 0) {
+ data.history.forEach(h => {
+ const item = document.createElement('div');
+ item.className = 'list-group-item px-0 border-0 border-bottom';
+ const badgeClass = h.points_change > 0 ? 'bg-success' : 'bg-danger';
+ item.innerHTML = `
+
+
${h.reason}
+
${h.points_change > 0 ? '+' : ''}${h.points_change}
+
+ ${h.created_at}
+ `;
+ pointsHistoryBody.appendChild(item);
+ });
+ } else {
+ pointsHistoryEmpty.classList.remove('d-none');
+ }
+ })
+ .catch(() => {
+ pointsHistoryBody.innerHTML = `${_t('error')}
`;
+ });
+ });
+ }
+
+ if (saveNewCustomerBtn) {
+ saveNewCustomerBtn.addEventListener('click', () => {
+ const name = document.getElementById('new-customer-name').value.trim();
+ const phone = document.getElementById('new-customer-phone').value.trim();
+
+ if (!name || !phone) {
+ showToast('Please fill in both name and phone', 'warning');
+ return;
+ }
+
+ saveNewCustomerBtn.disabled = true;
+ saveNewCustomerBtn.innerHTML = '';
+
+ fetch('api/create_customer.php', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ name, phone })
+ })
+ .then(res => res.json())
+ .then(data => {
+ saveNewCustomerBtn.disabled = false;
+ saveNewCustomerBtn.innerHTML = 'Add Customer';
+
+ if (data.success) {
+ showToast('Customer added successfully', 'success');
+ selectCustomer(data.customer);
+ if (addCustomerModal) addCustomerModal.hide();
+
+ // Clear inputs
+ document.getElementById('new-customer-name').value = '';
+ document.getElementById('new-customer-phone').value = '';
+ } else {
+ showToast(data.error || 'Failed to add customer', 'danger');
+ }
+ })
+ .catch(() => {
+ saveNewCustomerBtn.disabled = false;
+ saveNewCustomerBtn.innerHTML = 'Add Customer';
+ showToast('An error occurred', 'danger');
+ });
+ });
+ }
+
window.checkOrderType = function() {
const checked = document.querySelector('input[name="order_type"]:checked');
if (!checked) return;
@@ -442,8 +532,8 @@ document.addEventListener('DOMContentLoaded', () => {
if (typeof PAYMENT_TYPES !== 'undefined') {
PAYMENT_TYPES.forEach(pt => {
const col = document.createElement('div');
- col.className = 'col-6';
- col.innerHTML = ``;
+ col.className = 'col-12';
+ col.innerHTML = ``;
paymentMethodsContainer.appendChild(col);
});
}
@@ -464,7 +554,9 @@ document.addEventListener('DOMContentLoaded', () => {
outlet_id: CURRENT_OUTLET ? CURRENT_OUTLET.id : 1,
payment_type_id: paymentTypeId,
total_amount: subtotal + vat,
- vat: vat, items: cart.map(item => ({ product_id: item.id, quantity: item.quantity, unit_price: item.price, variant_id: item.variant_id }))
+ vat: vat,
+ items: cart.map(item => ({ product_id: item.id, quantity: item.quantity, unit_price: item.price, variant_id: item.variant_id })),
+ redeem_loyalty: isLoyaltyRedemption
};
fetch('api/order.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(orderData) })
diff --git a/assets/js/main.js?v=533-538 b/assets/js/main.js?v=533-538
new file mode 100644
index 0000000..21df886
--- /dev/null
+++ b/assets/js/main.js?v=533-538
@@ -0,0 +1,6 @@
+ PAYMENT_TYPES.forEach(pt => {
+ const col = document.createElement('div');
+ col.className = 'col-12';
+ col.innerHTML = ``;
+ paymentMethodsContainer.appendChild(col);
+ });
diff --git a/pos.php b/pos.php
index 028dbe4..954142d 100644
--- a/pos.php
+++ b/pos.php
@@ -106,7 +106,7 @@ if (!$loyalty_settings) {
.product-card:active { transform: scale(0.95); }
.product-card:hover { border-color: #0d6efd !important; box-shadow: 0 4px 12px rgba(0,0,0,0.08) !important; }
- .category-btn { text-align: left; border: none; background: none; padding: 10px 12px; width: 100%; display: flex; align-items: center; gap: 10px; border-radius: 12px; color: #64748b; font-weight: 700; transition: all 0.2s; }
+ .category-btn { font-size: 1.1rem; text-align: left; border: none; background: none; padding: 10px 12px; width: 100%; display: flex; align-items: center; gap: 10px; border-radius: 12px; color: #64748b; font-weight: 700; transition: all 0.2s; }
.category-btn:hover { background-color: #f1f5f9; color: #0f172a; }
.category-btn.active { background-color: #0d6efd; color: white; box-shadow: 0 4px 6px -1px rgba(13, 110, 253, 0.3); }
.search-dropdown { position: absolute; width: 100%; z-index: 1000; max-height: 200px; overflow-y: auto; display: none; }
@@ -138,6 +138,23 @@ if (!$loyalty_settings) {
body { overflow: visible !important; height: auto !important; }
}
.print-only { display: none; }
+
+ /* Touch-friendly enhancements */
+ .btn-touch {
+ padding-top: 0.75rem;
+ padding-bottom: 0.75rem;
+ font-weight: 700;
+ border-radius: 12px;
+ }
+ .btn-group-touch .btn {
+ padding-top: 0.75rem;
+ padding-bottom: 0.75rem;
+ font-weight: 700;
+ }
+ .input-group-touch .form-control, .input-group-touch .btn, .input-group-touch .input-group-text {
+ padding-top: 0.6rem;
+ padding-bottom: 0.6rem;
+ }
@@ -157,8 +174,6 @@ if (!$loyalty_settings) {
1): ?>
@@ -267,25 +282,38 @@ if (!$loyalty_settings) {
-
+
>
-
+
>
-
+
>
-
+
-
+
+
+
+
+
Loyalty Points
+
+ 0 pts
+
+
+
+
+
+
@@ -305,10 +333,10 @@ if (!$loyalty_settings) {
= format_currency(0) ?>
-
+
-
-
+
+
@@ -374,6 +402,22 @@ if (!$loyalty_settings) {
+
+
+
@@ -391,7 +435,7 @@ if (!$loyalty_settings) {
const translations = {
'en': {
'cart_empty': 'No Items in Cart',
- 'remove': 'Remove',
+ 'remove': '',
'order_placed': 'Order Placed!',
'order_success': 'Order saved successfully',
'error': 'Error',
diff --git a/qorder.php b/qorder.php
index e37500b..c5afe1e 100644
--- a/qorder.php
+++ b/qorder.php
@@ -60,7 +60,7 @@ foreach ($variants_raw as $v) {
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; }
+ .category-item { display: inline-block; padding: 8px 16px; border-radius: 20px; background: #f1f3f5; margin-right: 8px; font-weight: 500; font-size: 1.1rem; cursor: pointer; border: 1px solid transparent; }
.lang-ar .category-item { margin-right: 0; margin-left: 8px; }
.category-item.active { background: #0d6efd; color: #fff; }