Spaces:
Running
Running
Add 3 files
Browse files- README.md +6 -4
- index.html +1502 -19
- prompts.txt +3 -0
README.md
CHANGED
|
@@ -1,10 +1,12 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
colorTo: blue
|
| 6 |
sdk: static
|
| 7 |
pinned: false
|
|
|
|
|
|
|
| 8 |
---
|
| 9 |
|
| 10 |
-
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
|
| 1 |
---
|
| 2 |
+
title: billing
|
| 3 |
+
emoji: π³
|
| 4 |
+
colorFrom: yellow
|
| 5 |
colorTo: blue
|
| 6 |
sdk: static
|
| 7 |
pinned: false
|
| 8 |
+
tags:
|
| 9 |
+
- deepsite
|
| 10 |
---
|
| 11 |
|
| 12 |
+
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
index.html
CHANGED
|
@@ -1,19 +1,1502 @@
|
|
| 1 |
-
<!
|
| 2 |
-
<html>
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>Burger Joint Billing System</title>
|
| 7 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 8 |
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
| 9 |
+
<style>
|
| 10 |
+
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap');
|
| 11 |
+
|
| 12 |
+
body {
|
| 13 |
+
font-family: 'Poppins', sans-serif;
|
| 14 |
+
background-color: #f8f9fa;
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
.menu-item:hover {
|
| 18 |
+
transform: translateY(-5px);
|
| 19 |
+
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
.menu-item {
|
| 23 |
+
transition: all 0.3s ease;
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
.receipt {
|
| 27 |
+
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
|
| 28 |
+
border-left: 5px solid #f59e0b;
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
.print-area {
|
| 32 |
+
background-color: white;
|
| 33 |
+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
.tab-active {
|
| 37 |
+
border-bottom: 3px solid #f59e0b;
|
| 38 |
+
color: #f59e0b;
|
| 39 |
+
font-weight: 600;
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
.floating-btn {
|
| 43 |
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1), 0 1px 3px rgba(0, 0, 0, 0.08);
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
.floating-btn:hover {
|
| 47 |
+
transform: translateY(-2px);
|
| 48 |
+
box-shadow: 0 7px 14px rgba(0, 0, 0, 0.1), 0 3px 6px rgba(0, 0, 0, 0.08);
|
| 49 |
+
}
|
| 50 |
+
</style>
|
| 51 |
+
</head>
|
| 52 |
+
<body class="bg-gray-100">
|
| 53 |
+
<!-- Login Modal -->
|
| 54 |
+
<div id="loginModal" class="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 z-50">
|
| 55 |
+
<div class="bg-white rounded-lg p-8 w-full max-w-md">
|
| 56 |
+
<div class="text-center mb-6">
|
| 57 |
+
<img src="https://via.placeholder.com/150x50?text=Burger+Joint" alt="Burger Joint Logo" class="mx-auto h-12">
|
| 58 |
+
<h2 class="text-2xl font-bold text-gray-800 mt-4">Welcome Back!</h2>
|
| 59 |
+
<p class="text-gray-600">Please login to your account</p>
|
| 60 |
+
</div>
|
| 61 |
+
<form id="loginForm">
|
| 62 |
+
<div class="mb-4">
|
| 63 |
+
<label for="username" class="block text-gray-700 text-sm font-medium mb-2">Username</label>
|
| 64 |
+
<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>
|
| 65 |
+
</div>
|
| 66 |
+
<div class="mb-6">
|
| 67 |
+
<label for="password" class="block text-gray-700 text-sm font-medium mb-2">Password</label>
|
| 68 |
+
<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>
|
| 69 |
+
</div>
|
| 70 |
+
<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">
|
| 71 |
+
Login
|
| 72 |
+
</button>
|
| 73 |
+
</form>
|
| 74 |
+
</div>
|
| 75 |
+
</div>
|
| 76 |
+
|
| 77 |
+
<!-- Main App Container (hidden until login) -->
|
| 78 |
+
<div id="appContainer" class="hidden">
|
| 79 |
+
<!-- Header -->
|
| 80 |
+
<header class="bg-white shadow-sm">
|
| 81 |
+
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 flex justify-between items-center">
|
| 82 |
+
<div class="flex items-center">
|
| 83 |
+
<img src="https://via.placeholder.com/150x50?text=Burger+Joint" alt="Burger Joint Logo" class="h-8">
|
| 84 |
+
<span class="ml-2 text-xl font-bold text-gray-800 hidden md:inline">Burger Joint</span>
|
| 85 |
+
</div>
|
| 86 |
+
<div class="flex items-center space-x-4">
|
| 87 |
+
<div class="hidden md:block">
|
| 88 |
+
<span id="currentTime" class="text-gray-600"></span>
|
| 89 |
+
</div>
|
| 90 |
+
<div class="relative">
|
| 91 |
+
<button id="userMenuButton" class="flex items-center space-x-2 focus:outline-none">
|
| 92 |
+
<span id="loggedInUser" class="font-medium text-gray-700"></span>
|
| 93 |
+
<div class="w-8 h-8 rounded-full bg-amber-500 flex items-center justify-center text-white">
|
| 94 |
+
<i class="fas fa-user"></i>
|
| 95 |
+
</div>
|
| 96 |
+
</button>
|
| 97 |
+
<div id="userMenu" class="hidden absolute right-0 mt-2 w-48 bg-white rounded-md shadow-lg py-1 z-50">
|
| 98 |
+
<a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">Profile</a>
|
| 99 |
+
<a href="#" id="logoutButton" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">Logout</a>
|
| 100 |
+
</div>
|
| 101 |
+
</div>
|
| 102 |
+
</div>
|
| 103 |
+
</div>
|
| 104 |
+
</header>
|
| 105 |
+
|
| 106 |
+
<!-- Main Content -->
|
| 107 |
+
<main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
|
| 108 |
+
<!-- Tabs Navigation -->
|
| 109 |
+
<div class="border-b border-gray-200 mb-6">
|
| 110 |
+
<nav class="-mb-px flex space-x-8">
|
| 111 |
+
<button id="billingTab" class="tab-active whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm">
|
| 112 |
+
<i class="fas fa-cash-register mr-2"></i>Billing
|
| 113 |
+
</button>
|
| 114 |
+
<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">
|
| 115 |
+
<i class="fas fa-utensils mr-2"></i>Menu Management
|
| 116 |
+
</button>
|
| 117 |
+
<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">
|
| 118 |
+
<i class="fas fa-chart-bar mr-2"></i>Reports
|
| 119 |
+
</button>
|
| 120 |
+
<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">
|
| 121 |
+
<i class="fas fa-users mr-2"></i>User Management
|
| 122 |
+
</button>
|
| 123 |
+
</nav>
|
| 124 |
+
</div>
|
| 125 |
+
|
| 126 |
+
<!-- Billing Section -->
|
| 127 |
+
<div id="billingSection">
|
| 128 |
+
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
| 129 |
+
<!-- Menu Items -->
|
| 130 |
+
<div class="lg:col-span-2">
|
| 131 |
+
<div class="bg-white rounded-lg shadow p-4">
|
| 132 |
+
<div class="mb-4">
|
| 133 |
+
<h2 class="text-lg font-medium text-gray-900">Menu Items</h2>
|
| 134 |
+
<div class="mt-2 relative">
|
| 135 |
+
<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...">
|
| 136 |
+
<div class="absolute left-3 top-2.5 text-gray-400">
|
| 137 |
+
<i class="fas fa-search"></i>
|
| 138 |
+
</div>
|
| 139 |
+
</div>
|
| 140 |
+
</div>
|
| 141 |
+
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4" id="menuItemsContainer">
|
| 142 |
+
<!-- Menu items will be populated here by JavaScript -->
|
| 143 |
+
</div>
|
| 144 |
+
</div>
|
| 145 |
+
</div>
|
| 146 |
+
|
| 147 |
+
<!-- Order Summary -->
|
| 148 |
+
<div class="lg:col-span-1">
|
| 149 |
+
<div class="bg-white rounded-lg shadow p-4 sticky top-4">
|
| 150 |
+
<div class="flex justify-between items-center mb-4">
|
| 151 |
+
<h2 class="text-lg font-medium text-gray-900">Order Summary</h2>
|
| 152 |
+
<span id="orderNumber" class="text-sm text-gray-500">Order #0000</span>
|
| 153 |
+
</div>
|
| 154 |
+
|
| 155 |
+
<div class="border-b border-gray-200 mb-4"></div>
|
| 156 |
+
|
| 157 |
+
<div class="mb-4">
|
| 158 |
+
<div class="flex justify-between mb-2">
|
| 159 |
+
<span class="text-gray-600">Staff:</span>
|
| 160 |
+
<span id="staffName" class="font-medium">John Doe</span>
|
| 161 |
+
</div>
|
| 162 |
+
<div class="flex justify-between mb-2">
|
| 163 |
+
<span class="text-gray-600">Date:</span>
|
| 164 |
+
<span id="orderDate" class="font-medium">May 15, 2023</span>
|
| 165 |
+
</div>
|
| 166 |
+
<div class="flex justify-between mb-2">
|
| 167 |
+
<span class="text-gray-600">Time:</span>
|
| 168 |
+
<span id="orderTime" class="font-medium">10:30 AM</span>
|
| 169 |
+
</div>
|
| 170 |
+
</div>
|
| 171 |
+
|
| 172 |
+
<div class="border-b border-gray-200 mb-4"></div>
|
| 173 |
+
|
| 174 |
+
<div class="mb-4 max-h-64 overflow-y-auto" id="orderItemsContainer">
|
| 175 |
+
<!-- Order items will be populated here by JavaScript -->
|
| 176 |
+
<div class="text-center text-gray-500 py-4">
|
| 177 |
+
<i class="fas fa-shopping-cart text-2xl mb-2"></i>
|
| 178 |
+
<p>Your cart is empty</p>
|
| 179 |
+
</div>
|
| 180 |
+
</div>
|
| 181 |
+
|
| 182 |
+
<div class="border-b border-gray-200 mb-4"></div>
|
| 183 |
+
|
| 184 |
+
<div class="mb-4">
|
| 185 |
+
<div class="flex justify-between mb-2">
|
| 186 |
+
<span class="text-gray-600">Subtotal:</span>
|
| 187 |
+
<span id="subtotal" class="font-medium">$0.00</span>
|
| 188 |
+
</div>
|
| 189 |
+
<div class="flex justify-between mb-2">
|
| 190 |
+
<span class="text-gray-600">Tax (10%):</span>
|
| 191 |
+
<span id="tax" class="font-medium">$0.00</span>
|
| 192 |
+
</div>
|
| 193 |
+
<div class="flex justify-between text-lg font-bold">
|
| 194 |
+
<span>Total:</span>
|
| 195 |
+
<span id="total" class="text-amber-600">$0.00</span>
|
| 196 |
+
</div>
|
| 197 |
+
</div>
|
| 198 |
+
|
| 199 |
+
<div class="flex space-x-2">
|
| 200 |
+
<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">
|
| 201 |
+
Clear
|
| 202 |
+
</button>
|
| 203 |
+
<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">
|
| 204 |
+
Complete Order
|
| 205 |
+
</button>
|
| 206 |
+
</div>
|
| 207 |
+
</div>
|
| 208 |
+
</div>
|
| 209 |
+
</div>
|
| 210 |
+
</div>
|
| 211 |
+
|
| 212 |
+
<!-- Menu Management Section (Hidden by default) -->
|
| 213 |
+
<div id="menuManagementSection" class="hidden">
|
| 214 |
+
<div class="bg-white rounded-lg shadow overflow-hidden">
|
| 215 |
+
<div class="px-6 py-4 border-b border-gray-200 flex justify-between items-center">
|
| 216 |
+
<h2 class="text-lg font-medium text-gray-900">Menu Management</h2>
|
| 217 |
+
<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">
|
| 218 |
+
<i class="fas fa-plus mr-2"></i>Add Item
|
| 219 |
+
</button>
|
| 220 |
+
</div>
|
| 221 |
+
<div class="overflow-x-auto">
|
| 222 |
+
<table class="min-w-full divide-y divide-gray-200">
|
| 223 |
+
<thead class="bg-gray-50">
|
| 224 |
+
<tr>
|
| 225 |
+
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Image</th>
|
| 226 |
+
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Name</th>
|
| 227 |
+
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Description</th>
|
| 228 |
+
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Price</th>
|
| 229 |
+
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
|
| 230 |
+
</tr>
|
| 231 |
+
</thead>
|
| 232 |
+
<tbody class="bg-white divide-y divide-gray-200" id="menuItemsTable">
|
| 233 |
+
<!-- Menu items will be populated here by JavaScript -->
|
| 234 |
+
</tbody>
|
| 235 |
+
</table>
|
| 236 |
+
</div>
|
| 237 |
+
</div>
|
| 238 |
+
</div>
|
| 239 |
+
|
| 240 |
+
<!-- Reports Section (Hidden by default) -->
|
| 241 |
+
<div id="reportsSection" class="hidden">
|
| 242 |
+
<div class="bg-white rounded-lg shadow p-6">
|
| 243 |
+
<h2 class="text-lg font-medium text-gray-900 mb-6">Sales Reports</h2>
|
| 244 |
+
|
| 245 |
+
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8">
|
| 246 |
+
<div class="bg-gray-50 p-4 rounded-lg">
|
| 247 |
+
<h3 class="text-md font-medium text-gray-700 mb-4">Date Range</h3>
|
| 248 |
+
<div class="flex flex-col sm:flex-row space-y-2 sm:space-y-0 sm:space-x-4">
|
| 249 |
+
<div class="flex-1">
|
| 250 |
+
<label for="startDate" class="block text-sm font-medium text-gray-700 mb-1">Start Date</label>
|
| 251 |
+
<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">
|
| 252 |
+
</div>
|
| 253 |
+
<div class="flex-1">
|
| 254 |
+
<label for="endDate" class="block text-sm font-medium text-gray-700 mb-1">End Date</label>
|
| 255 |
+
<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">
|
| 256 |
+
</div>
|
| 257 |
+
<div class="flex items-end">
|
| 258 |
+
<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">
|
| 259 |
+
Generate
|
| 260 |
+
</button>
|
| 261 |
+
</div>
|
| 262 |
+
</div>
|
| 263 |
+
</div>
|
| 264 |
+
|
| 265 |
+
<div class="grid grid-cols-3 gap-4">
|
| 266 |
+
<div class="bg-amber-50 p-4 rounded-lg text-center">
|
| 267 |
+
<p class="text-sm font-medium text-amber-700">Today's Sales</p>
|
| 268 |
+
<p class="text-2xl font-bold text-amber-600 mt-2">$<span id="todaySales">0.00</span></p>
|
| 269 |
+
</div>
|
| 270 |
+
<div class="bg-blue-50 p-4 rounded-lg text-center">
|
| 271 |
+
<p class="text-sm font-medium text-blue-700">This Week</p>
|
| 272 |
+
<p class="text-2xl font-bold text-blue-600 mt-2">$<span id="weekSales">0.00</span></p>
|
| 273 |
+
</div>
|
| 274 |
+
<div class="bg-green-50 p-4 rounded-lg text-center">
|
| 275 |
+
<p class="text-sm font-medium text-green-700">This Month</p>
|
| 276 |
+
<p class="text-2xl font-bold text-green-600 mt-2">$<span id="monthSales">0.00</span></p>
|
| 277 |
+
</div>
|
| 278 |
+
</div>
|
| 279 |
+
</div>
|
| 280 |
+
|
| 281 |
+
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-8">
|
| 282 |
+
<div class="bg-white p-4 rounded-lg border border-gray-200">
|
| 283 |
+
<h3 class="text-md font-medium text-gray-700 mb-4">Daily Sales</h3>
|
| 284 |
+
<canvas id="dailySalesChart" height="250"></canvas>
|
| 285 |
+
</div>
|
| 286 |
+
<div class="bg-white p-4 rounded-lg border border-gray-200">
|
| 287 |
+
<h3 class="text-md font-medium text-gray-700 mb-4">Top Selling Items</h3>
|
| 288 |
+
<canvas id="topItemsChart" height="250"></canvas>
|
| 289 |
+
</div>
|
| 290 |
+
</div>
|
| 291 |
+
|
| 292 |
+
<div class="bg-white p-4 rounded-lg border border-gray-200">
|
| 293 |
+
<div class="flex justify-between items-center mb-4">
|
| 294 |
+
<h3 class="text-md font-medium text-gray-700">Recent Orders</h3>
|
| 295 |
+
<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">
|
| 296 |
+
<i class="fas fa-file-export mr-1"></i>Export
|
| 297 |
+
</button>
|
| 298 |
+
</div>
|
| 299 |
+
<div class="overflow-x-auto">
|
| 300 |
+
<table class="min-w-full divide-y divide-gray-200">
|
| 301 |
+
<thead class="bg-gray-50">
|
| 302 |
+
<tr>
|
| 303 |
+
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Order #</th>
|
| 304 |
+
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Date</th>
|
| 305 |
+
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Staff</th>
|
| 306 |
+
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Amount</th>
|
| 307 |
+
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
|
| 308 |
+
</tr>
|
| 309 |
+
</thead>
|
| 310 |
+
<tbody class="bg-white divide-y divide-gray-200" id="recentOrdersTable">
|
| 311 |
+
<!-- Recent orders will be populated here by JavaScript -->
|
| 312 |
+
</tbody>
|
| 313 |
+
</table>
|
| 314 |
+
</div>
|
| 315 |
+
</div>
|
| 316 |
+
</div>
|
| 317 |
+
</div>
|
| 318 |
+
|
| 319 |
+
<!-- User Management Section (Hidden by default) -->
|
| 320 |
+
<div id="userManagementSection" class="hidden">
|
| 321 |
+
<div class="bg-white rounded-lg shadow overflow-hidden">
|
| 322 |
+
<div class="px-6 py-4 border-b border-gray-200 flex justify-between items-center">
|
| 323 |
+
<h2 class="text-lg font-medium text-gray-900">User Management</h2>
|
| 324 |
+
<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">
|
| 325 |
+
<i class="fas fa-user-plus mr-2"></i>Add User
|
| 326 |
+
</button>
|
| 327 |
+
</div>
|
| 328 |
+
<div class="overflow-x-auto">
|
| 329 |
+
<table class="min-w-full divide-y divide-gray-200">
|
| 330 |
+
<thead class="bg-gray-50">
|
| 331 |
+
<tr>
|
| 332 |
+
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Name</th>
|
| 333 |
+
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Email</th>
|
| 334 |
+
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Role</th>
|
| 335 |
+
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Last Login</th>
|
| 336 |
+
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
|
| 337 |
+
</tr>
|
| 338 |
+
</thead>
|
| 339 |
+
<tbody class="bg-white divide-y divide-gray-200" id="usersTable">
|
| 340 |
+
<!-- Users will be populated here by JavaScript -->
|
| 341 |
+
</tbody>
|
| 342 |
+
</table>
|
| 343 |
+
</div>
|
| 344 |
+
</div>
|
| 345 |
+
</div>
|
| 346 |
+
</main>
|
| 347 |
+
|
| 348 |
+
<!-- Add/Edit Menu Item Modal -->
|
| 349 |
+
<div id="menuItemModal" class="hidden fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 z-50">
|
| 350 |
+
<div class="bg-white rounded-lg p-6 w-full max-w-md">
|
| 351 |
+
<div class="flex justify-between items-center mb-4">
|
| 352 |
+
<h3 class="text-lg font-medium text-gray-900" id="menuItemModalTitle">Add Menu Item</h3>
|
| 353 |
+
<button id="closeMenuItemModal" class="text-gray-500 hover:text-gray-700">
|
| 354 |
+
<i class="fas fa-times"></i>
|
| 355 |
+
</button>
|
| 356 |
+
</div>
|
| 357 |
+
<form id="menuItemForm">
|
| 358 |
+
<input type="hidden" id="menuItemId">
|
| 359 |
+
<div class="mb-4">
|
| 360 |
+
<label for="itemName" class="block text-gray-700 text-sm font-medium mb-2">Item Name</label>
|
| 361 |
+
<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>
|
| 362 |
+
</div>
|
| 363 |
+
<div class="mb-4">
|
| 364 |
+
<label for="itemPrice" class="block text-gray-700 text-sm font-medium mb-2">Price</label>
|
| 365 |
+
<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>
|
| 366 |
+
</div>
|
| 367 |
+
<div class="mb-4">
|
| 368 |
+
<label for="itemDescription" class="block text-gray-700 text-sm font-medium mb-2">Description</label>
|
| 369 |
+
<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>
|
| 370 |
+
</div>
|
| 371 |
+
<div class="mb-4">
|
| 372 |
+
<label for="itemImage" class="block text-gray-700 text-sm font-medium mb-2">Image</label>
|
| 373 |
+
<div class="flex items-center">
|
| 374 |
+
<div class="mr-4">
|
| 375 |
+
<img id="itemImagePreview" src="https://via.placeholder.com/100x100?text=No+Image" alt="Item preview" class="w-16 h-16 rounded-md object-cover">
|
| 376 |
+
</div>
|
| 377 |
+
<div class="flex-1">
|
| 378 |
+
<input type="file" id="itemImage" class="hidden" accept="image/*">
|
| 379 |
+
<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">
|
| 380 |
+
<i class="fas fa-upload mr-2"></i>Upload Image
|
| 381 |
+
</button>
|
| 382 |
+
</div>
|
| 383 |
+
</div>
|
| 384 |
+
</div>
|
| 385 |
+
<div class="flex justify-end space-x-3">
|
| 386 |
+
<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">
|
| 387 |
+
Cancel
|
| 388 |
+
</button>
|
| 389 |
+
<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">
|
| 390 |
+
Save Item
|
| 391 |
+
</button>
|
| 392 |
+
</div>
|
| 393 |
+
</form>
|
| 394 |
+
</div>
|
| 395 |
+
</div>
|
| 396 |
+
|
| 397 |
+
<!-- Add/Edit User Modal -->
|
| 398 |
+
<div id="userModal" class="hidden fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 z-50">
|
| 399 |
+
<div class="bg-white rounded-lg p-6 w-full max-w-md">
|
| 400 |
+
<div class="flex justify-between items-center mb-4">
|
| 401 |
+
<h3 class="text-lg font-medium text-gray-900" id="userModalTitle">Add User</h3>
|
| 402 |
+
<button id="closeUserModal" class="text-gray-500 hover:text-gray-700">
|
| 403 |
+
<i class="fas fa-times"></i>
|
| 404 |
+
</button>
|
| 405 |
+
</div>
|
| 406 |
+
<form id="userForm">
|
| 407 |
+
<input type="hidden" id="userId">
|
| 408 |
+
<div class="mb-4">
|
| 409 |
+
<label for="userName" class="block text-gray-700 text-sm font-medium mb-2">Full Name</label>
|
| 410 |
+
<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>
|
| 411 |
+
</div>
|
| 412 |
+
<div class="mb-4">
|
| 413 |
+
<label for="userEmail" class="block text-gray-700 text-sm font-medium mb-2">Email</label>
|
| 414 |
+
<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>
|
| 415 |
+
</div>
|
| 416 |
+
<div class="mb-4">
|
| 417 |
+
<label for="userRole" class="block text-gray-700 text-sm font-medium mb-2">Role</label>
|
| 418 |
+
<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>
|
| 419 |
+
<option value="admin">Admin</option>
|
| 420 |
+
<option value="staff">Staff</option>
|
| 421 |
+
</select>
|
| 422 |
+
</div>
|
| 423 |
+
<div class="mb-4" id="passwordFields">
|
| 424 |
+
<label for="userPassword" class="block text-gray-700 text-sm font-medium mb-2">Password</label>
|
| 425 |
+
<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>
|
| 426 |
+
</div>
|
| 427 |
+
<div class="flex justify-end space-x-3">
|
| 428 |
+
<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">
|
| 429 |
+
Cancel
|
| 430 |
+
</button>
|
| 431 |
+
<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">
|
| 432 |
+
Save User
|
| 433 |
+
</button>
|
| 434 |
+
</div>
|
| 435 |
+
</form>
|
| 436 |
+
</div>
|
| 437 |
+
</div>
|
| 438 |
+
|
| 439 |
+
<!-- Receipt Modal -->
|
| 440 |
+
<div id="receiptModal" class="hidden fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 z-50">
|
| 441 |
+
<div class="bg-white rounded-lg p-6 w-full max-w-md">
|
| 442 |
+
<div class="flex justify-between items-center mb-4">
|
| 443 |
+
<h3 class="text-lg font-medium text-gray-900">Order Receipt</h3>
|
| 444 |
+
<div class="flex space-x-2">
|
| 445 |
+
<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">
|
| 446 |
+
<i class="fas fa-print mr-1"></i>Print
|
| 447 |
+
</button>
|
| 448 |
+
<button id="closeReceiptModal" class="text-gray-500 hover:text-gray-700">
|
| 449 |
+
<i class="fas fa-times"></i>
|
| 450 |
+
</button>
|
| 451 |
+
</div>
|
| 452 |
+
</div>
|
| 453 |
+
<div class="print-area p-4" id="receiptContent">
|
| 454 |
+
<div class="text-center mb-4">
|
| 455 |
+
<h2 class="text-xl font-bold">Burger Joint</h2>
|
| 456 |
+
<p class="text-sm text-gray-600">123 Burger Street, Foodville</p>
|
| 457 |
+
<p class="text-sm text-gray-600">Tel: (123) 456-7890</p>
|
| 458 |
+
</div>
|
| 459 |
+
<div class="border-b border-gray-300 mb-3"></div>
|
| 460 |
+
<div class="flex justify-between mb-1">
|
| 461 |
+
<span class="text-sm">Order #:</span>
|
| 462 |
+
<span class="text-sm font-medium" id="receiptOrderNumber">0000</span>
|
| 463 |
+
</div>
|
| 464 |
+
<div class="flex justify-between mb-1">
|
| 465 |
+
<span class="text-sm">Date:</span>
|
| 466 |
+
<span class="text-sm font-medium" id="receiptDate">May 15, 2023</span>
|
| 467 |
+
</div>
|
| 468 |
+
<div class="flex justify-between mb-3">
|
| 469 |
+
<span class="text-sm">Time:</span>
|
| 470 |
+
<span class="text-sm font-medium" id="receiptTime">10:30 AM</span>
|
| 471 |
+
</div>
|
| 472 |
+
<div class="border-b border-gray-300 mb-3"></div>
|
| 473 |
+
<div class="mb-3" id="receiptItems">
|
| 474 |
+
<!-- Receipt items will be populated here by JavaScript -->
|
| 475 |
+
</div>
|
| 476 |
+
<div class="border-b border-dashed border-gray-300 mb-3"></div>
|
| 477 |
+
<div class="flex justify-between mb-1">
|
| 478 |
+
<span class="text-sm">Subtotal:</span>
|
| 479 |
+
<span class="text-sm font-medium" id="receiptSubtotal">$0.00</span>
|
| 480 |
+
</div>
|
| 481 |
+
<div class="flex justify-between mb-1">
|
| 482 |
+
<span class="text-sm">Tax (10%):</span>
|
| 483 |
+
<span class="text-sm font-medium" id="receiptTax">$0.00</span>
|
| 484 |
+
</div>
|
| 485 |
+
<div class="flex justify-between mb-3 font-bold">
|
| 486 |
+
<span>Total:</span>
|
| 487 |
+
<span id="receiptTotal">$0.00</span>
|
| 488 |
+
</div>
|
| 489 |
+
<div class="border-b border-gray-300 mb-3"></div>
|
| 490 |
+
<div class="text-center text-xs text-gray-600">
|
| 491 |
+
<p>Thank you for your order!</p>
|
| 492 |
+
<p>Please visit us again</p>
|
| 493 |
+
</div>
|
| 494 |
+
</div>
|
| 495 |
+
</div>
|
| 496 |
+
</div>
|
| 497 |
+
|
| 498 |
+
<!-- Confirmation Modal -->
|
| 499 |
+
<div id="confirmationModal" class="hidden fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 z-50">
|
| 500 |
+
<div class="bg-white rounded-lg p-6 w-full max-w-sm">
|
| 501 |
+
<div class="text-center mb-4">
|
| 502 |
+
<i class="fas fa-exclamation-circle text-3xl text-amber-500 mb-3"></i>
|
| 503 |
+
<h3 class="text-lg font-medium text-gray-900" id="confirmationTitle">Confirm Action</h3>
|
| 504 |
+
<p class="text-sm text-gray-500 mt-1" id="confirmationMessage">Are you sure you want to perform this action?</p>
|
| 505 |
+
</div>
|
| 506 |
+
<div class="flex justify-center space-x-3">
|
| 507 |
+
<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">
|
| 508 |
+
Cancel
|
| 509 |
+
</button>
|
| 510 |
+
<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">
|
| 511 |
+
Confirm
|
| 512 |
+
</button>
|
| 513 |
+
</div>
|
| 514 |
+
</div>
|
| 515 |
+
</div>
|
| 516 |
+
</div>
|
| 517 |
+
|
| 518 |
+
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
| 519 |
+
<script>
|
| 520 |
+
// Database simulation
|
| 521 |
+
const database = {
|
| 522 |
+
users: [
|
| 523 |
+
{ id: 1, name: 'Admin User', email: 'admin@burgerjoint.com', password: 'admin123', role: 'admin', lastLogin: '2023-05-15 10:00' },
|
| 524 |
+
{ id: 2, name: 'Staff User', email: 'staff@burgerjoint.com', password: 'staff123', role: 'staff', lastLogin: '2023-05-15 09:30' }
|
| 525 |
+
],
|
| 526 |
+
menuItems: [
|
| 527 |
+
{ 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' },
|
| 528 |
+
{ id: 2, name: 'Cheeseburger', price: 9.99, description: 'Classic burger with a slice of American cheese', image: 'https://via.placeholder.com/300x200?text=Cheeseburger' },
|
| 529 |
+
{ 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' },
|
| 530 |
+
{ 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' },
|
| 531 |
+
{ 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' },
|
| 532 |
+
{ 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' },
|
| 533 |
+
{ 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' },
|
| 534 |
+
{ id: 8, name: 'Soda', price: 2.49, description: 'Refreshing soda in various flavors', image: 'https://via.placeholder.com/300x200?text=Soda' }
|
| 535 |
+
],
|
| 536 |
+
orders: [
|
| 537 |
+
{ id: 1001, userId: 2, totalPrice: 15.98, date: '2023-05-14', time: '12:30 PM', items: [
|
| 538 |
+
{ menuItemId: 1, quantity: 1, price: 8.99 },
|
| 539 |
+
{ menuItemId: 6, quantity: 1, price: 3.99 },
|
| 540 |
+
{ menuItemId: 8, quantity: 2, price: 2.49 }
|
| 541 |
+
]},
|
| 542 |
+
{ id: 1002, userId: 2, totalPrice: 24.97, date: '2023-05-14', time: '1:45 PM', items: [
|
| 543 |
+
{ menuItemId: 3, quantity: 2, price: 10.99 },
|
| 544 |
+
{ menuItemId: 7, quantity: 1, price: 4.99 }
|
| 545 |
+
]},
|
| 546 |
+
{ id: 1003, userId: 2, totalPrice: 18.47, date: '2023-05-15', time: '9:15 AM', items: [
|
| 547 |
+
{ menuItemId: 2, quantity: 1, price: 9.99 },
|
| 548 |
+
{ menuItemId: 5, quantity: 1, price: 7.99 },
|
| 549 |
+
{ menuItemId: 8, quantity: 1, price: 2.49 }
|
| 550 |
+
]}
|
| 551 |
+
],
|
| 552 |
+
currentOrder: {
|
| 553 |
+
id: null,
|
| 554 |
+
userId: null,
|
| 555 |
+
items: [],
|
| 556 |
+
subtotal: 0,
|
| 557 |
+
tax: 0,
|
| 558 |
+
total: 0
|
| 559 |
+
}
|
| 560 |
+
};
|
| 561 |
+
|
| 562 |
+
// App state
|
| 563 |
+
const state = {
|
| 564 |
+
currentUser: null,
|
| 565 |
+
currentTab: 'billing',
|
| 566 |
+
editingItemId: null,
|
| 567 |
+
editingUserId: null,
|
| 568 |
+
confirmationAction: null,
|
| 569 |
+
confirmationData: null
|
| 570 |
+
};
|
| 571 |
+
|
| 572 |
+
// DOM Elements
|
| 573 |
+
const elements = {
|
| 574 |
+
loginModal: document.getElementById('loginModal'),
|
| 575 |
+
appContainer: document.getElementById('appContainer'),
|
| 576 |
+
loggedInUser: document.getElementById('loggedInUser'),
|
| 577 |
+
userMenuButton: document.getElementById('userMenuButton'),
|
| 578 |
+
userMenu: document.getElementById('userMenu'),
|
| 579 |
+
logoutButton: document.getElementById('logoutButton'),
|
| 580 |
+
currentTime: document.getElementById('currentTime'),
|
| 581 |
+
|
| 582 |
+
// Tabs
|
| 583 |
+
billingTab: document.getElementById('billingTab'),
|
| 584 |
+
menuTab: document.getElementById('menuTab'),
|
| 585 |
+
reportsTab: document.getElementById('reportsTab'),
|
| 586 |
+
usersTab: document.getElementById('usersTab'),
|
| 587 |
+
|
| 588 |
+
// Sections
|
| 589 |
+
billingSection: document.getElementById('billingSection'),
|
| 590 |
+
menuManagementSection: document.getElementById('menuManagementSection'),
|
| 591 |
+
reportsSection: document.getElementById('reportsSection'),
|
| 592 |
+
userManagementSection: document.getElementById('userManagementSection'),
|
| 593 |
+
|
| 594 |
+
// Billing section
|
| 595 |
+
menuItemsContainer: document.getElementById('menuItemsContainer'),
|
| 596 |
+
menuSearch: document.getElementById('menuSearch'),
|
| 597 |
+
orderItemsContainer: document.getElementById('orderItemsContainer'),
|
| 598 |
+
orderNumber: document.getElementById('orderNumber'),
|
| 599 |
+
staffName: document.getElementById('staffName'),
|
| 600 |
+
orderDate: document.getElementById('orderDate'),
|
| 601 |
+
orderTime: document.getElementById('orderTime'),
|
| 602 |
+
subtotal: document.getElementById('subtotal'),
|
| 603 |
+
tax: document.getElementById('tax'),
|
| 604 |
+
total: document.getElementById('total'),
|
| 605 |
+
clearOrderBtn: document.getElementById('clearOrderBtn'),
|
| 606 |
+
completeOrderBtn: document.getElementById('completeOrderBtn'),
|
| 607 |
+
|
| 608 |
+
// Menu management
|
| 609 |
+
menuItemsTable: document.getElementById('menuItemsTable'),
|
| 610 |
+
addMenuItemBtn: document.getElementById('addMenuItemBtn'),
|
| 611 |
+
|
| 612 |
+
// Reports
|
| 613 |
+
startDate: document.getElementById('startDate'),
|
| 614 |
+
endDate: document.getElementById('endDate'),
|
| 615 |
+
generateReportBtn: document.getElementById('generateReportBtn'),
|
| 616 |
+
todaySales: document.getElementById('todaySales'),
|
| 617 |
+
weekSales: document.getElementById('weekSales'),
|
| 618 |
+
monthSales: document.getElementById('monthSales'),
|
| 619 |
+
dailySalesChart: document.getElementById('dailySalesChart'),
|
| 620 |
+
topItemsChart: document.getElementById('topItemsChart'),
|
| 621 |
+
recentOrdersTable: document.getElementById('recentOrdersTable'),
|
| 622 |
+
exportReportBtn: document.getElementById('exportReportBtn'),
|
| 623 |
+
|
| 624 |
+
// User management
|
| 625 |
+
usersTable: document.getElementById('usersTable'),
|
| 626 |
+
addUserBtn: document.getElementById('addUserBtn'),
|
| 627 |
+
|
| 628 |
+
// Modals
|
| 629 |
+
menuItemModal: document.getElementById('menuItemModal'),
|
| 630 |
+
menuItemModalTitle: document.getElementById('menuItemModalTitle'),
|
| 631 |
+
menuItemForm: document.getElementById('menuItemForm'),
|
| 632 |
+
menuItemId: document.getElementById('menuItemId'),
|
| 633 |
+
itemName: document.getElementById('itemName'),
|
| 634 |
+
itemPrice: document.getElementById('itemPrice'),
|
| 635 |
+
itemDescription: document.getElementById('itemDescription'),
|
| 636 |
+
itemImage: document.getElementById('itemImage'),
|
| 637 |
+
itemImagePreview: document.getElementById('itemImagePreview'),
|
| 638 |
+
uploadImageBtn: document.getElementById('uploadImageBtn'),
|
| 639 |
+
cancelMenuItemBtn: document.getElementById('cancelMenuItemBtn'),
|
| 640 |
+
closeMenuItemModal: document.getElementById('closeMenuItemModal'),
|
| 641 |
+
|
| 642 |
+
userModal: document.getElementById('userModal'),
|
| 643 |
+
userModalTitle: document.getElementById('userModalTitle'),
|
| 644 |
+
userForm: document.getElementById('userForm'),
|
| 645 |
+
userId: document.getElementById('userId'),
|
| 646 |
+
userName: document.getElementById('userName'),
|
| 647 |
+
userEmail: document.getElementById('userEmail'),
|
| 648 |
+
userRole: document.getElementById('userRole'),
|
| 649 |
+
userPassword: document.getElementById('userPassword'),
|
| 650 |
+
passwordFields: document.getElementById('passwordFields'),
|
| 651 |
+
cancelUserBtn: document.getElementById('cancelUserBtn'),
|
| 652 |
+
closeUserModal: document.getElementById('closeUserModal'),
|
| 653 |
+
|
| 654 |
+
receiptModal: document.getElementById('receiptModal'),
|
| 655 |
+
receiptContent: document.getElementById('receiptContent'),
|
| 656 |
+
receiptOrderNumber: document.getElementById('receiptOrderNumber'),
|
| 657 |
+
receiptDate: document.getElementById('receiptDate'),
|
| 658 |
+
receiptTime: document.getElementById('receiptTime'),
|
| 659 |
+
receiptItems: document.getElementById('receiptItems'),
|
| 660 |
+
receiptSubtotal: document.getElementById('receiptSubtotal'),
|
| 661 |
+
receiptTax: document.getElementById('receiptTax'),
|
| 662 |
+
receiptTotal: document.getElementById('receiptTotal'),
|
| 663 |
+
printReceiptBtn: document.getElementById('printReceiptBtn'),
|
| 664 |
+
closeReceiptModal: document.getElementById('closeReceiptModal'),
|
| 665 |
+
|
| 666 |
+
confirmationModal: document.getElementById('confirmationModal'),
|
| 667 |
+
confirmationTitle: document.getElementById('confirmationTitle'),
|
| 668 |
+
confirmationMessage: document.getElementById('confirmationMessage'),
|
| 669 |
+
cancelConfirmBtn: document.getElementById('cancelConfirmBtn'),
|
| 670 |
+
confirmActionBtn: document.getElementById('confirmActionBtn'),
|
| 671 |
+
|
| 672 |
+
// Forms
|
| 673 |
+
loginForm: document.getElementById('loginForm'),
|
| 674 |
+
username: document.getElementById('username'),
|
| 675 |
+
password: document.getElementById('password')
|
| 676 |
+
};
|
| 677 |
+
|
| 678 |
+
// Initialize the app
|
| 679 |
+
function init() {
|
| 680 |
+
// Set current date for date inputs
|
| 681 |
+
const today = new Date().toISOString().split('T')[0];
|
| 682 |
+
elements.startDate.value = today;
|
| 683 |
+
elements.endDate.value = today;
|
| 684 |
+
|
| 685 |
+
// Update clock
|
| 686 |
+
updateClock();
|
| 687 |
+
setInterval(updateClock, 1000);
|
| 688 |
+
|
| 689 |
+
// Generate a random order number
|
| 690 |
+
generateOrderNumber();
|
| 691 |
+
|
| 692 |
+
// Set current date in order summary
|
| 693 |
+
const now = new Date();
|
| 694 |
+
elements.orderDate.textContent = now.toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' });
|
| 695 |
+
elements.orderTime.textContent = now.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' });
|
| 696 |
+
|
| 697 |
+
// Event listeners
|
| 698 |
+
setupEventListeners();
|
| 699 |
+
|
| 700 |
+
// Show login modal by default
|
| 701 |
+
elements.loginModal.classList.remove('hidden');
|
| 702 |
+
}
|
| 703 |
+
|
| 704 |
+
// Update clock
|
| 705 |
+
function updateClock() {
|
| 706 |
+
const now = new Date();
|
| 707 |
+
elements.currentTime.textContent = now.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', second: '2-digit' });
|
| 708 |
+
}
|
| 709 |
+
|
| 710 |
+
// Generate a random order number
|
| 711 |
+
function generateOrderNumber() {
|
| 712 |
+
const orderNumber = Math.floor(1000 + Math.random() * 9000);
|
| 713 |
+
database.currentOrder.id = orderNumber;
|
| 714 |
+
elements.orderNumber.textContent = `Order #${orderNumber}`;
|
| 715 |
+
elements.receiptOrderNumber.textContent = orderNumber;
|
| 716 |
+
}
|
| 717 |
+
|
| 718 |
+
// Setup event listeners
|
| 719 |
+
function setupEventListeners() {
|
| 720 |
+
// Login form
|
| 721 |
+
elements.loginForm.addEventListener('submit', handleLogin);
|
| 722 |
+
|
| 723 |
+
// Logout button
|
| 724 |
+
elements.logoutButton.addEventListener('click', handleLogout);
|
| 725 |
+
|
| 726 |
+
// User menu toggle
|
| 727 |
+
elements.userMenuButton.addEventListener('click', () => {
|
| 728 |
+
elements.userMenu.classList.toggle('hidden');
|
| 729 |
+
});
|
| 730 |
+
|
| 731 |
+
// Tab navigation
|
| 732 |
+
elements.billingTab.addEventListener('click', () => switchTab('billing'));
|
| 733 |
+
elements.menuTab.addEventListener('click', () => switchTab('menu'));
|
| 734 |
+
elements.reportsTab.addEventListener('click', () => switchTab('reports'));
|
| 735 |
+
elements.usersTab.addEventListener('click', () => switchTab('users'));
|
| 736 |
+
|
| 737 |
+
// Menu search
|
| 738 |
+
elements.menuSearch.addEventListener('input', filterMenuItems);
|
| 739 |
+
|
| 740 |
+
// Order buttons
|
| 741 |
+
elements.clearOrderBtn.addEventListener('click', clearOrder);
|
| 742 |
+
elements.completeOrderBtn.addEventListener('click', completeOrder);
|
| 743 |
+
|
| 744 |
+
// Menu item modal
|
| 745 |
+
elements.addMenuItemBtn.addEventListener('click', () => openMenuItemModal(null));
|
| 746 |
+
elements.uploadImageBtn.addEventListener('click', () => elements.itemImage.click());
|
| 747 |
+
elements.itemImage.addEventListener('change', handleImageUpload);
|
| 748 |
+
elements.cancelMenuItemBtn.addEventListener('click', closeMenuItemModal);
|
| 749 |
+
elements.closeMenuItemModal.addEventListener('click', closeMenuItemModal);
|
| 750 |
+
elements.menuItemForm.addEventListener('submit', saveMenuItem);
|
| 751 |
+
|
| 752 |
+
// User modal
|
| 753 |
+
elements.addUserBtn.addEventListener('click', () => openUserModal(null));
|
| 754 |
+
elements.cancelUserBtn.addEventListener('click', closeUserModal);
|
| 755 |
+
elements.closeUserModal.addEventListener('click', closeUserModal);
|
| 756 |
+
elements.userForm.addEventListener('submit', saveUser);
|
| 757 |
+
|
| 758 |
+
// Receipt modal
|
| 759 |
+
elements.printReceiptBtn.addEventListener('click', printReceipt);
|
| 760 |
+
elements.closeReceiptModal.addEventListener('click', () => {
|
| 761 |
+
elements.receiptModal.classList.add('hidden');
|
| 762 |
+
});
|
| 763 |
+
|
| 764 |
+
// Confirmation modal
|
| 765 |
+
elements.cancelConfirmBtn.addEventListener('click', () => {
|
| 766 |
+
elements.confirmationModal.classList.add('hidden');
|
| 767 |
+
});
|
| 768 |
+
elements.confirmActionBtn.addEventListener('click', confirmAction);
|
| 769 |
+
|
| 770 |
+
// Generate report
|
| 771 |
+
elements.generateReportBtn.addEventListener('click', generateReport);
|
| 772 |
+
elements.exportReportBtn.addEventListener('click', exportReport);
|
| 773 |
+
}
|
| 774 |
+
|
| 775 |
+
// Handle login
|
| 776 |
+
function handleLogin(e) {
|
| 777 |
+
e.preventDefault();
|
| 778 |
+
|
| 779 |
+
const username = elements.username.value;
|
| 780 |
+
const password = elements.password.value;
|
| 781 |
+
|
| 782 |
+
// Find user in database
|
| 783 |
+
const user = database.users.find(u =>
|
| 784 |
+
(u.email === username || u.name === username) && u.password === password
|
| 785 |
+
);
|
| 786 |
+
|
| 787 |
+
if (user) {
|
| 788 |
+
// Successful login
|
| 789 |
+
state.currentUser = user;
|
| 790 |
+
elements.loggedInUser.textContent = user.name;
|
| 791 |
+
|
| 792 |
+
// Hide login modal and show app
|
| 793 |
+
elements.loginModal.classList.add('hidden');
|
| 794 |
+
elements.appContainer.classList.remove('hidden');
|
| 795 |
+
|
| 796 |
+
// Load appropriate content based on role
|
| 797 |
+
if (user.role === 'admin') {
|
| 798 |
+
loadMenuItemsTable();
|
| 799 |
+
loadUsersTable();
|
| 800 |
+
loadReports();
|
| 801 |
+
} else {
|
| 802 |
+
// Staff can only see billing
|
| 803 |
+
elements.menuTab.classList.add('hidden');
|
| 804 |
+
elements.reportsTab.classList.add('hidden');
|
| 805 |
+
elements.usersTab.classList.add('hidden');
|
| 806 |
+
}
|
| 807 |
+
|
| 808 |
+
// Load menu items for billing
|
| 809 |
+
loadMenuItems();
|
| 810 |
+
|
| 811 |
+
// Set staff name in order summary
|
| 812 |
+
elements.staffName.textContent = user.name;
|
| 813 |
+
} else {
|
| 814 |
+
// Failed login
|
| 815 |
+
alert('Invalid username or password');
|
| 816 |
+
}
|
| 817 |
+
}
|
| 818 |
+
|
| 819 |
+
// Handle logout
|
| 820 |
+
function handleLogout() {
|
| 821 |
+
state.currentUser = null;
|
| 822 |
+
elements.appContainer.classList.add('hidden');
|
| 823 |
+
elements.loginModal.classList.remove('hidden');
|
| 824 |
+
elements.username.value = '';
|
| 825 |
+
elements.password.value = '';
|
| 826 |
+
elements.userMenu.classList.add('hidden');
|
| 827 |
+
}
|
| 828 |
+
|
| 829 |
+
// Switch between tabs
|
| 830 |
+
function switchTab(tab) {
|
| 831 |
+
state.currentTab = tab;
|
| 832 |
+
|
| 833 |
+
// Update tab styling
|
| 834 |
+
elements.billingTab.classList.remove('tab-active');
|
| 835 |
+
elements.menuTab.classList.remove('tab-active');
|
| 836 |
+
elements.reportsTab.classList.remove('tab-active');
|
| 837 |
+
elements.usersTab.classList.remove('tab-active');
|
| 838 |
+
|
| 839 |
+
// Hide all sections
|
| 840 |
+
elements.billingSection.classList.add('hidden');
|
| 841 |
+
elements.menuManagementSection.classList.add('hidden');
|
| 842 |
+
elements.reportsSection.classList.add('hidden');
|
| 843 |
+
elements.userManagementSection.classList.add('hidden');
|
| 844 |
+
|
| 845 |
+
// Show selected tab and section
|
| 846 |
+
switch (tab) {
|
| 847 |
+
case 'billing':
|
| 848 |
+
elements.billingTab.classList.add('tab-active');
|
| 849 |
+
elements.billingSection.classList.remove('hidden');
|
| 850 |
+
break;
|
| 851 |
+
case 'menu':
|
| 852 |
+
elements.menuTab.classList.add('tab-active');
|
| 853 |
+
elements.menuManagementSection.classList.remove('hidden');
|
| 854 |
+
break;
|
| 855 |
+
case 'reports':
|
| 856 |
+
elements.reportsTab.classList.add('tab-active');
|
| 857 |
+
elements.reportsSection.classList.remove('hidden');
|
| 858 |
+
break;
|
| 859 |
+
case 'users':
|
| 860 |
+
elements.usersTab.classList.add('tab-active');
|
| 861 |
+
elements.userManagementSection.classList.remove('hidden');
|
| 862 |
+
break;
|
| 863 |
+
}
|
| 864 |
+
}
|
| 865 |
+
|
| 866 |
+
// Load menu items for billing
|
| 867 |
+
function loadMenuItems() {
|
| 868 |
+
elements.menuItemsContainer.innerHTML = '';
|
| 869 |
+
|
| 870 |
+
database.menuItems.forEach(item => {
|
| 871 |
+
const menuItem = document.createElement('div');
|
| 872 |
+
menuItem.className = 'menu-item bg-white rounded-lg shadow overflow-hidden cursor-pointer';
|
| 873 |
+
menuItem.innerHTML = `
|
| 874 |
+
<div class="h-32 bg-gray-200 overflow-hidden">
|
| 875 |
+
<img src="${item.image}" alt="${item.name}" class="w-full h-full object-cover">
|
| 876 |
+
</div>
|
| 877 |
+
<div class="p-3">
|
| 878 |
+
<h3 class="font-medium text-gray-900 truncate">${item.name}</h3>
|
| 879 |
+
<p class="text-sm text-gray-500 mb-2 truncate">${item.description}</p>
|
| 880 |
+
<div class="flex justify-between items-center">
|
| 881 |
+
<span class="font-bold text-amber-600">$${item.price.toFixed(2)}</span>
|
| 882 |
+
<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">
|
| 883 |
+
<i class="fas fa-plus"></i>
|
| 884 |
+
</button>
|
| 885 |
+
</div>
|
| 886 |
+
</div>
|
| 887 |
+
`;
|
| 888 |
+
|
| 889 |
+
// Add event listener to the add to cart button
|
| 890 |
+
const addToCartBtn = menuItem.querySelector('.add-to-cart');
|
| 891 |
+
addToCartBtn.addEventListener('click', (e) => {
|
| 892 |
+
e.stopPropagation();
|
| 893 |
+
addToCart(item);
|
| 894 |
+
});
|
| 895 |
+
|
| 896 |
+
elements.menuItemsContainer.appendChild(menuItem);
|
| 897 |
+
});
|
| 898 |
+
}
|
| 899 |
+
|
| 900 |
+
// Filter menu items based on search input
|
| 901 |
+
function filterMenuItems() {
|
| 902 |
+
const searchTerm = elements.menuSearch.value.toLowerCase();
|
| 903 |
+
const menuItems = document.querySelectorAll('.menu-item');
|
| 904 |
+
|
| 905 |
+
menuItems.forEach(item => {
|
| 906 |
+
const name = item.querySelector('h3').textContent.toLowerCase();
|
| 907 |
+
const description = item.querySelector('p').textContent.toLowerCase();
|
| 908 |
+
|
| 909 |
+
if (name.includes(searchTerm) || description.includes(searchTerm)) {
|
| 910 |
+
item.classList.remove('hidden');
|
| 911 |
+
} else {
|
| 912 |
+
item.classList.add('hidden');
|
| 913 |
+
}
|
| 914 |
+
});
|
| 915 |
+
}
|
| 916 |
+
|
| 917 |
+
// Add item to cart
|
| 918 |
+
function addToCart(item) {
|
| 919 |
+
// Check if item already exists in cart
|
| 920 |
+
const existingItem = database.currentOrder.items.find(i => i.menuItemId === item.id);
|
| 921 |
+
|
| 922 |
+
if (existingItem) {
|
| 923 |
+
existingItem.quantity += 1;
|
| 924 |
+
} else {
|
| 925 |
+
database.currentOrder.items.push({
|
| 926 |
+
menuItemId: item.id,
|
| 927 |
+
quantity: 1,
|
| 928 |
+
price: item.price
|
| 929 |
+
});
|
| 930 |
+
}
|
| 931 |
+
|
| 932 |
+
// Update order summary
|
| 933 |
+
updateOrderSummary();
|
| 934 |
+
}
|
| 935 |
+
|
| 936 |
+
// Update order summary
|
| 937 |
+
function updateOrderSummary() {
|
| 938 |
+
// Clear current items
|
| 939 |
+
elements.orderItemsContainer.innerHTML = '';
|
| 940 |
+
|
| 941 |
+
if (database.currentOrder.items.length === 0) {
|
| 942 |
+
elements.orderItemsContainer.innerHTML = `
|
| 943 |
+
<div class="text-center text-gray-500 py-4">
|
| 944 |
+
<i class="fas fa-shopping-cart text-2xl mb-2"></i>
|
| 945 |
+
<p>Your cart is empty</p>
|
| 946 |
+
</div>
|
| 947 |
+
`;
|
| 948 |
+
|
| 949 |
+
// Update totals
|
| 950 |
+
elements.subtotal.textContent = '$0.00';
|
| 951 |
+
elements.tax.textContent = '$0.00';
|
| 952 |
+
elements.total.textContent = '$0.00';
|
| 953 |
+
|
| 954 |
+
return;
|
| 955 |
+
}
|
| 956 |
+
|
| 957 |
+
// Calculate totals
|
| 958 |
+
let subtotal = 0;
|
| 959 |
+
|
| 960 |
+
// Add each item to the order summary
|
| 961 |
+
database.currentOrder.items.forEach(item => {
|
| 962 |
+
const menuItem = database.menuItems.find(m => m.id === item.menuItemId);
|
| 963 |
+
const itemTotal = item.quantity * item.price;
|
| 964 |
+
subtotal += itemTotal;
|
| 965 |
+
|
| 966 |
+
const orderItem = document.createElement('div');
|
| 967 |
+
orderItem.className = 'flex justify-between items-center py-2 border-b border-gray-100';
|
| 968 |
+
orderItem.innerHTML = `
|
| 969 |
+
<div class="flex-1">
|
| 970 |
+
<h4 class="text-sm font-medium">${menuItem.name}</h4>
|
| 971 |
+
<p class="text-xs text-gray-500">$${item.price.toFixed(2)} x ${item.quantity}</p>
|
| 972 |
+
</div>
|
| 973 |
+
<div class="flex items-center">
|
| 974 |
+
<span class="text-sm font-medium mr-3">$${itemTotal.toFixed(2)}</span>
|
| 975 |
+
<div class="flex items-center space-x-1">
|
| 976 |
+
<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">
|
| 977 |
+
<i class="fas fa-minus"></i>
|
| 978 |
+
</button>
|
| 979 |
+
<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">
|
| 980 |
+
<i class="fas fa-plus"></i>
|
| 981 |
+
</button>
|
| 982 |
+
<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">
|
| 983 |
+
<i class="fas fa-times"></i>
|
| 984 |
+
</button>
|
| 985 |
+
</div>
|
| 986 |
+
</div>
|
| 987 |
+
`;
|
| 988 |
+
|
| 989 |
+
// Add event listeners to quantity buttons
|
| 990 |
+
const decreaseBtn = orderItem.querySelector('.decrease-quantity');
|
| 991 |
+
const increaseBtn = orderItem.querySelector('.increase-quantity');
|
| 992 |
+
const removeBtn = orderItem.querySelector('.remove-item');
|
| 993 |
+
|
| 994 |
+
decreaseBtn.addEventListener('click', () => updateQuantity(item.menuItemId, -1));
|
| 995 |
+
increaseBtn.addEventListener('click', () => updateQuantity(item.menuItemId, 1));
|
| 996 |
+
removeBtn.addEventListener('click', () => removeItem(item.menuItemId));
|
| 997 |
+
|
| 998 |
+
elements.orderItemsContainer.appendChild(orderItem);
|
| 999 |
+
});
|
| 1000 |
+
|
| 1001 |
+
// Calculate tax and total
|
| 1002 |
+
const tax = subtotal * 0.10; // 10% tax
|
| 1003 |
+
const total = subtotal + tax;
|
| 1004 |
+
|
| 1005 |
+
// Update totals in UI
|
| 1006 |
+
elements.subtotal.textContent = `$${subtotal.toFixed(2)}`;
|
| 1007 |
+
elements.tax.textContent = `$${tax.toFixed(2)}`;
|
| 1008 |
+
elements.total.textContent = `$${total.toFixed(2)}`;
|
| 1009 |
+
|
| 1010 |
+
// Update totals in database
|
| 1011 |
+
database.currentOrder.subtotal = subtotal;
|
| 1012 |
+
database.currentOrder.tax = tax;
|
| 1013 |
+
database.currentOrder.total = total;
|
| 1014 |
+
}
|
| 1015 |
+
|
| 1016 |
+
// Update item quantity
|
| 1017 |
+
function updateQuantity(menuItemId, change) {
|
| 1018 |
+
const item = database.currentOrder.items.find(i => i.menuItemId === menuItemId);
|
| 1019 |
+
|
| 1020 |
+
if (item) {
|
| 1021 |
+
item.quantity += change;
|
| 1022 |
+
|
| 1023 |
+
// Remove item if quantity reaches zero
|
| 1024 |
+
if (item.quantity <= 0) {
|
| 1025 |
+
database.currentOrder.items = database.currentOrder.items.filter(i => i.menuItemId !== menuItemId);
|
| 1026 |
+
}
|
| 1027 |
+
|
| 1028 |
+
// Update order summary
|
| 1029 |
+
updateOrderSummary();
|
| 1030 |
+
}
|
| 1031 |
+
}
|
| 1032 |
+
|
| 1033 |
+
// Remove item from cart
|
| 1034 |
+
function removeItem(menuItemId) {
|
| 1035 |
+
database.currentOrder.items = database.currentOrder.items.filter(i => i.menuItemId !== menuItemId);
|
| 1036 |
+
updateOrderSummary();
|
| 1037 |
+
}
|
| 1038 |
+
|
| 1039 |
+
// Clear current order
|
| 1040 |
+
function clearOrder() {
|
| 1041 |
+
database.currentOrder.items = [];
|
| 1042 |
+
updateOrderSummary();
|
| 1043 |
+
}
|
| 1044 |
+
|
| 1045 |
+
// Complete order and generate receipt
|
| 1046 |
+
function completeOrder() {
|
| 1047 |
+
if (database.currentOrder.items.length === 0) {
|
| 1048 |
+
alert('Cannot complete an empty order');
|
| 1049 |
+
return;
|
| 1050 |
+
}
|
| 1051 |
+
|
| 1052 |
+
// Set user ID for the order
|
| 1053 |
+
database.currentOrder.userId = state.currentUser.id;
|
| 1054 |
+
|
| 1055 |
+
// Add current order to orders history
|
| 1056 |
+
const now = new Date();
|
| 1057 |
+
const newOrder = {
|
| 1058 |
+
id: database.currentOrder.id,
|
| 1059 |
+
userId: database.currentOrder.userId,
|
| 1060 |
+
totalPrice: database.currentOrder.total,
|
| 1061 |
+
date: now.toISOString().split('T')[0],
|
| 1062 |
+
time: now.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' }),
|
| 1063 |
+
items: [...database.currentOrder.items]
|
| 1064 |
+
};
|
| 1065 |
+
|
| 1066 |
+
database.orders.push(newOrder);
|
| 1067 |
+
|
| 1068 |
+
// Generate receipt
|
| 1069 |
+
generateReceipt();
|
| 1070 |
+
|
| 1071 |
+
// Clear current order and generate a new order number
|
| 1072 |
+
clearOrder();
|
| 1073 |
+
generateOrderNumber();
|
| 1074 |
+
}
|
| 1075 |
+
|
| 1076 |
+
// Generate receipt
|
| 1077 |
+
function generateReceipt() {
|
| 1078 |
+
// Update receipt details
|
| 1079 |
+
const now = new Date();
|
| 1080 |
+
elements.receiptDate.textContent = now.toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' });
|
| 1081 |
+
elements.receiptTime.textContent = now.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' });
|
| 1082 |
+
|
| 1083 |
+
// Clear previous items
|
| 1084 |
+
elements.receiptItems.innerHTML = '';
|
| 1085 |
+
|
| 1086 |
+
// Add items to receipt
|
| 1087 |
+
database.currentOrder.items.forEach(item => {
|
| 1088 |
+
const menuItem = database.menuItems.find(m => m.id === item.menuItemId);
|
| 1089 |
+
const itemTotal = item.quantity * item.price;
|
| 1090 |
+
|
| 1091 |
+
const receiptItem = document.createElement('div');
|
| 1092 |
+
receiptItem.className = 'flex justify-between py-1';
|
| 1093 |
+
receiptItem.innerHTML = `
|
| 1094 |
+
<div>
|
| 1095 |
+
<span class="text-sm font-medium">${menuItem.name}</span>
|
| 1096 |
+
<span class="text-xs text-gray-500 block">$${item.price.toFixed(2)} x ${item.quantity}</span>
|
| 1097 |
+
</div>
|
| 1098 |
+
<span class="text-sm font-medium">$${itemTotal.toFixed(2)}</span>
|
| 1099 |
+
`;
|
| 1100 |
+
|
| 1101 |
+
elements.receiptItems.appendChild(receiptItem);
|
| 1102 |
+
});
|
| 1103 |
+
|
| 1104 |
+
// Update totals
|
| 1105 |
+
elements.receiptSubtotal.textContent = `$${database.currentOrder.subtotal.toFixed(2)}`;
|
| 1106 |
+
elements.receiptTax.textContent = `$${database.currentOrder.tax.toFixed(2)}`;
|
| 1107 |
+
elements.receiptTotal.textContent = `$${database.currentOrder.total.toFixed(2)}`;
|
| 1108 |
+
|
| 1109 |
+
// Show receipt modal
|
| 1110 |
+
elements.receiptModal.classList.remove('hidden');
|
| 1111 |
+
}
|
| 1112 |
+
|
| 1113 |
+
// Print receipt
|
| 1114 |
+
function printReceipt() {
|
| 1115 |
+
const printContents = elements.receiptContent.innerHTML;
|
| 1116 |
+
const originalContents = document.body.innerHTML;
|
| 1117 |
+
|
| 1118 |
+
document.body.innerHTML = printContents;
|
| 1119 |
+
window.print();
|
| 1120 |
+
document.body.innerHTML = originalContents;
|
| 1121 |
+
|
| 1122 |
+
// Reattach event listeners
|
| 1123 |
+
setupEventListeners();
|
| 1124 |
+
}
|
| 1125 |
+
|
| 1126 |
+
// Load menu items for management table
|
| 1127 |
+
function loadMenuItemsTable() {
|
| 1128 |
+
elements.menuItemsTable.innerHTML = '';
|
| 1129 |
+
|
| 1130 |
+
database.menuItems.forEach(item => {
|
| 1131 |
+
const row = document.createElement('tr');
|
| 1132 |
+
row.innerHTML = `
|
| 1133 |
+
<td class="px-6 py-4 whitespace-nowrap">
|
| 1134 |
+
<div class="flex-shrink-0 h-10 w-10">
|
| 1135 |
+
<img class="h-10 w-10 rounded-md object-cover" src="${item.image}" alt="${item.name}">
|
| 1136 |
+
</div>
|
| 1137 |
+
</td>
|
| 1138 |
+
<td class="px-6 py-4 whitespace-nowrap">
|
| 1139 |
+
<div class="text-sm font-medium text-gray-900">${item.name}</div>
|
| 1140 |
+
</td>
|
| 1141 |
+
<td class="px-6 py-4">
|
| 1142 |
+
<div class="text-sm text-gray-500 max-w-xs truncate">${item.description}</div>
|
| 1143 |
+
</td>
|
| 1144 |
+
<td class="px-6 py-4 whitespace-nowrap">
|
| 1145 |
+
<div class="text-sm text-gray-900">$${item.price.toFixed(2)}</div>
|
| 1146 |
+
</td>
|
| 1147 |
+
<td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
|
| 1148 |
+
<button class="edit-menu-item text-amber-600 hover:text-amber-900 mr-3" data-id="${item.id}">
|
| 1149 |
+
<i class="fas fa-edit"></i>
|
| 1150 |
+
</button>
|
| 1151 |
+
<button class="delete-menu-item text-red-600 hover:text-red-900" data-id="${item.id}">
|
| 1152 |
+
<i class="fas fa-trash"></i>
|
| 1153 |
+
</button>
|
| 1154 |
+
</td>
|
| 1155 |
+
`;
|
| 1156 |
+
|
| 1157 |
+
// Add event listeners to edit and delete buttons
|
| 1158 |
+
const editBtn = row.querySelector('.edit-menu-item');
|
| 1159 |
+
const deleteBtn = row.querySelector('.delete-menu-item');
|
| 1160 |
+
|
| 1161 |
+
editBtn.addEventListener('click', () => openMenuItemModal(item.id));
|
| 1162 |
+
deleteBtn.addEventListener('click', () => confirmDeleteMenuItem(item.id));
|
| 1163 |
+
|
| 1164 |
+
elements.menuItemsTable.appendChild(row);
|
| 1165 |
+
});
|
| 1166 |
+
}
|
| 1167 |
+
|
| 1168 |
+
// Open menu item modal for adding/editing
|
| 1169 |
+
function openMenuItemModal(itemId) {
|
| 1170 |
+
if (itemId) {
|
| 1171 |
+
// Editing existing item
|
| 1172 |
+
state.editingItemId = itemId;
|
| 1173 |
+
const item = database.menuItems.find(i => i.id === itemId);
|
| 1174 |
+
|
| 1175 |
+
elements.menuItemModalTitle.textContent = 'Edit Menu Item';
|
| 1176 |
+
elements.menuItemId.value = itemId;
|
| 1177 |
+
elements.itemName.value = item.name;
|
| 1178 |
+
elements.itemPrice.value = item.price;
|
| 1179 |
+
elements.itemDescription.value = item.description;
|
| 1180 |
+
elements.itemImagePreview.src = item.image;
|
| 1181 |
+
} else {
|
| 1182 |
+
// Adding new item
|
| 1183 |
+
state.editingItemId = null;
|
| 1184 |
+
elements.menuItemModalTitle.textContent = 'Add Menu Item';
|
| 1185 |
+
elements.menuItemId.value = '';
|
| 1186 |
+
elements.itemName.value = '';
|
| 1187 |
+
elements.itemPrice.value = '';
|
| 1188 |
+
elements.itemDescription.value = '';
|
| 1189 |
+
elements.itemImagePreview.src = 'https://via.placeholder.com/100x100?text=No+Image';
|
| 1190 |
+
}
|
| 1191 |
+
|
| 1192 |
+
elements.menuItemModal.classList.remove('hidden');
|
| 1193 |
+
}
|
| 1194 |
+
|
| 1195 |
+
// Close menu item modal
|
| 1196 |
+
function closeMenuItemModal() {
|
| 1197 |
+
elements.menuItemModal.classList.add('hidden');
|
| 1198 |
+
}
|
| 1199 |
+
|
| 1200 |
+
// Handle image upload
|
| 1201 |
+
function handleImageUpload(e) {
|
| 1202 |
+
const file = e.target.files[0];
|
| 1203 |
+
if (file) {
|
| 1204 |
+
const reader = new FileReader();
|
| 1205 |
+
reader.onload = function(event) {
|
| 1206 |
+
elements.itemImagePreview.src = event.target.result;
|
| 1207 |
+
};
|
| 1208 |
+
reader.readAsDataURL(file);
|
| 1209 |
+
}
|
| 1210 |
+
}
|
| 1211 |
+
|
| 1212 |
+
// Save menu item (add or update)
|
| 1213 |
+
function saveMenuItem(e) {
|
| 1214 |
+
e.preventDefault();
|
| 1215 |
+
|
| 1216 |
+
const itemId = parseInt(elements.menuItemId.value);
|
| 1217 |
+
const name = elements.itemName.value;
|
| 1218 |
+
const price = parseFloat(elements.itemPrice.value);
|
| 1219 |
+
const description = elements.itemDescription.value;
|
| 1220 |
+
const image = elements.itemImagePreview.src;
|
| 1221 |
+
|
| 1222 |
+
if (itemId) {
|
| 1223 |
+
// Update existing item
|
| 1224 |
+
const index = database.menuItems.findIndex(i => i.id === itemId);
|
| 1225 |
+
if (index !== -1) {
|
| 1226 |
+
database.menuItems[index] = {
|
| 1227 |
+
id: itemId,
|
| 1228 |
+
name,
|
| 1229 |
+
price,
|
| 1230 |
+
description,
|
| 1231 |
+
image
|
| 1232 |
+
};
|
| 1233 |
+
}
|
| 1234 |
+
} else {
|
| 1235 |
+
// Add new item
|
| 1236 |
+
const newId = database.menuItems.length > 0 ?
|
| 1237 |
+
Math.max(...database.menuItems.map(i => i.id)) + 1 : 1;
|
| 1238 |
+
|
| 1239 |
+
database.menuItems.push({
|
| 1240 |
+
id: newId,
|
| 1241 |
+
name,
|
| 1242 |
+
price,
|
| 1243 |
+
description,
|
| 1244 |
+
image
|
| 1245 |
+
});
|
| 1246 |
+
}
|
| 1247 |
+
|
| 1248 |
+
// Refresh tables
|
| 1249 |
+
loadMenuItems();
|
| 1250 |
+
loadMenuItemsTable();
|
| 1251 |
+
|
| 1252 |
+
// Close modal
|
| 1253 |
+
closeMenuItemModal();
|
| 1254 |
+
}
|
| 1255 |
+
|
| 1256 |
+
// Confirm delete menu item
|
| 1257 |
+
function confirmDeleteMenuItem(itemId) {
|
| 1258 |
+
state.confirmationAction = 'deleteMenuItem';
|
| 1259 |
+
state.confirmationData = itemId;
|
| 1260 |
+
|
| 1261 |
+
const item = database.menuItems.find(i => i.id === itemId);
|
| 1262 |
+
|
| 1263 |
+
elements.confirmationTitle.textContent = 'Delete Menu Item';
|
| 1264 |
+
elements.confirmationMessage.textContent = `Are you sure you want to delete "${item.name}"? This action cannot be undone.`;
|
| 1265 |
+
elements.confirmationModal.classList.remove('hidden');
|
| 1266 |
+
}
|
| 1267 |
+
|
| 1268 |
+
// Delete menu item
|
| 1269 |
+
function deleteMenuItem(itemId) {
|
| 1270 |
+
database.menuItems = database.menuItems.filter(i => i.id !== itemId);
|
| 1271 |
+
loadMenuItems();
|
| 1272 |
+
loadMenuItemsTable();
|
| 1273 |
+
}
|
| 1274 |
+
|
| 1275 |
+
// Load users table
|
| 1276 |
+
function loadUsersTable() {
|
| 1277 |
+
elements.usersTable.innerHTML = '';
|
| 1278 |
+
|
| 1279 |
+
database.users.forEach(user => {
|
| 1280 |
+
const row = document.createElement('tr');
|
| 1281 |
+
row.innerHTML = `
|
| 1282 |
+
<td class="px-6 py-4 whitespace-nowrap">
|
| 1283 |
+
<div class="text-sm font-medium text-gray-900">${user.name}</div>
|
| 1284 |
+
</td>
|
| 1285 |
+
<td class="px-6 py-4 whitespace-nowrap">
|
| 1286 |
+
<div class="text-sm text-gray-500">${user.email}</div>
|
| 1287 |
+
</td>
|
| 1288 |
+
<td class="px-6 py-4 whitespace-nowrap">
|
| 1289 |
+
<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'}">
|
| 1290 |
+
${user.role.charAt(0).toUpperCase() + user.role.slice(1)}
|
| 1291 |
+
</span>
|
| 1292 |
+
</td>
|
| 1293 |
+
<td class="px-6 py-4 whitespace-nowrap">
|
| 1294 |
+
<div class="text-sm text-gray-500">${user.lastLogin || 'Never'}</div>
|
| 1295 |
+
</td>
|
| 1296 |
+
<td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
|
| 1297 |
+
<button class="edit-user text-amber-600 hover:text-amber-900 mr-3" data-id="${user.id}">
|
| 1298 |
+
<i class="fas fa-edit"></i>
|
| 1299 |
+
</button>
|
| 1300 |
+
<button class="delete-user text-red-600 hover:text-red-900" data-id="${user.id}">
|
| 1301 |
+
<i class="fas fa-trash"></i>
|
| 1302 |
+
</button>
|
| 1303 |
+
</td>
|
| 1304 |
+
`;
|
| 1305 |
+
|
| 1306 |
+
// Add event listeners to edit and delete buttons
|
| 1307 |
+
const editBtn = row.querySelector('.edit-user');
|
| 1308 |
+
const deleteBtn = row.querySelector('.delete-user');
|
| 1309 |
+
|
| 1310 |
+
editBtn.addEventListener('click', () => openUserModal(user.id));
|
| 1311 |
+
deleteBtn.addEventListener('click', () => confirmDeleteUser(user.id));
|
| 1312 |
+
|
| 1313 |
+
elements.usersTable.appendChild(row);
|
| 1314 |
+
});
|
| 1315 |
+
}
|
| 1316 |
+
|
| 1317 |
+
// Open user modal for adding/editing
|
| 1318 |
+
function openUserModal(userId) {
|
| 1319 |
+
if (userId) {
|
| 1320 |
+
// Editing existing user
|
| 1321 |
+
state.editingUserId = userId;
|
| 1322 |
+
const user = database.users.find(u => u.id === userId);
|
| 1323 |
+
|
| 1324 |
+
elements.userModalTitle.textContent = 'Edit User';
|
| 1325 |
+
elements.userId.value = userId;
|
| 1326 |
+
elements.userName.value = user.name;
|
| 1327 |
+
elements.userEmail.value = user.email;
|
| 1328 |
+
elements.userRole.value = user.role;
|
| 1329 |
+
|
| 1330 |
+
// Hide password field for existing users
|
| 1331 |
+
elements.passwordFields.classList.add('hidden');
|
| 1332 |
+
elements.userPassword.required = false;
|
| 1333 |
+
} else {
|
| 1334 |
+
// Adding new user
|
| 1335 |
+
state.editingUserId = null;
|
| 1336 |
+
elements.userModalTitle.textContent = 'Add User';
|
| 1337 |
+
elements.userId.value = '';
|
| 1338 |
+
elements.userName.value = '';
|
| 1339 |
+
elements.userEmail.value = '';
|
| 1340 |
+
elements.userRole.value = 'staff';
|
| 1341 |
+
|
| 1342 |
+
// Show password field for new users
|
| 1343 |
+
elements.passwordFields.classList.remove('hidden');
|
| 1344 |
+
elements.userPassword.required = true;
|
| 1345 |
+
elements.userPassword.value = '';
|
| 1346 |
+
}
|
| 1347 |
+
|
| 1348 |
+
elements.userModal.classList.remove('hidden');
|
| 1349 |
+
}
|
| 1350 |
+
|
| 1351 |
+
// Close user modal
|
| 1352 |
+
function closeUserModal() {
|
| 1353 |
+
elements.userModal.classList.add('hidden');
|
| 1354 |
+
}
|
| 1355 |
+
|
| 1356 |
+
// Save user (add or update)
|
| 1357 |
+
function saveUser(e) {
|
| 1358 |
+
e.preventDefault();
|
| 1359 |
+
|
| 1360 |
+
const userId = parseInt(elements.userId.value);
|
| 1361 |
+
const name = elements.userName.value;
|
| 1362 |
+
const email = elements.userEmail.value;
|
| 1363 |
+
const role = elements.userRole.value;
|
| 1364 |
+
const password = elements.userPassword.value;
|
| 1365 |
+
|
| 1366 |
+
if (userId) {
|
| 1367 |
+
// Update existing user
|
| 1368 |
+
const index = database.users.findIndex(u => u.id === userId);
|
| 1369 |
+
if (index !== -1) {
|
| 1370 |
+
database.users[index] = {
|
| 1371 |
+
...database.users[index],
|
| 1372 |
+
name,
|
| 1373 |
+
email,
|
| 1374 |
+
role
|
| 1375 |
+
};
|
| 1376 |
+
|
| 1377 |
+
// Update password if provided
|
| 1378 |
+
if (password) {
|
| 1379 |
+
database.users[index].password = password;
|
| 1380 |
+
}
|
| 1381 |
+
}
|
| 1382 |
+
} else {
|
| 1383 |
+
// Add new user
|
| 1384 |
+
const newId = database.users.length > 0 ?
|
| 1385 |
+
Math.max(...database.users.map(u => u.id)) + 1 : 1;
|
| 1386 |
+
|
| 1387 |
+
database.users.push({
|
| 1388 |
+
id: newId,
|
| 1389 |
+
name,
|
| 1390 |
+
email,
|
| 1391 |
+
password,
|
| 1392 |
+
role,
|
| 1393 |
+
lastLogin: null
|
| 1394 |
+
});
|
| 1395 |
+
}
|
| 1396 |
+
|
| 1397 |
+
// Refresh table
|
| 1398 |
+
loadUsersTable();
|
| 1399 |
+
|
| 1400 |
+
// Close modal
|
| 1401 |
+
closeUserModal();
|
| 1402 |
+
}
|
| 1403 |
+
|
| 1404 |
+
// Confirm delete user
|
| 1405 |
+
function confirmDeleteUser(userId) {
|
| 1406 |
+
state.confirmationAction = 'deleteUser';
|
| 1407 |
+
state.confirmationData = userId;
|
| 1408 |
+
|
| 1409 |
+
const user = database.users.find(u => u.id === userId);
|
| 1410 |
+
|
| 1411 |
+
elements.confirmationTitle.textContent = 'Delete User';
|
| 1412 |
+
elements.confirmationMessage.textContent = `Are you sure you want to delete "${user.name}"? This action cannot be undone.`;
|
| 1413 |
+
elements.confirmationModal.classList.remove('hidden');
|
| 1414 |
+
}
|
| 1415 |
+
|
| 1416 |
+
// Delete user
|
| 1417 |
+
function deleteUser(userId) {
|
| 1418 |
+
// Don't allow deleting the current user
|
| 1419 |
+
if (state.currentUser && state.currentUser.id === userId) {
|
| 1420 |
+
alert('You cannot delete your own account while logged in.');
|
| 1421 |
+
return;
|
| 1422 |
+
}
|
| 1423 |
+
|
| 1424 |
+
database.users = database.users.filter(u => u.id !== userId);
|
| 1425 |
+
loadUsersTable();
|
| 1426 |
+
}
|
| 1427 |
+
|
| 1428 |
+
// Handle confirmation actions
|
| 1429 |
+
function confirmAction() {
|
| 1430 |
+
switch (state.confirmationAction) {
|
| 1431 |
+
case 'deleteMenuItem':
|
| 1432 |
+
deleteMenuItem(state.confirmationData);
|
| 1433 |
+
break;
|
| 1434 |
+
case 'deleteUser':
|
| 1435 |
+
deleteUser(state.confirmationData);
|
| 1436 |
+
break;
|
| 1437 |
+
}
|
| 1438 |
+
|
| 1439 |
+
elements.confirmationModal.classList.add('hidden');
|
| 1440 |
+
}
|
| 1441 |
+
|
| 1442 |
+
// Load reports
|
| 1443 |
+
function loadReports() {
|
| 1444 |
+
// Calculate today's date
|
| 1445 |
+
const today = new Date().toISOString().split('T')[0];
|
| 1446 |
+
|
| 1447 |
+
// Calculate sales
|
| 1448 |
+
const todaySales = database.orders
|
| 1449 |
+
.filter(order => order.date === today)
|
| 1450 |
+
.reduce((sum, order) => sum + order.totalPrice, 0);
|
| 1451 |
+
|
| 1452 |
+
// Calculate this week's sales (simplified for demo)
|
| 1453 |
+
const weekSales = database.orders
|
| 1454 |
+
.reduce((sum, order) => sum + order.totalPrice, 0);
|
| 1455 |
+
|
| 1456 |
+
// Calculate this month's sales (simplified for demo)
|
| 1457 |
+
const monthSales = database.orders
|
| 1458 |
+
.reduce((sum, order) => sum + order.totalPrice, 0) * 3;
|
| 1459 |
+
|
| 1460 |
+
// Update UI
|
| 1461 |
+
elements.todaySales.textContent = todaySales.toFixed(2);
|
| 1462 |
+
elements.weekSales.textContent = weekSales.toFixed(2);
|
| 1463 |
+
elements.monthSales.textContent = monthSales.toFixed(2);
|
| 1464 |
+
|
| 1465 |
+
// Load recent orders
|
| 1466 |
+
loadRecentOrders();
|
| 1467 |
+
|
| 1468 |
+
// Initialize charts
|
| 1469 |
+
initCharts();
|
| 1470 |
+
}
|
| 1471 |
+
|
| 1472 |
+
// Initialize charts
|
| 1473 |
+
function initCharts() {
|
| 1474 |
+
// Daily sales chart (last 7 days)
|
| 1475 |
+
const dailySalesCtx = elements.dailySalesChart.getContext('2d');
|
| 1476 |
+
new Chart(dailySalesCtx, {
|
| 1477 |
+
type: 'bar',
|
| 1478 |
+
data: {
|
| 1479 |
+
labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
|
| 1480 |
+
datasets: [{
|
| 1481 |
+
label: 'Daily Sales ($)',
|
| 1482 |
+
data: [120, 190, 150, 210, 180, 250, 200],
|
| 1483 |
+
backgroundColor: 'rgba(245, 158, 11, 0.7)',
|
| 1484 |
+
borderColor: 'rgba(245, 158, 11, 1)',
|
| 1485 |
+
borderWidth: 1
|
| 1486 |
+
}]
|
| 1487 |
+
},
|
| 1488 |
+
options: {
|
| 1489 |
+
responsive: true,
|
| 1490 |
+
scales: {
|
| 1491 |
+
y: {
|
| 1492 |
+
beginAtZero: true
|
| 1493 |
+
}
|
| 1494 |
+
}
|
| 1495 |
+
}
|
| 1496 |
+
});
|
| 1497 |
+
|
| 1498 |
+
// Top items chart
|
| 1499 |
+
const topItemsCtx = elements.topItemsChart.getContext('2d');
|
| 1500 |
+
new Chart(topItemsCtx, {
|
| 1501 |
+
type
|
| 1502 |
+
</html>
|
prompts.txt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
c# burger joint billing store with mysql database
|
| 2 |
+
π 1. Login System (Landing Page) Prompt: Build a Laravel-based login system where the landing page is the login screen. Create roles for admin and staff. Only authenticated users should be allowed into the system. Use Laravel Breeze or Jetstream for authentication. Redirect based on roles: admin to dashboard with full control, staff to billing page. π§βπΌ 2. Role-Based Access Control Prompt: Implement role-based access in Laravel using middleware. Create two roles: admin and staff. Ensure admin has full permissions including user management, item editing, and viewing reports, while staff can only access the billing page and print receipts. Use Laravel policies or Spatie Laravel-Permission for managing roles and permissions. π§Ύ 3. Billing Page with Food Images (For Staff) Prompt: Create a graphical billing page for staff users. Display all menu items in a grid or card layout with: Food name Image Price Add to bill button Allow staff to: Add multiple items to the cart See subtotal and taxes Print a receipt with a unique bill number Use AJAX or Vue.js/Livewire to dynamically update the billing summary without refreshing the page. π 4. Receipt Printing Prompt: Implement a receipt printing function in Laravel where the bill details (items, prices, subtotal, tax, total, and time) are formatted into a printable view. Use Laravel's PDF generation (like dompdf or snappy) or a dedicated print view. Make sure the receipt includes the restaurant logo, name ("Ghost Burgers"), and order number. π 5. Admin Dashboard & Reports Prompt: Create an admin dashboard page showing: Total sales for the day/week/month Number of orders Most popular items Export to Excel/PDF Display reports using charts (Bar, Line, Pie) using a JS library like Chart.js or ApexCharts. Enable date filtering (e.g., fromβto). π₯ 6. User Management Page (For Admin) Prompt: Create a user management page where the admin can: View a list of all users Add new users (name, email, password, role) Edit or delete users Reset passwords Use form validation and confirmation prompts for deletions. π 7. Item Management Page (For Admin) Prompt: Build an item management panel where the admin can: View menu items in a table Add new items (name, price, image upload, description) Edit existing items Delete items Store images in Laravel's storage and display thumbnails in the UI. Use SQL migrations and a proper image upload mechanism. πΎ 8. Database Design (SQL/Migrations) Prompt: Generate Laravel migrations for the following tables: users: id, name, email, password, role menu_items: id, name, price, image, description orders: id, user_id (staff), total_price, created_at order_items: id, order_id, menu_item_id, quantity, price Add foreign key constraints, soft deletes for menu_items, and timestamps for all tables. π 9. Route & Middleware Setup Prompt: Configure Laravel routes with the following middleware: / β Login page (guest only) /billing β Accessible only to staff /admin/* (dashboard, users, items, reports) β Accessible only to admin Use Auth::routes() and group middleware accordingly in web.php.
|
| 3 |
+
what is the username and password
|