undefined / index.html
agentpx's picture
I need a sigin with google using firebase here as well as signup with email or link for this
c94949a verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Self-Service Ordering</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
.category-btn.active {
background-color: #3b82f6;
color: white;
}
.item-btn:hover {
transform: scale(1.02);
}
.cart-item:hover {
background-color: #f3f4f6;
}
.num-pad-btn:active {
transform: scale(0.95);
}
@media (max-width: 640px) {
.category-scroll {
overflow-x: auto;
white-space: nowrap;
padding-bottom: 8px;
}
.category-scroll::-webkit-scrollbar {
height: 4px;
}
}
</style>
</head>
<body class="bg-gray-100 font-sans">
<div class="flex flex-col h-screen max-w-md mx-auto bg-white shadow-lg">
<!-- Header - Simplified for customers -->
<header class="bg-blue-600 text-white p-4 shadow-md">
<div class="flex justify-between items-center">
<h1 class="text-xl font-bold">Self-Service Ordering</h1>
<div class="flex items-center space-x-2">
<span class="text-sm">Table #<span id="table-number">5</span></span>
</div>
</div>
</header>
<!-- Main Content - Single column for mobile -->
<div class="flex-1 overflow-hidden flex flex-col">
<!-- Category Navigation -->
<div class="p-2 bg-gray-200 category-scroll">
<div class="inline-flex space-x-2">
<button class="category-btn active px-3 py-2 rounded-lg bg-blue-500 text-white text-sm" data-category="all">
All
</button>
<button class="category-btn px-3 py-2 rounded-lg bg-white hover:bg-gray-300 text-sm" data-category="food">
Food
</button>
<button class="category-btn px-3 py-2 rounded-lg bg-white hover:bg-gray-300 text-sm" data-category="drinks">
Drinks
</button>
<button class="category-btn px-3 py-2 rounded-lg bg-white hover:bg-gray-300 text-sm" data-category="snacks">
Snacks
</button>
<button class="category-btn px-3 py-2 rounded-lg bg-white hover:bg-gray-300 text-sm" data-category="alcohol">
Beverages
</button>
</div>
</div>
<!-- Product Grid - Adjusted for mobile -->
<div class="flex-1 p-2 overflow-y-auto grid grid-cols-2 gap-2" id="product-grid">
<!-- Product buttons will be generated here -->
</div>
<!-- Order Summary Bar - Sticky at bottom -->
<div class="sticky bottom-0 bg-white border-t border-gray-300">
<div class="flex justify-between items-center p-2">
<div class="text-sm">
<span id="cart-count">0</span> item(s) | ₱<span id="cart-total">0.00</span>
</div>
<button class="bg-green-500 hover:bg-green-600 text-white px-4 py-2 rounded-lg text-sm" id="view-cart">
<i class="fas fa-shopping-cart mr-1"></i> View Cart
</button>
</div>
</div>
</div>
<!-- Cart Modal -->
<div class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden" id="cart-modal">
<div class="bg-white rounded-t-lg w-full max-w-md absolute bottom-0 max-h-[80vh] flex flex-col">
<div class="p-4 border-b border-gray-300 flex justify-between items-center sticky top-0 bg-white">
<h2 class="text-lg font-bold">Your Order</h2>
<button class="text-gray-500" id="close-cart">
<i class="fas fa-times"></i>
</button>
</div>
<div class="flex-1 overflow-y-auto p-4" id="cart-items">
<!-- Cart items will be displayed here -->
<div class="text-center text-gray-500 py-10" id="empty-cart-message">
<i class="fas fa-shopping-cart text-4xl mb-2"></i>
<p>Your cart is empty</p>
<p class="text-sm">Select items to add to your order</p>
</div>
</div>
<div class="p-4 bg-white border-t border-gray-300">
<div class="flex justify-between mb-1 text-sm">
<span>Subtotal:</span>
<span id="subtotal">₱0.00</span>
</div>
<div class="flex justify-between mb-1 text-sm">
<span>Tax (10%):</span>
<span id="tax">₱0.00</span>
</div>
<div class="flex justify-between font-bold mt-2">
<span>TOTAL:</span>
<span id="total">₱0.00</span>
</div>
<div class="grid grid-cols-2 gap-2 mt-4">
<button class="bg-gray-200 hover:bg-gray-300 py-2 rounded-lg text-sm" id="keep-shopping">
Keep Shopping
</button>
<button class="bg-blue-500 hover:bg-blue-600 text-white py-2 rounded-lg text-sm" id="proceed-payment">
Checkout
</button>
</div>
</div>
</div>
</div>
<!-- Table Selection Modal -->
<div class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden" id="table-modal">
<div class="bg-white rounded-lg p-6 w-5/6 max-w-sm">
<h2 class="text-lg font-bold mb-4">Select Your Table</h2>
<div class="grid grid-cols-4 gap-2">
<button class="table-btn bg-gray-200 hover:bg-gray-300 py-3 rounded" data-table="1">1</button>
<button class="table-btn bg-gray-200 hover:bg-gray-300 py-3 rounded" data-table="2">2</button>
<button class="table-btn bg-gray-200 hover:bg-gray-300 py-3 rounded" data-table="3">3</button>
<button class="table-btn bg-gray-200 hover:bg-gray-300 py-3 rounded" data-table="4">4</button>
<button class="table-btn bg-gray-200 hover:bg-gray-300 py-3 rounded" data-table="5">5</button>
<button class="table-btn bg-gray-200 hover:bg-gray-300 py-3 rounded" data-table="6">6</button>
<button class="table-btn bg-gray-200 hover:bg-gray-300 py-3 rounded" data-table="7">7</button>
<button class="table-btn bg-gray-200 hover:bg-gray-300 py-3 rounded" data-table="8">8</button>
<button class="table-btn bg-gray-200 hover:bg-gray-300 py-3 rounded" data-table="9">9</button>
<button class="table-btn bg-gray-200 hover:bg-gray-300 py-3 rounded" data-table="10">10</button>
<button class="table-btn bg-gray-200 hover:bg-gray-300 py-3 rounded" data-table="11">11</button>
<button class="table-btn bg-gray-200 hover:bg-gray-300 py-3 rounded" data-table="12">12</button>
</div>
<div class="mt-4 flex justify-center">
<button class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg text-sm" id="confirm-table">
Confirm
</button>
</div>
</div>
</div>
<!-- Payment Modal -->
<div class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden" id="payment-modal">
<div class="bg-white rounded-lg p-6 w-5/6 max-w-sm">
<h2 class="text-lg font-bold mb-4">Payment</h2>
<div class="mb-4">
<div class="flex justify-between mb-1">
<span>Total:</span>
<span id="payment-total">₱0.00</span>
</div>
<div class="mb-3">
<label class="block text-gray-700 mb-1 text-sm">Payment Method</label>
<select class="w-full p-2 border rounded text-sm" id="payment-method">
<option value="cash">Cash</option>
<option value="card">Credit/Debit Card</option>
<option value="mobile">Mobile Payment</option>
</select>
</div>
<div class="mb-3" id="cash-payment">
<label class="block text-gray-700 mb-1 text-sm">Amount Received</label>
<input type="number" class="w-full p-2 border rounded text-sm" id="amount-received">
<div class="grid grid-cols-3 gap-2 mt-2" id="payment-keypad">
<button class="num-pad-btn bg-gray-200 hover:bg-gray-300 py-2 rounded">1</button>
<button class="num-pad-btn bg-gray-200 hover:bg-gray-300 py-2 rounded">2</button>
<button class="num-pad-btn bg-gray-200 hover:bg-gray-300 py-2 rounded">3</button>
<button class="num-pad-btn bg-gray-200 hover:bg-gray-300 py-2 rounded">4</button>
<button class="num-pad-btn bg-gray-200 hover:bg-gray-300 py-2 rounded">5</button>
<button class="num-pad-btn bg-gray-200 hover:bg-gray-300 py-2 rounded">6</button>
<button class="num-pad-btn bg-gray-200 hover:bg-gray-300 py-2 rounded">7</button>
<button class="num-pad-btn bg-gray-200 hover:bg-gray-300 py-2 rounded">8</button>
<button class="num-pad-btn bg-gray-200 hover:bg-gray-300 py-2 rounded">9</button>
<button class="num-pad-btn bg-gray-200 hover:bg-gray-300 py-2 rounded">.</button>
<button class="num-pad-btn bg-gray-200 hover:bg-gray-300 py-2 rounded">0</button>
<button class="num-pad-btn bg-gray-200 hover:bg-gray-300 py-2 rounded">
<i class="fas fa-backspace"></i>
</button>
</div>
</div>
<div class="hidden" id="change-display">
<div class="flex justify-between">
<span>Change:</span>
<span id="change-amount">₱0.00</span>
</div>
</div>
</div>
<div class="flex space-x-2">
<button class="flex-1 bg-gray-500 hover:bg-gray-600 text-white py-2 rounded-lg text-sm" id="cancel-payment">
Cancel
</button>
<button class="flex-1 bg-green-500 hover:bg-green-600 text-white py-2 rounded-lg text-sm" id="complete-payment">
Pay Now
</button>
</div>
</div>
</div>
<!-- Order Confirmation Modal -->
<div class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden" id="confirmation-modal">
<div class="bg-white rounded-lg p-6 w-5/6 max-w-sm text-center">
<div class="text-green-500 text-5xl mb-4">
<i class="fas fa-check-circle"></i>
</div>
<h2 class="text-xl font-bold mb-2">Order Placed Successfully!</h2>
<p class="text-gray-600 mb-4">Your order #<span id="order-number">123</span> has been received.</p>
<p class="text-sm text-gray-500 mb-4">Estimated preparation time: 15-20 minutes</p>
<button class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg w-full" id="new-order">
Start New Order
</button>
</div>
</div>
</div>
<script>
// Sample data
const products = [
{ id: 1, name: "Cheeseburger", price: 5.99, category: "food" },
{ id: 2, name: "Pepperoni Pizza", price: 8.99, category: "food" },
{ id: 3, name: "French Fries", price: 2.99, category: "food" },
{ id: 4, name: "Soda", price: 1.50, category: "drinks" },
{ id: 5, name: "Bottled Water", price: 1.00, category: "drinks" },
{ id: 6, name: "Orange Juice", price: 2.50, category: "drinks" },
{ id: 7, name: "Potato Chips", price: 1.25, category: "snacks" },
{ id: 8, name: "Chocolate Bar", price: 1.00, category: "snacks" },
{ id: 9, name: "Craft Beer", price: 3.50, category: "alcohol" },
{ id: 10, name: "House Wine", price: 5.00, category: "alcohol" },
{ id: 11, name: "Garden Salad", price: 4.50, category: "food" },
{ id: 12, name: "Coffee", price: 2.00, category: "drinks" }
];
// Current cart state
let cart = [];
let currentTable = 5;
let orderNumber = Math.floor(Math.random() * 9000) + 1000;
// DOM elements
const productGrid = document.getElementById('product-grid');
const cartItemsContainer = document.getElementById('cart-items');
const emptyCartMessage = document.getElementById('empty-cart-message');
const subtotalElement = document.getElementById('subtotal');
const taxElement = document.getElementById('tax');
const totalElement = document.getElementById('total');
const cartTotalElement = document.getElementById('cart-total');
const cartCountElement = document.getElementById('cart-count');
const categoryButtons = document.querySelectorAll('.category-btn');
const tableNumberElement = document.getElementById('table-number');
// Initialize the app
function init() {
renderProducts('all');
updateTableNumber();
// Show table selection modal on first load
document.getElementById('table-modal').classList.remove('hidden');
}
// Render products based on category
function renderProducts(category) {
productGrid.innerHTML = '';
const filteredProducts = category === 'all'
? products
: products.filter(product => product.category === category);
filteredProducts.forEach(product => {
const productBtn = document.createElement('div');
productBtn.className = 'item-btn bg-white p-3 rounded-lg shadow-sm border border-gray-200 flex flex-col items-center';
productBtn.dataset.id = product.id;
productBtn.innerHTML = `
<div class="w-12 h-12 bg-blue-100 rounded-full flex items-center justify-center mb-2 overflow-hidden">
${product.image ? `<img src="${product.image}" class="w-full h-full object-cover">` : `
<i class="fas ${getProductIcon(product.category)} text-blue-500"></i>`}
</div>
<span class="font-semibold text-sm text-center">${product.name}</span>
<span class="text-blue-600 text-sm">₱${product.price.toFixed(2)}</span>
`;
productBtn.addEventListener('click', () => addToCart(product.id));
productGrid.appendChild(productBtn);
});
}
// Helper function to get appropriate icon for product category
function getProductIcon(category) {
switch(category) {
case 'food': return 'fa-utensils';
case 'drinks': return 'fa-glass-whiskey';
case 'snacks': return 'fa-cookie';
case 'alcohol': return 'fa-wine-glass-alt';
default: return 'fa-shopping-bag';
}
}
// Add item to cart
function addToCart(productId) {
const product = products.find(p => p.id === productId);
const existingItem = cart.find(item => item.id === productId);
if (existingItem) {
existingItem.quantity++;
} else {
cart.push({
id: product.id,
name: product.name,
price: product.price,
quantity: 1
});
}
updateCartDisplay();
showAddedToCartFeedback(product.name);
}
// Show brief feedback when item is added to cart
function showAddedToCartFeedback(productName) {
const feedback = document.createElement('div');
feedback.className = 'fixed bottom-20 left-1/2 transform -translate-x-1/2 bg-green-500 text-white px-4 py-2 rounded-lg shadow-lg z-50 animate-fade';
feedback.innerHTML = `Added ${productName} to cart`;
document.body.appendChild(feedback);
setTimeout(() => {
feedback.classList.add('opacity-0', 'transition-opacity', 'duration-300');
setTimeout(() => feedback.remove(), 300);
}, 1500);
}
// Update cart display in the bottom bar
function updateCartMiniDisplay() {
const itemCount = cart.reduce((sum, item) => sum + item.quantity, 0);
const total = cart.reduce((sum, item) => sum + (item.price * item.quantity), 0);
cartCountElement.textContent = itemCount;
cartTotalElement.textContent = total.toFixed(2);
}
// Render cart items in the cart modal
function renderCart() {
if (cart.length === 0) {
emptyCartMessage.classList.remove('hidden');
cartItemsContainer.innerHTML = '';
return;
}
emptyCartMessage.classList.add('hidden');
cartItemsContainer.innerHTML = '';
cart.forEach(item => {
const cartItem = document.createElement('div');
cartItem.className = 'cart-item flex justify-between items-center p-3 mb-2 bg-white rounded-lg shadow-sm';
cartItem.innerHTML = `
<div class="flex-1">
<div class="font-semibold text-sm">${item.name}</div>
<div class="text-xs text-gray-500">₱${item.price.toFixed(2)} each</div>
</div>
<div class="flex items-center">
<button class="qty-btn minus w-6 h-6 rounded-full bg-gray-200 flex items-center justify-center text-xs" data-id="${item.id}">
<i class="fas fa-minus"></i>
</button>
<span class="mx-2 w-6 text-center text-sm">${item.quantity}</span>
<button class="qty-btn plus w-6 h-6 rounded-full bg-gray-200 flex items-center justify-center text-xs" data-id="${item.id}">
<i class="fas fa-plus"></i>
</button>
<div class="ml-3 w-16 text-right text-sm font-semibold">₱${(item.price * item.quantity).toFixed(2)}</div>
<button class="delete-btn ml-2 w-6 h-6 rounded-full bg-red-100 text-red-600 flex items-center justify-center text-xs" data-id="${item.id}">
<i class="fas fa-times"></i>
</button>
</div>
`;
cartItemsContainer.appendChild(cartItem);
});
updateCartTotals();
}
// Update cart totals
function updateCartTotals() {
const subtotal = cart.reduce((sum, item) => sum + (item.price * item.quantity), 0);
const tax = subtotal * 0.10;
const total = subtotal + tax;
subtotalElement.textContent = `₱${subtotal.toFixed(2)}`;
taxElement.textContent = `₱${tax.toFixed(2)}`;
totalElement.textContent = `₱${total.toFixed(2)}`;
}
// Update entire cart display (both mini and modal)
function updateCartDisplay() {
updateCartMiniDisplay();
renderCart();
updateCartTotals();
}
// Update table number display
function updateTableNumber() {
tableNumberElement.textContent = currentTable;
}
// Event listeners
categoryButtons.forEach(btn => {
btn.addEventListener('click', function() {
categoryButtons.forEach(b => b.classList.remove('active', 'bg-blue-500', 'text-white'));
this.classList.add('active', 'bg-blue-500', 'text-white');
renderProducts(this.getAttribute('data-category'));
});
});
// View cart button
document.getElementById('view-cart').addEventListener('click', function() {
document.getElementById('cart-modal').classList.remove('hidden');
});
// Close cart modal
document.getElementById('close-cart').addEventListener('click', function() {
document.getElementById('cart-modal').classList.add('hidden');
});
// Keep shopping button
document.getElementById('keep-shopping').addEventListener('click', function() {
document.getElementById('cart-modal').classList.add('hidden');
});
// Proceed to payment button
document.getElementById('proceed-payment').addEventListener('click', function() {
if (cart.length === 0) return;
document.getElementById('payment-total').textContent = totalElement.textContent;
document.getElementById('cart-modal').classList.add('hidden');
document.getElementById('payment-modal').classList.remove('hidden');
});
// Cancel payment button
document.getElementById('cancel-payment').addEventListener('click', function() {
document.getElementById('payment-modal').classList.add('hidden');
});
// Complete payment button
document.getElementById('complete-payment').addEventListener('click', function() {
const paymentMethod = document.getElementById('payment-method').value;
const amountReceived = parseFloat(document.getElementById('amount-received').value) || 0;
const total = parseFloat(totalElement.textContent.substring(1));
// Validate cash payment
if (paymentMethod === 'cash' && amountReceived < total) {
alert('Amount received is less than total amount');
return;
}
// Process the payment
processPayment();
});
// Process the payment and show confirmation
function processPayment() {
// In a real app, this would send the order to the kitchen/bar system
document.getElementById('payment-modal').classList.add('hidden');
document.getElementById('order-number').textContent = orderNumber++;
document.getElementById('confirmation-modal').classList.remove('hidden');
// Reset for new order
cart = [];
updateCartDisplay();
}
// Start new order button
document.getElementById('new-order').addEventListener('click', function() {
document.getElementById('confirmation-modal').classList.add('hidden');
document.getElementById('table-modal').classList.remove('hidden');
});
// Table selection
document.querySelectorAll('.table-btn').forEach(btn => {
btn.addEventListener('click', function() {
// Highlight selected table
document.querySelectorAll('.table-btn').forEach(b =>
b.classList.remove('bg-blue-500', 'text-white'));
this.classList.add('bg-blue-500', 'text-white');
currentTable = parseInt(this.dataset.table);
});
});
// Confirm table selection
document.getElementById('confirm-table').addEventListener('click', function() {
document.getElementById('table-modal').classList.add('hidden');
updateTableNumber();
});
// Handle quantity changes in cart
document.addEventListener('click', function(e) {
if (e.target.closest('.qty-btn')) {
const btn = e.target.closest('.qty-btn');
const itemId = parseInt(btn.getAttribute('data-id'));
const item = cart.find(i => i.id === itemId);
if (btn.classList.contains('minus')) {
if (item.quantity > 1) {
item.quantity--;
} else {
cart = cart.filter(i => i.id !== itemId);
}
} else if (btn.classList.contains('plus')) {
item.quantity++;
}
updateCartDisplay();
}
if (e.target.closest('.delete-btn')) {
const itemId = parseInt(e.target.closest('.delete-btn').getAttribute('data-id'));
cart = cart.filter(i => i.id !== itemId);
updateCartDisplay();
}
});
// Payment keypad functionality
document.querySelectorAll('#payment-keypad .num-pad-btn').forEach(btn => {
btn.addEventListener('click', function() {
const input = document.getElementById('amount-received');
let currentValue = input.value || '';
if (this.textContent.trim() === '<i class="fas fa-backspace"></i>') {
input.value = currentValue.slice(0, -1);
} else if (this.textContent.trim() === '.' && currentValue.includes('.')) {
return;
} else {
input.value = currentValue + this.textContent.trim();
}
// Calculate change if cash payment
const amountReceived = parseFloat(input.value) || 0;
const total = parseFloat(totalElement.textContent.substring(1));
if (amountReceived >= total) {
const change = amountReceived - total;
document.getElementById('change-amount').textContent = `₱${change.toFixed(2)}`;
document.getElementById('change-display').classList.remove('hidden');
} else {
document.getElementById('change-display').classList.add('hidden');
}
});
});
// Payment method change handler
document.getElementById('payment-method').addEventListener('change', function() {
if (this.value === 'cash') {
document.getElementById('cash-payment').classList.remove('hidden');
} else {
document.getElementById('cash-payment').classList.add('hidden');
document.getElementById('change-display').classList.add('hidden');
}
});
// Initialize the app when the page loads
window.addEventListener('DOMContentLoaded', init);
</script>
</body>
</html>