billing / index.html
GilbertKambu's picture
Add 3 files
b214df8 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Burger Joint Billing 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>
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap');
body {
font-family: 'Poppins', sans-serif;
background-color: #f8f9fa;
}
.menu-item:hover {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
}
.menu-item {
transition: all 0.3s ease;
}
.receipt {
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
border-left: 5px solid #f59e0b;
}
.print-area {
background-color: white;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
.tab-active {
border-bottom: 3px solid #f59e0b;
color: #f59e0b;
font-weight: 600;
}
.floating-btn {
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1), 0 1px 3px rgba(0, 0, 0, 0.08);
}
.floating-btn:hover {
transform: translateY(-2px);
box-shadow: 0 7px 14px rgba(0, 0, 0, 0.1), 0 3px 6px rgba(0, 0, 0, 0.08);
}
</style>
</head>
<body class="bg-gray-100">
<!-- Login Modal -->
<div id="loginModal" class="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 z-50">
<div class="bg-white rounded-lg p-8 w-full max-w-md">
<div class="text-center mb-6">
<img src="https://via.placeholder.com/150x50?text=Burger+Joint" alt="Burger Joint Logo" class="mx-auto h-12">
<h2 class="text-2xl font-bold text-gray-800 mt-4">Welcome Back!</h2>
<p class="text-gray-600">Please login to your account</p>
</div>
<form id="loginForm">
<div class="mb-4">
<label for="username" class="block text-gray-700 text-sm font-medium mb-2">Username</label>
<input type="text" id="username" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-amber-500" placeholder="Enter your username" required>
</div>
<div class="mb-6">
<label for="password" class="block text-gray-700 text-sm font-medium mb-2">Password</label>
<input type="password" id="password" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-amber-500" placeholder="Enter your password" required>
</div>
<button type="submit" class="w-full bg-amber-500 text-white py-2 px-4 rounded-md hover:bg-amber-600 focus:outline-none focus:ring-2 focus:ring-amber-500 focus:ring-offset-2 transition duration-150">
Login
</button>
</form>
</div>
</div>
<!-- Main App Container (hidden until login) -->
<div id="appContainer" class="hidden">
<!-- Header -->
<header class="bg-white shadow-sm">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 flex justify-between items-center">
<div class="flex items-center">
<img src="https://via.placeholder.com/150x50?text=Burger+Joint" alt="Burger Joint Logo" class="h-8">
<span class="ml-2 text-xl font-bold text-gray-800 hidden md:inline">Burger Joint</span>
</div>
<div class="flex items-center space-x-4">
<div class="hidden md:block">
<span id="currentTime" class="text-gray-600"></span>
</div>
<div class="relative">
<button id="userMenuButton" class="flex items-center space-x-2 focus:outline-none">
<span id="loggedInUser" class="font-medium text-gray-700"></span>
<div class="w-8 h-8 rounded-full bg-amber-500 flex items-center justify-center text-white">
<i class="fas fa-user"></i>
</div>
</button>
<div id="userMenu" class="hidden absolute right-0 mt-2 w-48 bg-white rounded-md shadow-lg py-1 z-50">
<a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">Profile</a>
<a href="#" id="logoutButton" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">Logout</a>
</div>
</div>
</div>
</div>
</header>
<!-- Main Content -->
<main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
<!-- Tabs Navigation -->
<div class="border-b border-gray-200 mb-6">
<nav class="-mb-px flex space-x-8">
<button id="billingTab" class="tab-active whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm">
<i class="fas fa-cash-register mr-2"></i>Billing
</button>
<button id="menuTab" class="whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300">
<i class="fas fa-utensils mr-2"></i>Menu Management
</button>
<button id="reportsTab" class="whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300">
<i class="fas fa-chart-bar mr-2"></i>Reports
</button>
<button id="usersTab" class="whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300">
<i class="fas fa-users mr-2"></i>User Management
</button>
</nav>
</div>
<!-- Billing Section -->
<div id="billingSection">
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<!-- Menu Items -->
<div class="lg:col-span-2">
<div class="bg-white rounded-lg shadow p-4">
<div class="mb-4">
<h2 class="text-lg font-medium text-gray-900">Menu Items</h2>
<div class="mt-2 relative">
<input type="text" id="menuSearch" class="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-amber-500" placeholder="Search menu items...">
<div class="absolute left-3 top-2.5 text-gray-400">
<i class="fas fa-search"></i>
</div>
</div>
</div>
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4" id="menuItemsContainer">
<!-- Menu items will be populated here by JavaScript -->
</div>
</div>
</div>
<!-- Order Summary -->
<div class="lg:col-span-1">
<div class="bg-white rounded-lg shadow p-4 sticky top-4">
<div class="flex justify-between items-center mb-4">
<h2 class="text-lg font-medium text-gray-900">Order Summary</h2>
<span id="orderNumber" class="text-sm text-gray-500">Order #0000</span>
</div>
<div class="border-b border-gray-200 mb-4"></div>
<div class="mb-4">
<div class="flex justify-between mb-2">
<span class="text-gray-600">Staff:</span>
<span id="staffName" class="font-medium">John Doe</span>
</div>
<div class="flex justify-between mb-2">
<span class="text-gray-600">Date:</span>
<span id="orderDate" class="font-medium">May 15, 2023</span>
</div>
<div class="flex justify-between mb-2">
<span class="text-gray-600">Time:</span>
<span id="orderTime" class="font-medium">10:30 AM</span>
</div>
</div>
<div class="border-b border-gray-200 mb-4"></div>
<div class="mb-4 max-h-64 overflow-y-auto" id="orderItemsContainer">
<!-- Order items will be populated here by JavaScript -->
<div class="text-center text-gray-500 py-4">
<i class="fas fa-shopping-cart text-2xl mb-2"></i>
<p>Your cart is empty</p>
</div>
</div>
<div class="border-b border-gray-200 mb-4"></div>
<div class="mb-4">
<div class="flex justify-between mb-2">
<span class="text-gray-600">Subtotal:</span>
<span id="subtotal" class="font-medium">$0.00</span>
</div>
<div class="flex justify-between mb-2">
<span class="text-gray-600">Tax (10%):</span>
<span id="tax" class="font-medium">$0.00</span>
</div>
<div class="flex justify-between text-lg font-bold">
<span>Total:</span>
<span id="total" class="text-amber-600">$0.00</span>
</div>
</div>
<div class="flex space-x-2">
<button id="clearOrderBtn" class="flex-1 bg-gray-200 text-gray-800 py-2 px-4 rounded-md hover:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 transition duration-150">
Clear
</button>
<button id="completeOrderBtn" class="flex-1 bg-amber-500 text-white py-2 px-4 rounded-md hover:bg-amber-600 focus:outline-none focus:ring-2 focus:ring-amber-500 focus:ring-offset-2 transition duration-150">
Complete Order
</button>
</div>
</div>
</div>
</div>
</div>
<!-- Menu Management Section (Hidden by default) -->
<div id="menuManagementSection" class="hidden">
<div class="bg-white rounded-lg shadow overflow-hidden">
<div class="px-6 py-4 border-b border-gray-200 flex justify-between items-center">
<h2 class="text-lg font-medium text-gray-900">Menu Management</h2>
<button id="addMenuItemBtn" class="bg-amber-500 text-white py-2 px-4 rounded-md hover:bg-amber-600 focus:outline-none focus:ring-2 focus:ring-amber-500 focus:ring-offset-2 transition duration-150">
<i class="fas fa-plus mr-2"></i>Add Item
</button>
</div>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Image</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Name</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Description</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Price</th>
<th scope="col" 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" id="menuItemsTable">
<!-- Menu items will be populated here by JavaScript -->
</tbody>
</table>
</div>
</div>
</div>
<!-- Reports Section (Hidden by default) -->
<div id="reportsSection" class="hidden">
<div class="bg-white rounded-lg shadow p-6">
<h2 class="text-lg font-medium text-gray-900 mb-6">Sales Reports</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8">
<div class="bg-gray-50 p-4 rounded-lg">
<h3 class="text-md font-medium text-gray-700 mb-4">Date Range</h3>
<div class="flex flex-col sm:flex-row space-y-2 sm:space-y-0 sm:space-x-4">
<div class="flex-1">
<label for="startDate" class="block text-sm font-medium text-gray-700 mb-1">Start Date</label>
<input type="date" id="startDate" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-amber-500">
</div>
<div class="flex-1">
<label for="endDate" class="block text-sm font-medium text-gray-700 mb-1">End Date</label>
<input type="date" id="endDate" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-amber-500">
</div>
<div class="flex items-end">
<button id="generateReportBtn" class="bg-amber-500 text-white py-2 px-4 rounded-md hover:bg-amber-600 focus:outline-none focus:ring-2 focus:ring-amber-500 focus:ring-offset-2 transition duration-150">
Generate
</button>
</div>
</div>
</div>
<div class="grid grid-cols-3 gap-4">
<div class="bg-amber-50 p-4 rounded-lg text-center">
<p class="text-sm font-medium text-amber-700">Today's Sales</p>
<p class="text-2xl font-bold text-amber-600 mt-2">$<span id="todaySales">0.00</span></p>
</div>
<div class="bg-blue-50 p-4 rounded-lg text-center">
<p class="text-sm font-medium text-blue-700">This Week</p>
<p class="text-2xl font-bold text-blue-600 mt-2">$<span id="weekSales">0.00</span></p>
</div>
<div class="bg-green-50 p-4 rounded-lg text-center">
<p class="text-sm font-medium text-green-700">This Month</p>
<p class="text-2xl font-bold text-green-600 mt-2">$<span id="monthSales">0.00</span></p>
</div>
</div>
</div>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-8">
<div class="bg-white p-4 rounded-lg border border-gray-200">
<h3 class="text-md font-medium text-gray-700 mb-4">Daily Sales</h3>
<canvas id="dailySalesChart" height="250"></canvas>
</div>
<div class="bg-white p-4 rounded-lg border border-gray-200">
<h3 class="text-md font-medium text-gray-700 mb-4">Top Selling Items</h3>
<canvas id="topItemsChart" height="250"></canvas>
</div>
</div>
<div class="bg-white p-4 rounded-lg border border-gray-200">
<div class="flex justify-between items-center mb-4">
<h3 class="text-md font-medium text-gray-700">Recent Orders</h3>
<button id="exportReportBtn" class="bg-green-500 text-white py-1 px-3 rounded-md text-sm hover:bg-green-600 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 transition duration-150">
<i class="fas fa-file-export mr-1"></i>Export
</button>
</div>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Order #</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Date</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Staff</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Amount</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200" id="recentOrdersTable">
<!-- Recent orders will be populated here by JavaScript -->
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- User Management Section (Hidden by default) -->
<div id="userManagementSection" class="hidden">
<div class="bg-white rounded-lg shadow overflow-hidden">
<div class="px-6 py-4 border-b border-gray-200 flex justify-between items-center">
<h2 class="text-lg font-medium text-gray-900">User Management</h2>
<button id="addUserBtn" class="bg-amber-500 text-white py-2 px-4 rounded-md hover:bg-amber-600 focus:outline-none focus:ring-2 focus:ring-amber-500 focus:ring-offset-2 transition duration-150">
<i class="fas fa-user-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 scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Name</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Email</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Role</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Last Login</th>
<th scope="col" 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" id="usersTable">
<!-- Users will be populated here by JavaScript -->
</tbody>
</table>
</div>
</div>
</div>
</main>
<!-- Add/Edit Menu Item Modal -->
<div id="menuItemModal" class="hidden fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 z-50">
<div class="bg-white rounded-lg p-6 w-full max-w-md">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-medium text-gray-900" id="menuItemModalTitle">Add Menu Item</h3>
<button id="closeMenuItemModal" class="text-gray-500 hover:text-gray-700">
<i class="fas fa-times"></i>
</button>
</div>
<form id="menuItemForm">
<input type="hidden" id="menuItemId">
<div class="mb-4">
<label for="itemName" class="block text-gray-700 text-sm font-medium mb-2">Item Name</label>
<input type="text" id="itemName" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-amber-500" required>
</div>
<div class="mb-4">
<label for="itemPrice" class="block text-gray-700 text-sm font-medium mb-2">Price</label>
<input type="number" id="itemPrice" step="0.01" min="0" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-amber-500" required>
</div>
<div class="mb-4">
<label for="itemDescription" class="block text-gray-700 text-sm font-medium mb-2">Description</label>
<textarea id="itemDescription" rows="3" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-amber-500"></textarea>
</div>
<div class="mb-4">
<label for="itemImage" class="block text-gray-700 text-sm font-medium mb-2">Image</label>
<div class="flex items-center">
<div class="mr-4">
<img id="itemImagePreview" src="https://via.placeholder.com/100x100?text=No+Image" alt="Item preview" class="w-16 h-16 rounded-md object-cover">
</div>
<div class="flex-1">
<input type="file" id="itemImage" class="hidden" accept="image/*">
<button type="button" id="uploadImageBtn" class="bg-gray-100 text-gray-700 py-2 px-4 rounded-md hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-amber-500 focus:ring-offset-2 transition duration-150">
<i class="fas fa-upload mr-2"></i>Upload Image
</button>
</div>
</div>
</div>
<div class="flex justify-end space-x-3">
<button type="button" id="cancelMenuItemBtn" class="bg-gray-200 text-gray-800 py-2 px-4 rounded-md hover:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 transition duration-150">
Cancel
</button>
<button type="submit" class="bg-amber-500 text-white py-2 px-4 rounded-md hover:bg-amber-600 focus:outline-none focus:ring-2 focus:ring-amber-500 focus:ring-offset-2 transition duration-150">
Save Item
</button>
</div>
</form>
</div>
</div>
<!-- Add/Edit User Modal -->
<div id="userModal" class="hidden fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 z-50">
<div class="bg-white rounded-lg p-6 w-full max-w-md">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-medium text-gray-900" id="userModalTitle">Add User</h3>
<button id="closeUserModal" class="text-gray-500 hover:text-gray-700">
<i class="fas fa-times"></i>
</button>
</div>
<form id="userForm">
<input type="hidden" id="userId">
<div class="mb-4">
<label for="userName" class="block text-gray-700 text-sm font-medium mb-2">Full Name</label>
<input type="text" id="userName" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-amber-500" required>
</div>
<div class="mb-4">
<label for="userEmail" class="block text-gray-700 text-sm font-medium mb-2">Email</label>
<input type="email" id="userEmail" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-amber-500" required>
</div>
<div class="mb-4">
<label for="userRole" class="block text-gray-700 text-sm font-medium mb-2">Role</label>
<select id="userRole" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-amber-500" required>
<option value="admin">Admin</option>
<option value="staff">Staff</option>
</select>
</div>
<div class="mb-4" id="passwordFields">
<label for="userPassword" class="block text-gray-700 text-sm font-medium mb-2">Password</label>
<input type="password" id="userPassword" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-amber-500" required>
</div>
<div class="flex justify-end space-x-3">
<button type="button" id="cancelUserBtn" class="bg-gray-200 text-gray-800 py-2 px-4 rounded-md hover:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 transition duration-150">
Cancel
</button>
<button type="submit" class="bg-amber-500 text-white py-2 px-4 rounded-md hover:bg-amber-600 focus:outline-none focus:ring-2 focus:ring-amber-500 focus:ring-offset-2 transition duration-150">
Save User
</button>
</div>
</form>
</div>
</div>
<!-- Receipt Modal -->
<div id="receiptModal" class="hidden fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 z-50">
<div class="bg-white rounded-lg p-6 w-full max-w-md">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-medium text-gray-900">Order Receipt</h3>
<div class="flex space-x-2">
<button id="printReceiptBtn" class="bg-blue-500 text-white py-1 px-3 rounded-md text-sm hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition duration-150">
<i class="fas fa-print mr-1"></i>Print
</button>
<button id="closeReceiptModal" class="text-gray-500 hover:text-gray-700">
<i class="fas fa-times"></i>
</button>
</div>
</div>
<div class="print-area p-4" id="receiptContent">
<div class="text-center mb-4">
<h2 class="text-xl font-bold">Burger Joint</h2>
<p class="text-sm text-gray-600">123 Burger Street, Foodville</p>
<p class="text-sm text-gray-600">Tel: (123) 456-7890</p>
</div>
<div class="border-b border-gray-300 mb-3"></div>
<div class="flex justify-between mb-1">
<span class="text-sm">Order #:</span>
<span class="text-sm font-medium" id="receiptOrderNumber">0000</span>
</div>
<div class="flex justify-between mb-1">
<span class="text-sm">Date:</span>
<span class="text-sm font-medium" id="receiptDate">May 15, 2023</span>
</div>
<div class="flex justify-between mb-3">
<span class="text-sm">Time:</span>
<span class="text-sm font-medium" id="receiptTime">10:30 AM</span>
</div>
<div class="border-b border-gray-300 mb-3"></div>
<div class="mb-3" id="receiptItems">
<!-- Receipt items will be populated here by JavaScript -->
</div>
<div class="border-b border-dashed border-gray-300 mb-3"></div>
<div class="flex justify-between mb-1">
<span class="text-sm">Subtotal:</span>
<span class="text-sm font-medium" id="receiptSubtotal">$0.00</span>
</div>
<div class="flex justify-between mb-1">
<span class="text-sm">Tax (10%):</span>
<span class="text-sm font-medium" id="receiptTax">$0.00</span>
</div>
<div class="flex justify-between mb-3 font-bold">
<span>Total:</span>
<span id="receiptTotal">$0.00</span>
</div>
<div class="border-b border-gray-300 mb-3"></div>
<div class="text-center text-xs text-gray-600">
<p>Thank you for your order!</p>
<p>Please visit us again</p>
</div>
</div>
</div>
</div>
<!-- Confirmation Modal -->
<div id="confirmationModal" class="hidden fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 z-50">
<div class="bg-white rounded-lg p-6 w-full max-w-sm">
<div class="text-center mb-4">
<i class="fas fa-exclamation-circle text-3xl text-amber-500 mb-3"></i>
<h3 class="text-lg font-medium text-gray-900" id="confirmationTitle">Confirm Action</h3>
<p class="text-sm text-gray-500 mt-1" id="confirmationMessage">Are you sure you want to perform this action?</p>
</div>
<div class="flex justify-center space-x-3">
<button id="cancelConfirmBtn" class="bg-gray-200 text-gray-800 py-2 px-4 rounded-md hover:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 transition duration-150">
Cancel
</button>
<button id="confirmActionBtn" class="bg-amber-500 text-white py-2 px-4 rounded-md hover:bg-amber-600 focus:outline-none focus:ring-2 focus:ring-amber-500 focus:ring-offset-2 transition duration-150">
Confirm
</button>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
// Database simulation
const database = {
users: [
{ id: 1, name: 'Admin User', email: 'admin@burgerjoint.com', password: 'admin123', role: 'admin', lastLogin: '2023-05-15 10:00' },
{ id: 2, name: 'Staff User', email: 'staff@burgerjoint.com', password: 'staff123', role: 'staff', lastLogin: '2023-05-15 09:30' }
],
menuItems: [
{ id: 1, name: 'Classic Burger', price: 8.99, description: 'Juicy beef patty with lettuce, tomato, onion, and our special sauce', image: 'https://via.placeholder.com/300x200?text=Classic+Burger' },
{ id: 2, name: 'Cheeseburger', price: 9.99, description: 'Classic burger with a slice of American cheese', image: 'https://via.placeholder.com/300x200?text=Cheeseburger' },
{ id: 3, name: 'Bacon Burger', price: 10.99, description: 'Juicy beef patty with crispy bacon and cheddar cheese', image: 'https://via.placeholder.com/300x200?text=Bacon+Burger' },
{ id: 4, name: 'Veggie Burger', price: 8.99, description: 'Plant-based patty with fresh veggies and vegan mayo', image: 'https://via.placeholder.com/300x200?text=Veggie+Burger' },
{ id: 5, name: 'Chicken Sandwich', price: 7.99, description: 'Grilled chicken breast with lettuce and mayo', image: 'https://via.placeholder.com/300x200?text=Chicken+Sandwich' },
{ id: 6, name: 'French Fries', price: 3.99, description: 'Crispy golden fries with a pinch of salt', image: 'https://via.placeholder.com/300x200?text=French+Fries' },
{ id: 7, name: 'Onion Rings', price: 4.99, description: 'Crispy battered onion rings with dipping sauce', image: 'https://via.placeholder.com/300x200?text=Onion+Rings' },
{ id: 8, name: 'Soda', price: 2.49, description: 'Refreshing soda in various flavors', image: 'https://via.placeholder.com/300x200?text=Soda' }
],
orders: [
{ id: 1001, userId: 2, totalPrice: 15.98, date: '2023-05-14', time: '12:30 PM', items: [
{ menuItemId: 1, quantity: 1, price: 8.99 },
{ menuItemId: 6, quantity: 1, price: 3.99 },
{ menuItemId: 8, quantity: 2, price: 2.49 }
]},
{ id: 1002, userId: 2, totalPrice: 24.97, date: '2023-05-14', time: '1:45 PM', items: [
{ menuItemId: 3, quantity: 2, price: 10.99 },
{ menuItemId: 7, quantity: 1, price: 4.99 }
]},
{ id: 1003, userId: 2, totalPrice: 18.47, date: '2023-05-15', time: '9:15 AM', items: [
{ menuItemId: 2, quantity: 1, price: 9.99 },
{ menuItemId: 5, quantity: 1, price: 7.99 },
{ menuItemId: 8, quantity: 1, price: 2.49 }
]}
],
currentOrder: {
id: null,
userId: null,
items: [],
subtotal: 0,
tax: 0,
total: 0
}
};
// App state
const state = {
currentUser: null,
currentTab: 'billing',
editingItemId: null,
editingUserId: null,
confirmationAction: null,
confirmationData: null
};
// DOM Elements
const elements = {
loginModal: document.getElementById('loginModal'),
appContainer: document.getElementById('appContainer'),
loggedInUser: document.getElementById('loggedInUser'),
userMenuButton: document.getElementById('userMenuButton'),
userMenu: document.getElementById('userMenu'),
logoutButton: document.getElementById('logoutButton'),
currentTime: document.getElementById('currentTime'),
// Tabs
billingTab: document.getElementById('billingTab'),
menuTab: document.getElementById('menuTab'),
reportsTab: document.getElementById('reportsTab'),
usersTab: document.getElementById('usersTab'),
// Sections
billingSection: document.getElementById('billingSection'),
menuManagementSection: document.getElementById('menuManagementSection'),
reportsSection: document.getElementById('reportsSection'),
userManagementSection: document.getElementById('userManagementSection'),
// Billing section
menuItemsContainer: document.getElementById('menuItemsContainer'),
menuSearch: document.getElementById('menuSearch'),
orderItemsContainer: document.getElementById('orderItemsContainer'),
orderNumber: document.getElementById('orderNumber'),
staffName: document.getElementById('staffName'),
orderDate: document.getElementById('orderDate'),
orderTime: document.getElementById('orderTime'),
subtotal: document.getElementById('subtotal'),
tax: document.getElementById('tax'),
total: document.getElementById('total'),
clearOrderBtn: document.getElementById('clearOrderBtn'),
completeOrderBtn: document.getElementById('completeOrderBtn'),
// Menu management
menuItemsTable: document.getElementById('menuItemsTable'),
addMenuItemBtn: document.getElementById('addMenuItemBtn'),
// Reports
startDate: document.getElementById('startDate'),
endDate: document.getElementById('endDate'),
generateReportBtn: document.getElementById('generateReportBtn'),
todaySales: document.getElementById('todaySales'),
weekSales: document.getElementById('weekSales'),
monthSales: document.getElementById('monthSales'),
dailySalesChart: document.getElementById('dailySalesChart'),
topItemsChart: document.getElementById('topItemsChart'),
recentOrdersTable: document.getElementById('recentOrdersTable'),
exportReportBtn: document.getElementById('exportReportBtn'),
// User management
usersTable: document.getElementById('usersTable'),
addUserBtn: document.getElementById('addUserBtn'),
// Modals
menuItemModal: document.getElementById('menuItemModal'),
menuItemModalTitle: document.getElementById('menuItemModalTitle'),
menuItemForm: document.getElementById('menuItemForm'),
menuItemId: document.getElementById('menuItemId'),
itemName: document.getElementById('itemName'),
itemPrice: document.getElementById('itemPrice'),
itemDescription: document.getElementById('itemDescription'),
itemImage: document.getElementById('itemImage'),
itemImagePreview: document.getElementById('itemImagePreview'),
uploadImageBtn: document.getElementById('uploadImageBtn'),
cancelMenuItemBtn: document.getElementById('cancelMenuItemBtn'),
closeMenuItemModal: document.getElementById('closeMenuItemModal'),
userModal: document.getElementById('userModal'),
userModalTitle: document.getElementById('userModalTitle'),
userForm: document.getElementById('userForm'),
userId: document.getElementById('userId'),
userName: document.getElementById('userName'),
userEmail: document.getElementById('userEmail'),
userRole: document.getElementById('userRole'),
userPassword: document.getElementById('userPassword'),
passwordFields: document.getElementById('passwordFields'),
cancelUserBtn: document.getElementById('cancelUserBtn'),
closeUserModal: document.getElementById('closeUserModal'),
receiptModal: document.getElementById('receiptModal'),
receiptContent: document.getElementById('receiptContent'),
receiptOrderNumber: document.getElementById('receiptOrderNumber'),
receiptDate: document.getElementById('receiptDate'),
receiptTime: document.getElementById('receiptTime'),
receiptItems: document.getElementById('receiptItems'),
receiptSubtotal: document.getElementById('receiptSubtotal'),
receiptTax: document.getElementById('receiptTax'),
receiptTotal: document.getElementById('receiptTotal'),
printReceiptBtn: document.getElementById('printReceiptBtn'),
closeReceiptModal: document.getElementById('closeReceiptModal'),
confirmationModal: document.getElementById('confirmationModal'),
confirmationTitle: document.getElementById('confirmationTitle'),
confirmationMessage: document.getElementById('confirmationMessage'),
cancelConfirmBtn: document.getElementById('cancelConfirmBtn'),
confirmActionBtn: document.getElementById('confirmActionBtn'),
// Forms
loginForm: document.getElementById('loginForm'),
username: document.getElementById('username'),
password: document.getElementById('password')
};
// Initialize the app
function init() {
// Set current date for date inputs
const today = new Date().toISOString().split('T')[0];
elements.startDate.value = today;
elements.endDate.value = today;
// Update clock
updateClock();
setInterval(updateClock, 1000);
// Generate a random order number
generateOrderNumber();
// Set current date in order summary
const now = new Date();
elements.orderDate.textContent = now.toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' });
elements.orderTime.textContent = now.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' });
// Event listeners
setupEventListeners();
// Show login modal by default
elements.loginModal.classList.remove('hidden');
}
// Update clock
function updateClock() {
const now = new Date();
elements.currentTime.textContent = now.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', second: '2-digit' });
}
// Generate a random order number
function generateOrderNumber() {
const orderNumber = Math.floor(1000 + Math.random() * 9000);
database.currentOrder.id = orderNumber;
elements.orderNumber.textContent = `Order #${orderNumber}`;
elements.receiptOrderNumber.textContent = orderNumber;
}
// Setup event listeners
function setupEventListeners() {
// Login form
elements.loginForm.addEventListener('submit', handleLogin);
// Logout button
elements.logoutButton.addEventListener('click', handleLogout);
// User menu toggle
elements.userMenuButton.addEventListener('click', () => {
elements.userMenu.classList.toggle('hidden');
});
// Tab navigation
elements.billingTab.addEventListener('click', () => switchTab('billing'));
elements.menuTab.addEventListener('click', () => switchTab('menu'));
elements.reportsTab.addEventListener('click', () => switchTab('reports'));
elements.usersTab.addEventListener('click', () => switchTab('users'));
// Menu search
elements.menuSearch.addEventListener('input', filterMenuItems);
// Order buttons
elements.clearOrderBtn.addEventListener('click', clearOrder);
elements.completeOrderBtn.addEventListener('click', completeOrder);
// Menu item modal
elements.addMenuItemBtn.addEventListener('click', () => openMenuItemModal(null));
elements.uploadImageBtn.addEventListener('click', () => elements.itemImage.click());
elements.itemImage.addEventListener('change', handleImageUpload);
elements.cancelMenuItemBtn.addEventListener('click', closeMenuItemModal);
elements.closeMenuItemModal.addEventListener('click', closeMenuItemModal);
elements.menuItemForm.addEventListener('submit', saveMenuItem);
// User modal
elements.addUserBtn.addEventListener('click', () => openUserModal(null));
elements.cancelUserBtn.addEventListener('click', closeUserModal);
elements.closeUserModal.addEventListener('click', closeUserModal);
elements.userForm.addEventListener('submit', saveUser);
// Receipt modal
elements.printReceiptBtn.addEventListener('click', printReceipt);
elements.closeReceiptModal.addEventListener('click', () => {
elements.receiptModal.classList.add('hidden');
});
// Confirmation modal
elements.cancelConfirmBtn.addEventListener('click', () => {
elements.confirmationModal.classList.add('hidden');
});
elements.confirmActionBtn.addEventListener('click', confirmAction);
// Generate report
elements.generateReportBtn.addEventListener('click', generateReport);
elements.exportReportBtn.addEventListener('click', exportReport);
}
// Handle login
function handleLogin(e) {
e.preventDefault();
const username = elements.username.value;
const password = elements.password.value;
// Find user in database
const user = database.users.find(u =>
(u.email === username || u.name === username) && u.password === password
);
if (user) {
// Successful login
state.currentUser = user;
elements.loggedInUser.textContent = user.name;
// Hide login modal and show app
elements.loginModal.classList.add('hidden');
elements.appContainer.classList.remove('hidden');
// Load appropriate content based on role
if (user.role === 'admin') {
loadMenuItemsTable();
loadUsersTable();
loadReports();
} else {
// Staff can only see billing
elements.menuTab.classList.add('hidden');
elements.reportsTab.classList.add('hidden');
elements.usersTab.classList.add('hidden');
}
// Load menu items for billing
loadMenuItems();
// Set staff name in order summary
elements.staffName.textContent = user.name;
} else {
// Failed login
alert('Invalid username or password');
}
}
// Handle logout
function handleLogout() {
state.currentUser = null;
elements.appContainer.classList.add('hidden');
elements.loginModal.classList.remove('hidden');
elements.username.value = '';
elements.password.value = '';
elements.userMenu.classList.add('hidden');
}
// Switch between tabs
function switchTab(tab) {
state.currentTab = tab;
// Update tab styling
elements.billingTab.classList.remove('tab-active');
elements.menuTab.classList.remove('tab-active');
elements.reportsTab.classList.remove('tab-active');
elements.usersTab.classList.remove('tab-active');
// Hide all sections
elements.billingSection.classList.add('hidden');
elements.menuManagementSection.classList.add('hidden');
elements.reportsSection.classList.add('hidden');
elements.userManagementSection.classList.add('hidden');
// Show selected tab and section
switch (tab) {
case 'billing':
elements.billingTab.classList.add('tab-active');
elements.billingSection.classList.remove('hidden');
break;
case 'menu':
elements.menuTab.classList.add('tab-active');
elements.menuManagementSection.classList.remove('hidden');
break;
case 'reports':
elements.reportsTab.classList.add('tab-active');
elements.reportsSection.classList.remove('hidden');
break;
case 'users':
elements.usersTab.classList.add('tab-active');
elements.userManagementSection.classList.remove('hidden');
break;
}
}
// Load menu items for billing
function loadMenuItems() {
elements.menuItemsContainer.innerHTML = '';
database.menuItems.forEach(item => {
const menuItem = document.createElement('div');
menuItem.className = 'menu-item bg-white rounded-lg shadow overflow-hidden cursor-pointer';
menuItem.innerHTML = `
<div class="h-32 bg-gray-200 overflow-hidden">
<img src="${item.image}" alt="${item.name}" class="w-full h-full object-cover">
</div>
<div class="p-3">
<h3 class="font-medium text-gray-900 truncate">${item.name}</h3>
<p class="text-sm text-gray-500 mb-2 truncate">${item.description}</p>
<div class="flex justify-between items-center">
<span class="font-bold text-amber-600">$${item.price.toFixed(2)}</span>
<button class="add-to-cart bg-amber-500 text-white rounded-full w-8 h-8 flex items-center justify-center hover:bg-amber-600 focus:outline-none">
<i class="fas fa-plus"></i>
</button>
</div>
</div>
`;
// Add event listener to the add to cart button
const addToCartBtn = menuItem.querySelector('.add-to-cart');
addToCartBtn.addEventListener('click', (e) => {
e.stopPropagation();
addToCart(item);
});
elements.menuItemsContainer.appendChild(menuItem);
});
}
// Filter menu items based on search input
function filterMenuItems() {
const searchTerm = elements.menuSearch.value.toLowerCase();
const menuItems = document.querySelectorAll('.menu-item');
menuItems.forEach(item => {
const name = item.querySelector('h3').textContent.toLowerCase();
const description = item.querySelector('p').textContent.toLowerCase();
if (name.includes(searchTerm) || description.includes(searchTerm)) {
item.classList.remove('hidden');
} else {
item.classList.add('hidden');
}
});
}
// Add item to cart
function addToCart(item) {
// Check if item already exists in cart
const existingItem = database.currentOrder.items.find(i => i.menuItemId === item.id);
if (existingItem) {
existingItem.quantity += 1;
} else {
database.currentOrder.items.push({
menuItemId: item.id,
quantity: 1,
price: item.price
});
}
// Update order summary
updateOrderSummary();
}
// Update order summary
function updateOrderSummary() {
// Clear current items
elements.orderItemsContainer.innerHTML = '';
if (database.currentOrder.items.length === 0) {
elements.orderItemsContainer.innerHTML = `
<div class="text-center text-gray-500 py-4">
<i class="fas fa-shopping-cart text-2xl mb-2"></i>
<p>Your cart is empty</p>
</div>
`;
// Update totals
elements.subtotal.textContent = '$0.00';
elements.tax.textContent = '$0.00';
elements.total.textContent = '$0.00';
return;
}
// Calculate totals
let subtotal = 0;
// Add each item to the order summary
database.currentOrder.items.forEach(item => {
const menuItem = database.menuItems.find(m => m.id === item.menuItemId);
const itemTotal = item.quantity * item.price;
subtotal += itemTotal;
const orderItem = document.createElement('div');
orderItem.className = 'flex justify-between items-center py-2 border-b border-gray-100';
orderItem.innerHTML = `
<div class="flex-1">
<h4 class="text-sm font-medium">${menuItem.name}</h4>
<p class="text-xs text-gray-500">$${item.price.toFixed(2)} x ${item.quantity}</p>
</div>
<div class="flex items-center">
<span class="text-sm font-medium mr-3">$${itemTotal.toFixed(2)}</span>
<div class="flex items-center space-x-1">
<button class="decrease-quantity text-xs bg-gray-200 text-gray-700 rounded-full w-5 h-5 flex items-center justify-center hover:bg-gray-300">
<i class="fas fa-minus"></i>
</button>
<button class="increase-quantity text-xs bg-gray-200 text-gray-700 rounded-full w-5 h-5 flex items-center justify-center hover:bg-gray-300">
<i class="fas fa-plus"></i>
</button>
<button class="remove-item text-xs bg-red-100 text-red-600 rounded-full w-5 h-5 flex items-center justify-center hover:bg-red-200 ml-1">
<i class="fas fa-times"></i>
</button>
</div>
</div>
`;
// Add event listeners to quantity buttons
const decreaseBtn = orderItem.querySelector('.decrease-quantity');
const increaseBtn = orderItem.querySelector('.increase-quantity');
const removeBtn = orderItem.querySelector('.remove-item');
decreaseBtn.addEventListener('click', () => updateQuantity(item.menuItemId, -1));
increaseBtn.addEventListener('click', () => updateQuantity(item.menuItemId, 1));
removeBtn.addEventListener('click', () => removeItem(item.menuItemId));
elements.orderItemsContainer.appendChild(orderItem);
});
// Calculate tax and total
const tax = subtotal * 0.10; // 10% tax
const total = subtotal + tax;
// Update totals in UI
elements.subtotal.textContent = `$${subtotal.toFixed(2)}`;
elements.tax.textContent = `$${tax.toFixed(2)}`;
elements.total.textContent = `$${total.toFixed(2)}`;
// Update totals in database
database.currentOrder.subtotal = subtotal;
database.currentOrder.tax = tax;
database.currentOrder.total = total;
}
// Update item quantity
function updateQuantity(menuItemId, change) {
const item = database.currentOrder.items.find(i => i.menuItemId === menuItemId);
if (item) {
item.quantity += change;
// Remove item if quantity reaches zero
if (item.quantity <= 0) {
database.currentOrder.items = database.currentOrder.items.filter(i => i.menuItemId !== menuItemId);
}
// Update order summary
updateOrderSummary();
}
}
// Remove item from cart
function removeItem(menuItemId) {
database.currentOrder.items = database.currentOrder.items.filter(i => i.menuItemId !== menuItemId);
updateOrderSummary();
}
// Clear current order
function clearOrder() {
database.currentOrder.items = [];
updateOrderSummary();
}
// Complete order and generate receipt
function completeOrder() {
if (database.currentOrder.items.length === 0) {
alert('Cannot complete an empty order');
return;
}
// Set user ID for the order
database.currentOrder.userId = state.currentUser.id;
// Add current order to orders history
const now = new Date();
const newOrder = {
id: database.currentOrder.id,
userId: database.currentOrder.userId,
totalPrice: database.currentOrder.total,
date: now.toISOString().split('T')[0],
time: now.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' }),
items: [...database.currentOrder.items]
};
database.orders.push(newOrder);
// Generate receipt
generateReceipt();
// Clear current order and generate a new order number
clearOrder();
generateOrderNumber();
}
// Generate receipt
function generateReceipt() {
// Update receipt details
const now = new Date();
elements.receiptDate.textContent = now.toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' });
elements.receiptTime.textContent = now.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' });
// Clear previous items
elements.receiptItems.innerHTML = '';
// Add items to receipt
database.currentOrder.items.forEach(item => {
const menuItem = database.menuItems.find(m => m.id === item.menuItemId);
const itemTotal = item.quantity * item.price;
const receiptItem = document.createElement('div');
receiptItem.className = 'flex justify-between py-1';
receiptItem.innerHTML = `
<div>
<span class="text-sm font-medium">${menuItem.name}</span>
<span class="text-xs text-gray-500 block">$${item.price.toFixed(2)} x ${item.quantity}</span>
</div>
<span class="text-sm font-medium">$${itemTotal.toFixed(2)}</span>
`;
elements.receiptItems.appendChild(receiptItem);
});
// Update totals
elements.receiptSubtotal.textContent = `$${database.currentOrder.subtotal.toFixed(2)}`;
elements.receiptTax.textContent = `$${database.currentOrder.tax.toFixed(2)}`;
elements.receiptTotal.textContent = `$${database.currentOrder.total.toFixed(2)}`;
// Show receipt modal
elements.receiptModal.classList.remove('hidden');
}
// Print receipt
function printReceipt() {
const printContents = elements.receiptContent.innerHTML;
const originalContents = document.body.innerHTML;
document.body.innerHTML = printContents;
window.print();
document.body.innerHTML = originalContents;
// Reattach event listeners
setupEventListeners();
}
// Load menu items for management table
function loadMenuItemsTable() {
elements.menuItemsTable.innerHTML = '';
database.menuItems.forEach(item => {
const row = document.createElement('tr');
row.innerHTML = `
<td class="px-6 py-4 whitespace-nowrap">
<div class="flex-shrink-0 h-10 w-10">
<img class="h-10 w-10 rounded-md object-cover" src="${item.image}" alt="${item.name}">
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="text-sm font-medium text-gray-900">${item.name}</div>
</td>
<td class="px-6 py-4">
<div class="text-sm text-gray-500 max-w-xs truncate">${item.description}</div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="text-sm text-gray-900">$${item.price.toFixed(2)}</div>
</td>
<td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
<button class="edit-menu-item text-amber-600 hover:text-amber-900 mr-3" data-id="${item.id}">
<i class="fas fa-edit"></i>
</button>
<button class="delete-menu-item text-red-600 hover:text-red-900" data-id="${item.id}">
<i class="fas fa-trash"></i>
</button>
</td>
`;
// Add event listeners to edit and delete buttons
const editBtn = row.querySelector('.edit-menu-item');
const deleteBtn = row.querySelector('.delete-menu-item');
editBtn.addEventListener('click', () => openMenuItemModal(item.id));
deleteBtn.addEventListener('click', () => confirmDeleteMenuItem(item.id));
elements.menuItemsTable.appendChild(row);
});
}
// Open menu item modal for adding/editing
function openMenuItemModal(itemId) {
if (itemId) {
// Editing existing item
state.editingItemId = itemId;
const item = database.menuItems.find(i => i.id === itemId);
elements.menuItemModalTitle.textContent = 'Edit Menu Item';
elements.menuItemId.value = itemId;
elements.itemName.value = item.name;
elements.itemPrice.value = item.price;
elements.itemDescription.value = item.description;
elements.itemImagePreview.src = item.image;
} else {
// Adding new item
state.editingItemId = null;
elements.menuItemModalTitle.textContent = 'Add Menu Item';
elements.menuItemId.value = '';
elements.itemName.value = '';
elements.itemPrice.value = '';
elements.itemDescription.value = '';
elements.itemImagePreview.src = 'https://via.placeholder.com/100x100?text=No+Image';
}
elements.menuItemModal.classList.remove('hidden');
}
// Close menu item modal
function closeMenuItemModal() {
elements.menuItemModal.classList.add('hidden');
}
// Handle image upload
function handleImageUpload(e) {
const file = e.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function(event) {
elements.itemImagePreview.src = event.target.result;
};
reader.readAsDataURL(file);
}
}
// Save menu item (add or update)
function saveMenuItem(e) {
e.preventDefault();
const itemId = parseInt(elements.menuItemId.value);
const name = elements.itemName.value;
const price = parseFloat(elements.itemPrice.value);
const description = elements.itemDescription.value;
const image = elements.itemImagePreview.src;
if (itemId) {
// Update existing item
const index = database.menuItems.findIndex(i => i.id === itemId);
if (index !== -1) {
database.menuItems[index] = {
id: itemId,
name,
price,
description,
image
};
}
} else {
// Add new item
const newId = database.menuItems.length > 0 ?
Math.max(...database.menuItems.map(i => i.id)) + 1 : 1;
database.menuItems.push({
id: newId,
name,
price,
description,
image
});
}
// Refresh tables
loadMenuItems();
loadMenuItemsTable();
// Close modal
closeMenuItemModal();
}
// Confirm delete menu item
function confirmDeleteMenuItem(itemId) {
state.confirmationAction = 'deleteMenuItem';
state.confirmationData = itemId;
const item = database.menuItems.find(i => i.id === itemId);
elements.confirmationTitle.textContent = 'Delete Menu Item';
elements.confirmationMessage.textContent = `Are you sure you want to delete "${item.name}"? This action cannot be undone.`;
elements.confirmationModal.classList.remove('hidden');
}
// Delete menu item
function deleteMenuItem(itemId) {
database.menuItems = database.menuItems.filter(i => i.id !== itemId);
loadMenuItems();
loadMenuItemsTable();
}
// Load users table
function loadUsersTable() {
elements.usersTable.innerHTML = '';
database.users.forEach(user => {
const row = document.createElement('tr');
row.innerHTML = `
<td class="px-6 py-4 whitespace-nowrap">
<div class="text-sm font-medium text-gray-900">${user.name}</div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="text-sm text-gray-500">${user.email}</div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full ${user.role === 'admin' ? 'bg-green-100 text-green-800' : 'bg-blue-100 text-blue-800'}">
${user.role.charAt(0).toUpperCase() + user.role.slice(1)}
</span>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="text-sm text-gray-500">${user.lastLogin || 'Never'}</div>
</td>
<td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
<button class="edit-user text-amber-600 hover:text-amber-900 mr-3" data-id="${user.id}">
<i class="fas fa-edit"></i>
</button>
<button class="delete-user text-red-600 hover:text-red-900" data-id="${user.id}">
<i class="fas fa-trash"></i>
</button>
</td>
`;
// Add event listeners to edit and delete buttons
const editBtn = row.querySelector('.edit-user');
const deleteBtn = row.querySelector('.delete-user');
editBtn.addEventListener('click', () => openUserModal(user.id));
deleteBtn.addEventListener('click', () => confirmDeleteUser(user.id));
elements.usersTable.appendChild(row);
});
}
// Open user modal for adding/editing
function openUserModal(userId) {
if (userId) {
// Editing existing user
state.editingUserId = userId;
const user = database.users.find(u => u.id === userId);
elements.userModalTitle.textContent = 'Edit User';
elements.userId.value = userId;
elements.userName.value = user.name;
elements.userEmail.value = user.email;
elements.userRole.value = user.role;
// Hide password field for existing users
elements.passwordFields.classList.add('hidden');
elements.userPassword.required = false;
} else {
// Adding new user
state.editingUserId = null;
elements.userModalTitle.textContent = 'Add User';
elements.userId.value = '';
elements.userName.value = '';
elements.userEmail.value = '';
elements.userRole.value = 'staff';
// Show password field for new users
elements.passwordFields.classList.remove('hidden');
elements.userPassword.required = true;
elements.userPassword.value = '';
}
elements.userModal.classList.remove('hidden');
}
// Close user modal
function closeUserModal() {
elements.userModal.classList.add('hidden');
}
// Save user (add or update)
function saveUser(e) {
e.preventDefault();
const userId = parseInt(elements.userId.value);
const name = elements.userName.value;
const email = elements.userEmail.value;
const role = elements.userRole.value;
const password = elements.userPassword.value;
if (userId) {
// Update existing user
const index = database.users.findIndex(u => u.id === userId);
if (index !== -1) {
database.users[index] = {
...database.users[index],
name,
email,
role
};
// Update password if provided
if (password) {
database.users[index].password = password;
}
}
} else {
// Add new user
const newId = database.users.length > 0 ?
Math.max(...database.users.map(u => u.id)) + 1 : 1;
database.users.push({
id: newId,
name,
email,
password,
role,
lastLogin: null
});
}
// Refresh table
loadUsersTable();
// Close modal
closeUserModal();
}
// Confirm delete user
function confirmDeleteUser(userId) {
state.confirmationAction = 'deleteUser';
state.confirmationData = userId;
const user = database.users.find(u => u.id === userId);
elements.confirmationTitle.textContent = 'Delete User';
elements.confirmationMessage.textContent = `Are you sure you want to delete "${user.name}"? This action cannot be undone.`;
elements.confirmationModal.classList.remove('hidden');
}
// Delete user
function deleteUser(userId) {
// Don't allow deleting the current user
if (state.currentUser && state.currentUser.id === userId) {
alert('You cannot delete your own account while logged in.');
return;
}
database.users = database.users.filter(u => u.id !== userId);
loadUsersTable();
}
// Handle confirmation actions
function confirmAction() {
switch (state.confirmationAction) {
case 'deleteMenuItem':
deleteMenuItem(state.confirmationData);
break;
case 'deleteUser':
deleteUser(state.confirmationData);
break;
}
elements.confirmationModal.classList.add('hidden');
}
// Load reports
function loadReports() {
// Calculate today's date
const today = new Date().toISOString().split('T')[0];
// Calculate sales
const todaySales = database.orders
.filter(order => order.date === today)
.reduce((sum, order) => sum + order.totalPrice, 0);
// Calculate this week's sales (simplified for demo)
const weekSales = database.orders
.reduce((sum, order) => sum + order.totalPrice, 0);
// Calculate this month's sales (simplified for demo)
const monthSales = database.orders
.reduce((sum, order) => sum + order.totalPrice, 0) * 3;
// Update UI
elements.todaySales.textContent = todaySales.toFixed(2);
elements.weekSales.textContent = weekSales.toFixed(2);
elements.monthSales.textContent = monthSales.toFixed(2);
// Load recent orders
loadRecentOrders();
// Initialize charts
initCharts();
}
// Initialize charts
function initCharts() {
// Daily sales chart (last 7 days)
const dailySalesCtx = elements.dailySalesChart.getContext('2d');
new Chart(dailySalesCtx, {
type: 'bar',
data: {
labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
datasets: [{
label: 'Daily Sales ($)',
data: [120, 190, 150, 210, 180, 250, 200],
backgroundColor: 'rgba(245, 158, 11, 0.7)',
borderColor: 'rgba(245, 158, 11, 1)',
borderWidth: 1
}]
},
options: {
responsive: true,
scales: {
y: {
beginAtZero: true
}
}
}
});
// Top items chart
const topItemsCtx = elements.topItemsChart.getContext('2d');
new Chart(topItemsCtx, {
type
</html>