webprojects / index.html
GilbertKambu's picture
Add 3 files
913401f verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ghost Burger - Fast Food Ordering System</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>
.menu-item:hover {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0,0,0,0.1);
}
.receipt {
background: repeating-linear-gradient(
to bottom,
white,
white 24px,
#f0f0f0 24px,
#f0f0f0 25px
);
}
@media print {
.no-print {
display: none !important;
}
}
</style>
</head>
<body class="bg-gray-100 font-sans">
<!-- Login Page -->
<div id="login-page" class="min-h-screen flex items-center justify-center bg-gray-900">
<div class="bg-white p-8 rounded-lg shadow-xl w-full max-w-md">
<div class="text-center mb-8">
<img src="https://via.placeholder.com/100x100?text=🍔" alt="Ghost Burger Logo" class="mx-auto h-20 w-20">
<h1 class="text-3xl font-bold text-gray-800 mt-4">Ghost Burger</h1>
<p class="text-gray-600">Fast Food Ordering System</p>
</div>
<form id="login-form" class="space-y-6">
<div>
<label for="username" class="block text-sm font-medium text-gray-700">Username</label>
<input type="text" id="username" name="username" required
class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500">
</div>
<div>
<label for="password" class="block text-sm font-medium text-gray-700">Password</label>
<input type="password" id="password" name="password" required
class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500">
</div>
<div>
<button type="submit"
class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
Sign in
</button>
</div>
</form>
</div>
</div>
<!-- Main App Container (hidden initially) -->
<div id="app-container" class="hidden min-h-screen">
<!-- Header/Navigation -->
<header class="bg-gray-900 text-white shadow-lg">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between h-16 items-center">
<div class="flex items-center">
<img src="https://via.placeholder.com/40x40?text=GB" alt="Logo" class="h-8 w-8">
<span class="ml-2 text-xl font-bold">Ghost Burger</span>
</div>
<nav class="hidden md:flex space-x-8">
<a href="#" class="nav-link active" data-page="billing">Billing</a>
<a href="#" class="nav-link" data-page="admin-dashboard">Admin Dashboard</a>
<a href="#" class="nav-link" data-page="reports">Reports</a>
</nav>
<div class="flex items-center">
<span id="current-user" class="mr-4"></span>
<button id="logout-btn" class="bg-red-600 hover:bg-red-700 px-4 py-2 rounded-md text-sm font-medium">
Logout
</button>
</div>
</div>
</div>
</header>
<!-- Main Content Area -->
<main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
<!-- Billing Page -->
<div id="billing-page" class="page-content">
<div class="flex flex-col md:flex-row gap-6">
<!-- Menu Items -->
<div class="w-full md:w-2/3">
<h2 class="text-2xl font-bold mb-6">Menu Items</h2>
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
<!-- Menu items will be populated here by JavaScript -->
</div>
</div>
<!-- Order Summary -->
<div class="w-full md:w-1/3 bg-white p-6 rounded-lg shadow-md">
<h2 class="text-2xl font-bold mb-6">Order Summary</h2>
<div id="order-items" class="mb-6 space-y-3">
<!-- Order items will be populated here -->
<div class="text-gray-500 italic">No items added yet</div>
</div>
<div class="border-t border-gray-200 pt-4 mb-6">
<div class="flex justify-between font-semibold text-lg">
<span>Total:</span>
<span id="order-total">KSh 0.00</span>
</div>
</div>
<div class="mb-6">
<label class="block text-sm font-medium text-gray-700 mb-2">Payment Method</label>
<div class="flex space-x-4">
<label class="inline-flex items-center">
<input type="radio" name="payment-method" value="cash" checked
class="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300">
<span class="ml-2">Cash</span>
</label>
<label class="inline-flex items-center">
<input type="radio" name="payment-method" value="mpesa"
class="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300">
<span class="ml-2">MPesa</span>
</label>
</div>
</div>
<div id="mpesa-section" class="hidden mb-6">
<label for="phone-number" class="block text-sm font-medium text-gray-700">Phone Number</label>
<input type="tel" id="phone-number"
class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500">
<button id="process-mpesa" class="mt-2 w-full bg-green-600 hover:bg-green-700 text-white py-2 px-4 rounded-md">
Process MPesa Payment
</button>
</div>
<div class="flex space-x-4">
<button id="print-receipt" class="flex-1 bg-blue-600 hover:bg-blue-700 text-white py-2 px-4 rounded-md">
<i class="fas fa-print mr-2"></i> Print Receipt
</button>
<button id="email-receipt" class="flex-1 bg-purple-600 hover:bg-purple-700 text-white py-2 px-4 rounded-md">
<i class="fas fa-envelope mr-2"></i> Email Receipt
</button>
</div>
</div>
</div>
</div>
<!-- Admin Dashboard -->
<div id="admin-dashboard" class="page-content hidden">
<h1 class="text-3xl font-bold mb-8">Admin Dashboard</h1>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
<div class="bg-white p-6 rounded-lg shadow-md">
<h3 class="text-lg font-medium text-gray-900 mb-2">Total Sales</h3>
<p class="text-3xl font-bold text-indigo-600">KSh 24,850</p>
<p class="text-sm text-gray-500 mt-1">Today</p>
</div>
<div class="bg-white p-6 rounded-lg shadow-md">
<h3 class="text-lg font-medium text-gray-900 mb-2">Orders</h3>
<p class="text-3xl font-bold text-green-600">42</p>
<p class="text-sm text-gray-500 mt-1">Today</p>
</div>
<div class="bg-white p-6 rounded-lg shadow-md">
<h3 class="text-lg font-medium text-gray-900 mb-2">Top Item</h3>
<p class="text-3xl font-bold text-yellow-600">Ghost Burger</p>
<p class="text-sm text-gray-500 mt-1">15 sold today</p>
</div>
</div>
<div class="bg-white p-6 rounded-lg shadow-md mb-8">
<div class="flex justify-between items-center mb-6">
<h2 class="text-xl font-bold">User Management</h2>
<button id="add-user-btn" class="bg-indigo-600 hover:bg-indigo-700 text-white py-2 px-4 rounded-md">
<i class="fas fa-plus mr-2"></i> Add User
</button>
</div>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Name</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Email</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Role</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
<tr>
<td class="px-6 py-4 whitespace-nowrap">Admin User</td>
<td class="px-6 py-4 whitespace-nowrap">admin@ghostburger.com</td>
<td class="px-6 py-4 whitespace-nowrap"><span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-purple-100 text-purple-800">Admin</span></td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
<button class="text-indigo-600 hover:text-indigo-900 mr-3">Edit</button>
<button class="text-red-600 hover:text-red-900">Delete</button>
</td>
</tr>
<tr>
<td class="px-6 py-4 whitespace-nowrap">Staff User</td>
<td class="px-6 py-4 whitespace-nowrap">staff@ghostburger.com</td>
<td class="px-6 py-4 whitespace-nowrap"><span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800">Staff</span></td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
<button class="text-indigo-600 hover:text-indigo-900 mr-3">Edit</button>
<button class="text-red-600 hover:text-red-900">Delete</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div class="bg-white p-6 rounded-lg shadow-md">
<div class="flex justify-between items-center mb-6">
<h2 class="text-xl font-bold">Add Menu Item</h2>
</div>
<form id="add-item-form" class="space-y-4">
<div>
<label for="item-name" class="block text-sm font-medium text-gray-700">Item Name</label>
<input type="text" id="item-name" name="item-name" required
class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500">
</div>
<div>
<label for="item-price" class="block text-sm font-medium text-gray-700">Price</label>
<input type="number" id="item-price" name="item-price" required
class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500">
</div>
<div>
<label for="item-category" class="block text-sm font-medium text-gray-700">Category</label>
<select id="item-category" name="item-category" required
class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500">
<option value="">Select a category</option>
<option value="burgers">Burgers</option>
<option value="fries">Fries</option>
<option value="drinks">Drinks</option>
<option value="desserts">Desserts</option>
</select>
</div>
<div>
<label for="item-image" class="block text-sm font-medium text-gray-700">Image</label>
<input type="file" id="item-image" name="item-image" accept="image/*"
class="mt-1 block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-md file:border-0 file:text-sm file:font-semibold file:bg-indigo-50 file:text-indigo-700 hover:file:bg-indigo-100">
</div>
<div>
<button type="submit"
class="w-full bg-indigo-600 hover:bg-indigo-700 text-white py-2 px-4 rounded-md">
Add Item
</button>
</div>
</form>
</div>
<div class="bg-white p-6 rounded-lg shadow-md">
<div class="flex justify-between items-center mb-6">
<h2 class="text-xl font-bold">Delete Menu Items</h2>
</div>
<div class="space-y-4">
<div class="flex items-center justify-between p-3 border border-gray-200 rounded-md">
<div class="flex items-center">
<img src="https://via.placeholder.com/50x50?text=🍔" alt="Ghost Burger" class="h-10 w-10 rounded-full">
<div class="ml-3">
<p class="font-medium">Ghost Burger</p>
<p class="text-sm text-gray-500">KSh 450</p>
</div>
</div>
<button class="text-red-600 hover:text-red-900">
<i class="fas fa-trash"></i>
</button>
</div>
<div class="flex items-center justify-between p-3 border border-gray-200 rounded-md">
<div class="flex items-center">
<img src="https://via.placeholder.com/50x50?text=🍟" alt="Fries" class="h-10 w-10 rounded-full">
<div class="ml-3">
<p class="font-medium">French Fries</p>
<p class="text-sm text-gray-500">KSh 200</p>
</div>
</div>
<button class="text-red-600 hover:text-red-900">
<i class="fas fa-trash"></i>
</button>
</div>
<div class="flex items-center justify-between p-3 border border-gray-200 rounded-md">
<div class="flex items-center">
<img src="https://via.placeholder.com/50x50?text=🥤" alt="Soda" class="h-10 w-10 rounded-full">
<div class="ml-3">
<p class="font-medium">Soda</p>
<p class="text-sm text-gray-500">KSh 150</p>
</div>
</div>
<button class="text-red-600 hover:text-red-900">
<i class="fas fa-trash"></i>
</button>
</div>
</div>
</div>
</div>
</div>
<!-- Reports Page -->
<div id="reports-page" class="page-content hidden">
<h1 class="text-3xl font-bold mb-8">Reports</h1>
<div class="bg-white p-6 rounded-lg shadow-md mb-8">
<div class="flex flex-col md:flex-row justify-between items-start md:items-center mb-6">
<h2 class="text-xl font-bold mb-4 md:mb-0">Sales Report</h2>
<div class="flex space-x-4">
<div>
<label for="report-period" class="block text-sm font-medium text-gray-700">Period</label>
<select id="report-period"
class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500">
<option value="today">Today</option>
<option value="week">This Week</option>
<option value="month">This Month</option>
<option value="custom">Custom</option>
</select>
</div>
<div id="custom-date-range" class="hidden">
<label for="start-date" class="block text-sm font-medium text-gray-700">Date Range</label>
<div class="flex space-x-2">
<input type="date" id="start-date"
class="mt-1 block px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500">
<input type="date" id="end-date"
class="mt-1 block px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500">
</div>
</div>
<div class="flex items-end">
<button id="generate-report" class="bg-indigo-600 hover:bg-indigo-700 text-white py-2 px-4 rounded-md">
Generate
</button>
</div>
</div>
</div>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Date</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Order ID</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Items</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Payment</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Amount</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
<tr>
<td class="px-6 py-4 whitespace-nowrap">2023-06-15</td>
<td class="px-6 py-4 whitespace-nowrap">#GB-00123</td>
<td class="px-6 py-4">Ghost Burger, Fries, Soda</td>
<td class="px-6 py-4 whitespace-nowrap"><span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800">MPesa</span></td>
<td class="px-6 py-4 whitespace-nowrap">KSh 800</td>
</tr>
<tr>
<td class="px-6 py-4 whitespace-nowrap">2023-06-15</td>
<td class="px-6 py-4 whitespace-nowrap">#GB-00122</td>
<td class="px-6 py-4">Double Ghost Burger, Large Fries</td>
<td class="px-6 py-4 whitespace-nowrap"><span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-blue-100 text-blue-800">Cash</span></td>
<td class="px-6 py-4 whitespace-nowrap">KSh 900</td>
</tr>
</tbody>
</table>
</div>
<div class="mt-6 flex justify-between items-center">
<div class="text-sm text-gray-500">
Showing <span class="font-medium">1</span> to <span class="font-medium">10</span> of <span class="font-medium">42</span> results
</div>
<div class="flex space-x-2">
<button class="px-3 py-1 border border-gray-300 rounded-md text-sm font-medium text-gray-700 bg-white hover:bg-gray-50">
Previous
</button>
<button class="px-3 py-1 border border-gray-300 rounded-md text-sm font-medium text-gray-700 bg-white hover:bg-gray-50">
Next
</button>
</div>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div class="bg-white p-6 rounded-lg shadow-md">
<h2 class="text-xl font-bold mb-6">Top Selling Items</h2>
<div class="space-y-4">
<div>
<div class="flex justify-between mb-1">
<span class="text-sm font-medium text-gray-700">Ghost Burger</span>
<span class="text-sm font-medium text-gray-700">42</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2.5">
<div class="bg-indigo-600 h-2.5 rounded-full" style="width: 75%"></div>
</div>
</div>
<div>
<div class="flex justify-between mb-1">
<span class="text-sm font-medium text-gray-700">French Fries</span>
<span class="text-sm font-medium text-gray-700">35</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2.5">
<div class="bg-green-600 h-2.5 rounded-full" style="width: 62%"></div>
</div>
</div>
<div>
<div class="flex justify-between mb-1">
<span class="text-sm font-medium text-gray-700">Soda</span>
<span class="text-sm font-medium text-gray-700">28</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2.5">
<div class="bg-yellow-500 h-2.5 rounded-full" style="width: 50%"></div>
</div>
</div>
</div>
</div>
<div class="bg-white p-6 rounded-lg shadow-md">
<h2 class="text-xl font-bold mb-6">Payment Methods</h2>
<div class="flex justify-center">
<div class="w-64 h-64">
<canvas id="paymentChart"></canvas>
</div>
</div>
</div>
</div>
<div class="mt-6 flex justify-end">
<button id="export-pdf" class="bg-red-600 hover:bg-red-700 text-white py-2 px-4 rounded-md mr-3">
<i class="fas fa-file-pdf mr-2"></i> Export PDF
</button>
<button id="export-csv" class="bg-green-600 hover:bg-green-700 text-white py-2 px-4 rounded-md">
<i class="fas fa-file-excel mr-2"></i> Export CSV
</button>
</div>
</div>
</main>
</div>
<!-- Receipt Modal -->
<div id="receipt-modal" class="fixed inset-0 z-50 hidden overflow-y-auto">
<div class="flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
<div class="absolute inset-0 bg-gray-500 opacity-75"></div>
</div>
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span>
<div class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full">
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<div class="receipt p-6 w-full max-w-md mx-auto">
<div class="text-center mb-4">
<h2 class="text-2xl font-bold">GHOST BURGER</h2>
<p class="text-sm">123 Fast Food Lane, Nairobi</p>
<p class="text-sm">Tel: 0700 123 456</p>
</div>
<div class="border-t border-b border-gray-300 py-2 my-2">
<div class="flex justify-between">
<span>Order #GB-00123</span>
<span id="receipt-date">2023-06-15 14:30</span>
</div>
</div>
<div id="receipt-items" class="mb-4">
<!-- Receipt items will be populated here -->
</div>
<div class="border-t border-gray-300 pt-2">
<div class="flex justify-between font-semibold">
<span>Total:</span>
<span id="receipt-total">KSh 0.00</span>
</div>
<div class="mt-2 text-sm" id="receipt-payment-method">
Payment Method: Cash
</div>
<div class="mt-4 text-center text-xs">
Thank you for dining with us!
</div>
</div>
</div>
</div>
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse no-print">
<button type="button" id="print-receipt-btn"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm">
<i class="fas fa-print mr-2"></i> Print Receipt
</button>
<button type="button" id="close-receipt-modal"
class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm">
Close
</button>
</div>
</div>
</div>
</div>
<!-- Email Receipt Modal -->
<div id="email-receipt-modal" class="fixed inset-0 z-50 hidden overflow-y-auto">
<div class="flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
<div class="absolute inset-0 bg-gray-500 opacity-75"></div>
</div>
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span>
<div class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full">
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<h3 class="text-lg leading-6 font-medium text-gray-900 mb-4">Email Receipt</h3>
<div class="mb-4">
<label for="customer-email" class="block text-sm font-medium text-gray-700">Customer Email</label>
<input type="email" id="customer-email"
class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500"
placeholder="customer@example.com">
</div>
<div class="mb-4">
<label for="receipt-message" class="block text-sm font-medium text-gray-700">Message (optional)</label>
<textarea id="receipt-message" rows="3"
class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500">Thank you for dining at Ghost Burger! Here's your receipt.</textarea>
</div>
</div>
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
<button type="button" id="send-email-receipt"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-purple-600 text-base font-medium text-white hover:bg-purple-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-purple-500 sm:ml-3 sm:w-auto sm:text-sm">
<i class="fas fa-paper-plane mr-2"></i> Send Receipt
</button>
<button type="button" id="close-email-receipt-modal"
class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm">
Cancel
</button>
</div>
</div>
</div>
</div>
<!-- Add User Modal -->
<div id="add-user-modal" class="fixed inset-0 z-50 hidden overflow-y-auto">
<div class="flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
<div class="absolute inset-0 bg-gray-500 opacity-75"></div>
</div>
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span>
<div class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full">
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<h3 class="text-lg leading-6 font-medium text-gray-900 mb-4">Add New User</h3>
<form id="add-user-form" class="space-y-4">
<div>
<label for="new-user-name" class="block text-sm font-medium text-gray-700">Full Name</label>
<input type="text" id="new-user-name" name="new-user-name" required
class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500">
</div>
<div>
<label for="new-user-email" class="block text-sm font-medium text-gray-700">Email</label>
<input type="email" id="new-user-email" name="new-user-email" required
class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500">
</div>
<div>
<label for="new-user-role" class="block text-sm font-medium text-gray-700">Role</label>
<select id="new-user-role" name="new-user-role" required
class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500">
<option value="">Select a role</option>
<option value="admin">Admin</option>
<option value="staff">Staff</option>
</select>
</div>
<div>
<label for="new-user-password" class="block text-sm font-medium text-gray-700">Password</label>
<input type="password" id="new-user-password" name="new-user-password" required
class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500">
</div>
<div>
<label for="new-user-confirm-password" class="block text-sm font-medium text-gray-700">Confirm Password</label>
<input type="password" id="new-user-confirm-password" name="new-user-confirm-password" required
class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500">
</div>
</form>
</div>
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
<button type="button" id="save-new-user"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-indigo-600 text-base font-medium text-white hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:ml-3 sm:w-auto sm:text-sm">
Save User
</button>
<button type="button" id="cancel-add-user"
class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm">
Cancel
</button>
</div>
</div>
</div>
</div>
<!-- MPesa Processing Modal -->
<div id="mpesa-processing-modal" class="fixed inset-0 z-50 hidden overflow-y-auto">
<div class="flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
<div class="absolute inset-0 bg-gray-500 opacity-75"></div>
</div>
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span>
<div class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-md sm:w-full">
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<div class="text-center">
<div class="mx-auto flex items-center justify-center h-12 w-12 rounded-full bg-green-100">
<i class="fas fa-mobile-alt text-green-600"></i>
</div>
<h3 class="mt-3 text-lg leading-6 font-medium text-gray-900">MPesa Payment Processing</h3>
<div class="mt-2">
<p class="text-sm text-gray-500">Please check your phone and enter your MPesa PIN to complete the payment of <span id="mpesa-amount" class="font-bold">KSh 0.00</span>.</p>
<div id="mpesa-spinner" class="mt-4">
<div class="flex justify-center">
<div class="animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900"></div>
</div>
<p class="mt-2 text-sm text-gray-500">Waiting for payment confirmation...</p>
</div>
<div id="mpesa-success" class="hidden mt-4">
<div class="mx-auto flex items-center justify-center h-12 w-12 rounded-full bg-green-100">
<i class="fas fa-check text-green-600"></i>
</div>
<p class="mt-2 text-sm text-green-600">Payment received! Transaction ID: <span id="mpesa-transaction-id" class="font-bold">NCJ892HJK2</span></p>
</div>
<div id="mpesa-failure" class="hidden mt-4">
<div class="mx-auto flex items-center justify-center h-12 w-12 rounded-full bg-red-100">
<i class="fas fa-times text-red-600"></i>
</div>
<p class="mt-2 text-sm text-red-600">Payment failed. Please try again or use another payment method.</p>
</div>
</div>
</div>
</div>
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
<button type="button" id="mpesa-done-btn" class="hidden w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-green-600 text-base font-medium text-white hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500 sm:ml-3 sm:w-auto sm:text-sm">
Done
</button>
<button type="button" id="mpesa-retry-btn" class="hidden w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm">
Retry
</button>
<button type="button" id="mpesa-cancel-btn" class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm">
Cancel
</button>
</div>
</div>
</div>
</div>
<script>
// Sample menu data
const menuItems = [
{ id: 1, name: "Ghost Burger", price: 450, category: "burgers", image: "🍔" },
{ id: 2, name: "Double Ghost Burger", price: 650, category: "burgers", image: "🍔🍔" },
{ id: 3, name: "Cheese Ghost Burger", price: 500, category: "burgers", image: "🧀🍔" },
{ id: 4, name: "French Fries", price: 200, category: "fries", image: "🍟" },
{ id: 5, name: "Large Fries", price: 300, category: "fries", image: "🍟🍟" },
{ id: 6, name: "Cheese Fries", price: 350, category: "fries", image: "🧀🍟" },
{ id: 7, name: "Soda", price: 150, category: "drinks", image: "🥤" },
{ id: 8, name: "Milkshake", price: 250, category: "drinks", image: "🥛" },
{ id: 9, name: "Ice Cream", price: 200, category: "desserts", image: "🍦" },
{ id: 10, name: "Chocolate Cake", price: 300, category: "desserts", image: "🍫🍰" }
];
// Current order
let currentOrder = [];
let currentUser = null;
// DOM elements
const loginPage = document.getElementById('login-page');
const appContainer = document.getElementById('app-container');
const loginForm = document.getElementById('login-form');
const logoutBtn = document.getElementById('logout-btn');
const currentUserSpan = document.getElementById('current-user');
const navLinks = document.querySelectorAll('.nav-link');
const pageContents = document.querySelectorAll('.page-content');
const menuContainer = document.querySelector('#billing-page .grid');
const orderItemsContainer = document.getElementById('order-items');
const orderTotalSpan = document.getElementById('order-total');
const paymentMethodRadios = document.querySelectorAll('input[name="payment-method"]');
const mpesaSection = document.getElementById('mpesa-section');
const printReceiptBtn = document.getElementById('print-receipt');
const emailReceiptBtn = document.getElementById('email-receipt');
const receiptModal = document.getElementById('receipt-modal');
const closeReceiptModal = document.getElementById('close-receipt-modal');
const printReceiptBtnModal = document.getElementById('print-receipt-btn');
const emailReceiptModal = document.getElementById('email-receipt-modal');
const closeEmailReceiptModal = document.getElementById('close-email-receipt-modal');
const sendEmailReceiptBtn = document.getElementById('send-email-receipt');
const addUserBtn = document.getElementById('add-user-btn');
const addUserModal = document.getElementById('add-user-modal');
const cancelAddUserBtn = document.getElementById('cancel-add-user');
const saveNewUserBtn = document.getElementById('save-new-user');
const processMpesaBtn = document.getElementById('process-mpesa');
const mpesaProcessingModal = document.getElementById('mpesa-processing-modal');
const mpesaCancelBtn = document.getElementById('mpesa-cancel-btn');
const mpesaDoneBtn = document.getElementById('mpesa-done-btn');
const mpesaRetryBtn = document.getElementById('mpesa-retry-btn');
const mpesaAmountSpan = document.getElementById('mpesa-amount');
const reportPeriodSelect = document.getElementById('report-period');
const customDateRangeDiv = document.getElementById('custom-date-range');
// Initialize the app
function initApp() {
// Populate menu items
renderMenuItems();
// Set up event listeners
setupEventListeners();
}
// Render menu items
function renderMenuItems() {
menuContainer.innerHTML = '';
menuItems.forEach(item => {
const menuItem = document.createElement('div');
menuItem.className = 'bg-white p-4 rounded-lg shadow-md cursor-pointer menu-item transition duration-300';
menuItem.innerHTML = `
<div class="text-4xl text-center mb-2">${item.image}</div>
<h3 class="font-medium text-center">${item.name}</h3>
<p class="text-center text-gray-600">KSh ${item.price.toFixed(2)}</p>
`;
menuItem.addEventListener('click', () => addToOrder(item));
menuContainer.appendChild(menuItem);
});
}
// Add item to order
function addToOrder(item) {
const existingItem = currentOrder.find(orderItem => orderItem.id === item.id);
if (existingItem) {
existingItem.quantity += 1;
} else {
currentOrder.push({
id: item.id,
name: item.name,
price: item.price,
quantity: 1
});
}
renderOrderItems();
}
// Remove item from order
function removeFromOrder(itemId) {
const itemIndex = currentOrder.findIndex(item => item.id === itemId);
if (itemIndex !== -1) {
if (currentOrder[itemIndex].quantity > 1) {
currentOrder[itemIndex].quantity -= 1;
} else {
currentOrder.splice(itemIndex, 1);
}
renderOrderItems();
}
}
// Render order items
function renderOrderItems() {
if (currentOrder.length === 0) {
orderItemsContainer.innerHTML = '<div class="text-gray-500 italic">No items added yet</div>';
orderTotalSpan.textContent = 'KSh 0.00';
return;
}
let html = '';
let total = 0;
currentOrder.forEach(item => {
const itemTotal = item.price * item.quantity;
total += itemTotal;
html += `
<div class="flex justify-between items-center">
<div>
<span class="font-medium">${item.name}</span>
<div class="text-sm text-gray-500">
KSh ${item.price.toFixed(2)} × ${item.quantity}
</div>
</div>
<div class="flex items-center">
<span class="font-medium mr-3">KSh ${itemTotal.toFixed(2)}</span>
<button class="text-red-500 hover:text-red-700 remove-item" data-id="${item.id}">
<i class="fas fa-times"></i>
</button>
</div>
</div>
`;
});
orderItemsContainer.innerHTML = html;
orderTotalSpan.textContent = `KSh ${total.toFixed(2)}`;
// Add event listeners to remove buttons
document.querySelectorAll('.remove-item').forEach(button => {
button.addEventListener('click', (e) => {
e.stopPropagation();
removeFromOrder(parseInt(button.dataset.id));
});
});
}
// Render receipt
function renderReceipt(paymentMethod) {
const receiptItems = document.getElementById('receipt-items');
const receiptTotal = document.getElementById('receipt-total');
const receiptPaymentMethod = document.getElementById('receipt-payment-method');
let html = '';
let total = 0;
currentOrder.forEach(item => {
const itemTotal = item.price * item.quantity;
total += itemTotal;
html += `
<div class="flex justify-between mb-1">
<span>${item.name} × ${item.quantity}</span>
<span>KSh ${itemTotal.toFixed(2)}</span>
</div>
`;
});
receiptItems.innerHTML = html;
receiptTotal.textContent = `KSh ${total.toFixed(2)}`;
receiptPaymentMethod.textContent = `Payment Method: ${paymentMethod === 'mpesa' ? 'MPesa' : 'Cash'}`;
// Set current date and time
const now = new Date();
const dateStr = now.toISOString().split('T')[0];
const timeStr = now.toTimeString().substring(0, 5);
document.getElementById('receipt-date').textContent = `${dateStr} ${timeStr}`;
// Set MPesa transaction details if applicable
if (paymentMethod === 'mpesa') {
const transactionId = `MP${Math.floor(Math.random() * 1000000000).toString().padStart(9, '0')}`;
receiptPaymentMethod.innerHTML += `<div class="mt-1">Transaction ID: ${transactionId}</div>`;
}
}
// Setup event listeners
function setupEventListeners() {
// Login form
loginForm.addEventListener('submit', (e) => {
e.preventDefault();
const username = document.getElementById('username').value;
const password = document.getElementById('password').value;
// Simple authentication (in a real app, this would be server-side)
if (username && password) {
currentUser = {
name: username === 'admin' ? 'Admin User' : 'Staff User',
role: username === 'admin' ? 'admin' : 'staff'
};
loginPage.classList.add('hidden');
appContainer.classList.remove('hidden');
currentUserSpan.textContent = `Logged in as ${currentUser.name} (${currentUser.role})`;
// Show appropriate pages based on role
if (currentUser.role === 'staff') {
document.querySelector('[data-page="admin-dashboard"]').style.display = 'none';
document.querySelector('[data-page="reports"]').style.display = 'none';
showPage('billing');
} else {
showPage('billing');
}
}
});
// Logout button
logoutBtn.addEventListener('click', () => {
currentUser = null;
currentOrder = [];
appContainer.classList.add('hidden');
loginPage.classList.remove('hidden');
document.getElementById('username').value = '';
document.getElementById('password').value = '';
});
// Navigation links
navLinks.forEach(link => {
link.addEventListener('click', (e) => {
e.preventDefault();
showPage(link.dataset.page);
});
});
// Payment method radio buttons
paymentMethodRadios.forEach(radio => {
radio.addEventListener('change', (e) => {
if (e.target.value === 'mpesa') {
mpesaSection.classList.remove('hidden');
} else {
mpesaSection.classList.add('hidden');
}
});
});
// Print receipt button
printReceiptBtn.addEventListener('click', () => {
if (currentOrder.length === 0) {
alert('Please add items to the order first');
return;
}
const paymentMethod = document.querySelector('input[name="payment-method"]:checked').value;
renderReceipt(paymentMethod);
receiptModal.classList.remove('hidden');
});
// Email receipt button
emailReceiptBtn.addEventListener('click', () => {
if (currentOrder.length === 0) {
alert('Please add items to the order first');
return;
}
emailReceiptModal.classList.remove('hidden');
});
// Close receipt modal
closeReceiptModal.addEventListener('click', () => {
receiptModal.classList.add('hidden');
});
// Print receipt from modal
printReceiptBtnModal.addEventListener('click', () => {
window.print();
});
// Close email receipt modal
closeEmailReceiptModal.addEventListener('click', () => {
emailReceiptModal.classList.add('hidden');
});
// Send email receipt
sendEmailReceipt.addEventListener('click', () => {
const email = document.getElementById('customer-email').value;
if (!email) {
alert('Please enter customer email');
return;
}
alert(`Receipt sent to ${email}`);
emailReceiptModal.classList.add('hidden');
currentOrder = [];
renderOrderItems();
});
// Add user button
addUserBtn.addEventListener('click', () => {
addUserModal.classList.remove('hidden');
});
// Cancel add user
cancelAddUserBtn.addEventListener('click', () => {
addUserModal.classList.add('hidden');
});
// Save new user
saveNewUserBtn.addEventListener('click', () => {
const name = document.getElementById('new-user-name').value;
const email = document.getElementById('new-user-email').value;
const role = document.getElementById('new-user-role').value;
const password = document.getElementById('new-user-password').value;
const confirmPassword = document.getElementById('new-user-confirm-password').value;
if (!name || !email || !role || !password || !confirmPassword) {
alert('Please fill in all fields');
return;
}
if (password !== confirmPassword) {
alert('Passwords do not match');
return;
}
alert(`User ${name} (${role}) added successfully`);
addUserModal.classList.add('hidden');
document.getElementById('add-user-form').reset();
});
// Process MPesa payment
processMpesaBtn.addEventListener('click', () => {
const phoneNumber = document.getElementById('phone-number').value;
if (!phoneNumber || phoneNumber.length < 9) {
alert('Please enter a valid phone number');
return;
}
if (currentOrder.length === 0) {
alert('Please add items to the order first');
return;
}
// Calculate total
let total = 0;
currentOrder.forEach(item => {
total += item.price * item.quantity;
});
mpesaAmountSpan.textContent = `KSh ${total.toFixed(2)}`;
mpesaProcessingModal.classList.remove('hidden');
// Simulate MPesa processing
const mpesaSpinner = document.getElementById('mpesa-spinner');
const mpesaSuccess = document.getElementById('mpesa-success');
const mpesaFailure = document.getElementById('mpesa-failure');
mpesaSpinner.classList.remove('hidden');
mpesaSuccess.classList.add('hidden');
mpesaFailure.classList.add('hidden');
mpesaDoneBtn.classList.add('hidden');
mpesaRetryBtn.classList.add('hidden');
setTimeout(() => {
// Randomly decide if payment succeeds (80% chance)
const success = Math.random() < 0.8;
mpesaSpinner.classList.add('hidden');
if (success) {
mpesaSuccess.classList.remove('hidden');
mpesaDoneBtn.classList.remove('hidden');
// Generate random transaction ID
const transactionId = `MP${Math.floor(Math.random() * 1000000000).toString().padStart(9, '0')}`;
document.getElementById('mpesa-transaction-id').textContent = transactionId;
} else {
mpesaFailure.classList.remove('hidden');
mpesaRetryBtn.classList.remove('hidden');
}
}, 3000);
});
// MPesa modal buttons
mpesaCancelBtn.addEventListener('click', () => {
mpesaProcessingModal.classList.add('hidden');
});
mpesaDoneBtn.addEventListener('click', () => {
mpesaProcessingModal.classList.add('hidden');
const paymentMethod = document.querySelector('input[name="payment-method"]:checked').value;
renderReceipt(paymentMethod);
receiptModal.classList.remove('hidden');
// Clear order after successful payment
currentOrder = [];
renderOrderItems();
});
mpesaRetryBtn.addEventListener('click', () => {
document.getElementById('mpesa-spinner').classList.remove('hidden');
document.getElementById('mpesa-success').classList.add('hidden');
document.getElementById('mpesa-failure').classList.add('hidden');
mpesaDoneBtn.classList.add('hidden');
mpesaRetryBtn.classList.add('hidden');
setTimeout(() => {
// Randomly decide if payment succeeds (80% chance)
const success = Math.random() < 0.8;
document.getElementById('mpesa-spinner').classList.add('hidden');
if (success) {
document.getElementById('mpesa-success').classList.remove('hidden');
mpesaDoneBtn.classList.remove('hidden');
// Generate random transaction ID
const transactionId = `MP${Math.floor(Math.random() * 1000000000).toString().padStart(9, '0')}`;
document.getElementById('mpesa-transaction-id').textContent = transactionId;
} else {
document.getElementById('mpesa-failure').classList.remove('hidden');
mpesaRetryBtn.classList.remove('hidden');
}
}, 3000);
});
// Report period selector
reportPeriodSelect.addEventListener('change', (e) => {
if (e.target.value === 'custom') {
customDateRangeDiv.classList.remove('hidden');
} else {
customDateRangeDiv.classList.add('hidden');
}
});
}
// Show page
function showPage(pageName) {
pageContents.forEach(content => {
content.classList.add('hidden');
});
navLinks.forEach(link => {
link.classList.remove('active');
});
document.getElementById(`${pageName}-page`).classList.remove('hidden');
document.querySelector(`[data-page="${pageName}"]`).classList.add('active');
}
// Initialize the app when DOM is loaded
document.addEventListener('DOMContentLoaded', initApp);
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=GilbertKambu/webprojects" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>