From f616da6fa0dba77396eef2eb6d48ea6a730b2d4d Mon Sep 17 00:00:00 2001 From: Jevinca Marvella Date: Sat, 6 Dec 2025 16:18:27 +0700 Subject: [PATCH] Update main.py --- main.py | 635 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 626 insertions(+), 9 deletions(-) diff --git a/main.py b/main.py index ebd608c..b972cf9 100644 --- a/main.py +++ b/main.py @@ -21,6 +21,22 @@ DETAIL_TRANSAKSI_CSV = "detail_transaksi.csv" FAVORITES_CSV = "favorites.csv" IMG_PREVIEW_SIZE = (120, 80) +COLORS = { + 'primary': '#2C3E50', # Dark Blue + 'secondary': '#E67E22', # Orange + 'success': '#27AE60', # Green + 'danger': '#E74C3C', # Red + 'warning': '#F39C12', # Yellow + 'info': '#3498DB', # Light Blue + 'light': '#ECF0F1', # Light Gray + 'dark': '#34495E', # Dark Gray + 'bg_gradient_start': '#667eea', # Purple + 'bg_gradient_end': '#764ba2', # Dark Purple + 'cafe_brown': '#8B4513', # Saddle Brown + 'cafe_cream': '#F5DEB3', # Wheat + 'cafe_green': '#228B22', # Forest Green +} + def ensure_file(path, fieldnames): if not os.path.exists(path): @@ -586,12 +602,35 @@ def get_user_favorites(user_id, limit=5): class App: def __init__(self, root): self.root = root - self.root.title("Cafe Totoro Mania") + self.root.title("🍵 Cafe Totoro Mania") self.session = None self.img_cache = {} self.cart = [] + self.setup_styles() self.setup_ui() + def setup_styles(self): + style = ttk.Style() + style.theme_use('clam') + + # Button styles + style.configure('Primary.TButton', background=COLORS['secondary'], + foreground='white', font=('Arial', 10, 'bold')) + style.map('Primary.TButton', background=[('active', COLORS['warning'])]) + + style.configure('Success.TButton', background=COLORS['success'], + foreground='white', font=('Arial', 10, 'bold')) + + style.configure('Danger.TButton', background=COLORS['danger'], + foreground='white', font=('Arial', 10, 'bold')) + + # Treeview style + style.configure('Treeview', background=COLORS['light'], + foreground=COLORS['dark'], font=('Arial', 9)) + style.configure('Treeview.Heading', background=COLORS['primary'], + foreground='white', font=('Arial', 10, 'bold')) + style.map('Treeview', background=[('selected', COLORS['info'])]) + def setup_ui(self): self.root.geometry("1000x650") self.root.resizable(False, False) @@ -600,20 +639,77 @@ class App: def login_frame(self): for w in self.root.winfo_children(): w.destroy() - frame = ttk.Frame(self.root, padding=20) - frame.pack(expand=True) - ttk.Label(frame, text="Login kak", font=("Arial", 24)).grid(row=0, column=0, columnspan=2, pady=10) + # Main container dengan background cafe + main_frame = tk.Frame(self.root, bg=COLORS['cafe_brown']) + main_frame.pack(fill='both', expand=True) + + # Center frame + center = tk.Frame(main_frame, bg='white', relief='raised', bd=3) + center.place(relx=0.5, rely=0.5, anchor='center', width=500, height=550) + + # Logo/Header Section + header_frame = tk.Frame(center, bg=COLORS['cafe_green'], height=120) + header_frame.pack(fill='x') + + tk.Label(header_frame, text="☕", font=("Arial", 48), + bg=COLORS['cafe_green'], fg='white').pack(pady=5) + + tk.Label(header_frame, text="CAFE TOTORO MANIA", + font=("Arial", 24, "bold"), bg=COLORS['cafe_green'], + fg='white').pack() + + tk.Label(header_frame, text="~ Your Cozy Coffee Corner ~", + font=("Arial", 11, "italic"), bg=COLORS['cafe_green'], + fg=COLORS['cafe_cream']).pack(pady=2) + + # Form Section + form_frame = tk.Frame(center, bg='white', padx=40, pady=30) + form_frame.pack(fill='both', expand=True) + + tk.Label(form_frame, text="Selamat Datang! 👋", + font=("Arial", 18, "bold"), bg='white', + fg=COLORS['cafe_brown']).pack(pady=(0,10)) + + tk.Label(form_frame, text="Silakan login untuk melanjutkan", + font=("Arial", 10), bg='white', + fg=COLORS['dark']).pack(pady=(0,25)) + + # Username + tk.Label(form_frame, text="👤 Username", font=("Arial", 11, "bold"), + bg='white', fg=COLORS['dark']).pack(anchor='w', pady=(10,5)) - ttk.Label(frame, text="Username:").grid(row=1, column=0, sticky='e', pady=5) self.username_var = tk.StringVar() - ttk.Entry(frame, textvariable=self.username_var, width=30).grid(row=1, column=1, pady=5) + username_entry = tk.Entry(form_frame, textvariable=self.username_var, + font=("Arial", 12), relief='solid', bd=2) + username_entry.pack(fill='x', ipady=8) + + # Password + tk.Label(form_frame, text="🔒 Password", font=("Arial", 11, "bold"), + bg='white', fg=COLORS['dark']).pack(anchor='w', pady=(15,5)) - ttk.Label(frame, text="Password:").grid(row=2, column=0, sticky='e', pady=5) self.password_var = tk.StringVar() - ttk.Entry(frame, textvariable=self.password_var, show="*", width=30).grid(row=2, column=1, pady=5) + password_entry = tk.Entry(form_frame, textvariable=self.password_var, + show="●", font=("Arial", 12), relief='solid', bd=2) + password_entry.pack(fill='x', ipady=8) - ttk.Button(frame, text="Login", command=self.handle_login).grid(row=3, column=0, columnspan=2, pady=12) + # Login Button + login_btn = tk.Button(form_frame, text="🔐 LOGIN", command=self.handle_login, + font=("Arial", 13, "bold"), bg=COLORS['cafe_green'], + fg='white', relief='flat', cursor='hand2', bd=0) + login_btn.pack(fill='x', pady=(25,10), ipady=10) + + # Hover effect + login_btn.bind("", lambda e: login_btn.config(bg=COLORS['success'])) + login_btn.bind("", lambda e: login_btn.config(bg=COLORS['cafe_green'])) + + # Info text + info_frame = tk.Frame(center, bg=COLORS['light'], height=60) + info_frame.pack(fill='x', side='bottom') + + tk.Label(info_frame, text="💡 Tip: Gunakan user/user123 untuk pembeli", + font=("Arial", 9), bg=COLORS['light'], + fg=COLORS['dark']).pack(pady=15) def handle_login(self): u = self.username_var.get().strip() @@ -1002,7 +1098,528 @@ class App: self.reload_promo_table() + # ========== TAB: ORDER SYSTEM (PEMBELI) ========== + def build_order_tab(self, parent): + """Tab pemesanan untuk pembeli""" + for w in parent.winfo_children(): + w.destroy() + + # Container utama + container = ttk.Frame(parent) + container.pack(fill='both', expand=True, padx=10, pady=10) + + # LEFT: Daftar Menu + left = ttk.Frame(container, relief='solid', borderwidth=1) + left.pack(side='left', fill='both', expand=True, padx=(0, 5)) + + ttk.Label(left, text="🍽️ Menu Tersedia", font=("Arial", 14, "bold")).pack(pady=8) + + # Filter pencarian + filter_frm = ttk.Frame(left) + filter_frm.pack(fill='x', padx=10, pady=5) + ttk.Label(filter_frm, text="Cari Menu:").pack(side='left', padx=5) + self.order_search_var = tk.StringVar() + ttk.Entry(filter_frm, textvariable=self.order_search_var, width=20).pack(side='left', padx=5) + ttk.Button(filter_frm, text="🔍 Cari", command=self.reload_order_menu).pack(side='left', padx=3) + ttk.Button(filter_frm, text="🔄 Reset", command=self.reset_order_search).pack(side='left', padx=3) + + # Treeview menu + cols = ("ID", "Nama", "Kategori", "Harga", "Stok") + self.order_menu_tree = ttk.Treeview(left, columns=cols, show='headings', height=15) + for c in cols: + self.order_menu_tree.heading(c, text=c) + w = 50 if c == "ID" else (180 if c == "Nama" else 100) + self.order_menu_tree.column(c, width=w) + self.order_menu_tree.pack(fill='both', expand=True, padx=10, pady=5) + + # Tombol tambah ke keranjang + add_frame = ttk.Frame(left) + add_frame.pack(fill='x', padx=10, pady=8) + ttk.Label(add_frame, text="Jumlah:", font=("Arial", 10)).pack(side='left', padx=5) + self.order_qty_var = tk.StringVar(value="1") + ttk.Entry(add_frame, textvariable=self.order_qty_var, width=8).pack(side='left', padx=5) + ttk.Button(add_frame, text="➕ Tambah ke Keranjang", command=self.add_to_cart).pack(side='left', padx=10) + + # RIGHT: Keranjang + right = ttk.Frame(container, relief='solid', borderwidth=1) + right.pack(side='right', fill='both', padx=(5, 0)) + right.config(width=350) + + ttk.Label(right, text="🛒 Keranjang Belanja", font=("Arial", 14, "bold")).pack(pady=8) + + # Treeview keranjang + cart_cols = ("Menu", "Harga", "Qty", "Subtotal") + self.cart_tree = ttk.Treeview(right, columns=cart_cols, show='headings', height=12) + for c in cart_cols: + self.cart_tree.heading(c, text=c) + w = 120 if c == "Menu" else 70 + self.cart_tree.column(c, width=w) + self.cart_tree.pack(fill='both', padx=10, pady=5) + + # Tombol update & hapus + cart_btn_frm = ttk.Frame(right) + cart_btn_frm.pack(fill='x', padx=10, pady=5) + ttk.Button(cart_btn_frm, text="🗑️ Hapus Item", command=self.remove_from_cart).pack(side='left', padx=3) + ttk.Button(cart_btn_frm, text="📝 Update Qty", command=self.update_cart_qty).pack(side='left', padx=3) + + # Total + self.cart_total_var = tk.StringVar(value="Total: Rp 0") + ttk.Label(right, textvariable=self.cart_total_var, font=("Arial", 12, "bold")).pack(pady=5) + + # Form nomor meja + meja_frm = ttk.Frame(right) + meja_frm.pack(fill='x', padx=10, pady=8) + ttk.Label(meja_frm, text="Nomor Meja:", font=("Arial", 10)).pack(side='left', padx=5) + self.nomor_meja_var = tk.StringVar() + ttk.Entry(meja_frm, textvariable=self.nomor_meja_var, width=10).pack(side='left', padx=5) + + # Tombol pesan + ttk.Button(right, text="📋 PESAN SEKARANG", command=self.submit_order, + style="Accent.TButton").pack(pady=10, padx=10, fill='x') + + self.reload_order_menu() + + def reload_order_menu(self): + """Reload daftar menu untuk order""" + for item in self.order_menu_tree.get_children(): + self.order_menu_tree.delete(item) + + search = self.order_search_var.get().strip() if hasattr(self, 'order_search_var') else "" + menus = menu_list(available_only=True, search_text=search or None) + + for m in menus: + mid, nama, kategori, harga, stok, foto, tersedia, disc = m + self.order_menu_tree.insert("", tk.END, values=(mid, nama, kategori, f"Rp {harga:,.0f}", stok)) + + def reset_order_search(self): + self.order_search_var.set("") + self.reload_order_menu() + + def add_to_cart(self): + """Tambah item ke keranjang""" + sel = self.order_menu_tree.selection() + if not sel: + messagebox.showwarning("Pilih Menu", "Pilih menu terlebih dahulu!") + return + + try: + qty = int(self.order_qty_var.get()) + if qty <= 0: + raise ValueError() + except: + messagebox.showerror("Error", "Jumlah harus angka positif!") + return + + item_vals = self.order_menu_tree.item(sel)['values'] + menu_id = item_vals[0] + nama = item_vals[1] + harga_str = item_vals[3].replace("Rp ", "").replace(",", "") + harga = float(harga_str) + stok = int(item_vals[4]) + + if qty > stok: + messagebox.showerror("Stok Habis", f"Stok hanya tersedia {stok}") + return + + # Cek apakah sudah ada di cart + found = False + for cart_item in self.cart: + if cart_item['menu_id'] == menu_id: + cart_item['qty'] += qty + cart_item['subtotal'] = cart_item['harga'] * cart_item['qty'] + found = True + break + + if not found: + self.cart.append({ + 'menu_id': menu_id, + 'nama': nama, + 'harga': harga, + 'qty': qty, + 'subtotal': harga * qty + }) + + self.update_cart_display() + messagebox.showinfo("Berhasil", f"✅ {nama} x{qty} ditambahkan ke keranjang!") + + def update_cart_display(self): + """Update tampilan keranjang""" + for item in self.cart_tree.get_children(): + self.cart_tree.delete(item) + + total = 0.0 + for item in self.cart: + self.cart_tree.insert("", tk.END, values=( + item['nama'], + f"Rp {item['harga']:,.0f}", + item['qty'], + f"Rp {item['subtotal']:,.0f}" + )) + total += item['subtotal'] + + self.cart_total_var.set(f"Total: Rp {total:,.0f}") + + def remove_from_cart(self): + """Hapus item dari keranjang""" + sel = self.cart_tree.selection() + if not sel: + messagebox.showwarning("Pilih Item", "Pilih item yang akan dihapus!") + return + + idx = self.cart_tree.index(sel) + del self.cart[idx] + self.update_cart_display() + messagebox.showinfo("Dihapus", "Item berhasil dihapus dari keranjang") + + def update_cart_qty(self): + """Update jumlah item di keranjang""" + sel = self.cart_tree.selection() + if not sel: + messagebox.showwarning("Pilih Item", "Pilih item yang akan diupdate!") + return + + idx = self.cart_tree.index(sel) + item = self.cart[idx] + + # Dialog input qty baru + new_qty = tk.simpledialog.askinteger("Update Jumlah", + f"Jumlah baru untuk {item['nama']}:", + initialvalue=item['qty'], + minvalue=1) + if new_qty: + item['qty'] = new_qty + item['subtotal'] = item['harga'] * new_qty + self.update_cart_display() + + def submit_order(self): + """Submit pesanan""" + if not self.cart: + messagebox.showwarning("Keranjang Kosong", "Tambahkan menu ke keranjang terlebih dahulu!") + return + + nomor_meja = self.nomor_meja_var.get().strip() + if not nomor_meja: + messagebox.showwarning("Nomor Meja", "Masukkan nomor meja!") + return + + try: + trans_id = create_transaksi(self.session['id'], nomor_meja, self.cart) + + # Tambah ke favorites + for item in self.cart: + add_to_favorites(self.session['id'], item['menu_id']) + + messagebox.showinfo("Berhasil", + f"✅ Pesanan berhasil dibuat!\n\n" + f"ID Transaksi: {trans_id}\n" + f"Nomor Meja: {nomor_meja}\n" + f"Total: Rp {sum(i['subtotal'] for i in self.cart):,.0f}\n\n" + f"Status: Menunggu\n" + f"Pesanan Anda akan segera diproses oleh waiter!") + + # Reset + self.cart = [] + self.nomor_meja_var.set("") + self.order_qty_var.set("1") + self.update_cart_display() + self.reload_order_menu() + + except Exception as e: + messagebox.showerror("Error", f"Gagal membuat pesanan: {e}") + # ========== TAB: WAITER DASHBOARD ========== + def build_waiter_tab(self, parent): + """Dashboard untuk waiter mengelola pesanan""" + for w in parent.winfo_children(): + w.destroy() + + ttk.Label(parent, text="📋 Dashboard Waiter - Kelola Pesanan", + font=("Arial", 16, "bold")).pack(pady=10) + + # Filter status + filter_frm = ttk.Frame(parent) + filter_frm.pack(fill='x', padx=10, pady=5) + ttk.Label(filter_frm, text="Filter Status:").pack(side='left', padx=5) + ttk.Button(filter_frm, text="🕐 Menunggu", + command=lambda: self.reload_waiter_orders("Menunggu")).pack(side='left', padx=3) + ttk.Button(filter_frm, text="⏳ Diproses", + command=lambda: self.reload_waiter_orders("Diproses")).pack(side='left', padx=3) + ttk.Button(filter_frm, text="✅ Selesai", + command=lambda: self.reload_waiter_orders("Selesai")).pack(side='left', padx=3) + ttk.Button(filter_frm, text="📋 Semua", + command=lambda: self.reload_waiter_orders(None)).pack(side='left', padx=3) + ttk.Button(filter_frm, text="🔄 Refresh", + command=lambda: self.reload_waiter_orders()).pack(side='right', padx=10) + + # Treeview pesanan + cols = ("ID", "Tanggal", "Meja", "Total", "Status") + self.waiter_tree = ttk.Treeview(parent, columns=cols, show='headings', height=10) + for c in cols: + self.waiter_tree.heading(c, text=c) + w = 50 if c == "ID" else (150 if c == "Tanggal" else 80) + self.waiter_tree.column(c, width=w) + self.waiter_tree.pack(fill='both', expand=True, padx=10, pady=10) + self.waiter_tree.bind("<>", self.on_waiter_select) + + # Detail pesanan + detail_frm = ttk.LabelFrame(parent, text="📝 Detail Pesanan", padding=10) + detail_frm.pack(fill='both', padx=10, pady=5) + + self.waiter_detail_text = tk.Text(detail_frm, height=8, width=80, state='disabled') + self.waiter_detail_text.pack(side='left', fill='both', expand=True) + + # Tombol aksi + btn_frm = ttk.Frame(parent) + btn_frm.pack(fill='x', padx=10, pady=10) + ttk.Button(btn_frm, text="⏳ Proses Pesanan", + command=lambda: self.change_order_status("Diproses")).pack(side='left', padx=5) + ttk.Button(btn_frm, text="✅ Selesai Dilayani", + command=lambda: self.change_order_status("Selesai")).pack(side='left', padx=5) + + self.reload_waiter_orders() + + def reload_waiter_orders(self, status=None): + """Reload daftar pesanan untuk waiter""" + for item in self.waiter_tree.get_children(): + self.waiter_tree.delete(item) + + orders = get_all_transaksi(status=status) + + for order in orders: + status_icon = {"Menunggu": "🕐", "Diproses": "⏳", "Selesai": "✅"}.get(order['status'], "") + self.waiter_tree.insert("", tk.END, values=( + order['id'], + order['tanggal'], + order['nomor_meja'], + f"Rp {order['total']:,.0f}", + f"{status_icon} {order['status']}" + )) + + def on_waiter_select(self, event): + """Ketika waiter pilih pesanan, tampilkan detail""" + sel = self.waiter_tree.selection() + if not sel: + return + + trans_id = self.waiter_tree.item(sel)['values'][0] + details = get_transaksi_detail(trans_id) + + self.waiter_detail_text.config(state='normal') + self.waiter_detail_text.delete('1.0', tk.END) + + text = f"ID Transaksi: {trans_id}\n" + text += f"{'='*50}\n" + text += f"{'Menu':<25} {'Qty':<5} {'Harga':<12} {'Subtotal':<12}\n" + text += f"{'-'*50}\n" + + for d in details: + text += f"{d['nama_menu']:<25} {d['jumlah']:<5} Rp {d['harga_satuan']:>8,.0f} Rp {d['subtotal']:>8,.0f}\n" + + self.waiter_detail_text.insert('1.0', text) + self.waiter_detail_text.config(state='disabled') + + def change_order_status(self, new_status): + """Ubah status pesanan""" + sel = self.waiter_tree.selection() + if not sel: + messagebox.showwarning("Pilih Pesanan", "Pilih pesanan terlebih dahulu!") + return + + trans_id = self.waiter_tree.item(sel)['values'][0] + current_status = self.waiter_tree.item(sel)['values'][4].split()[-1] + + # Validasi flow status + if current_status == "Selesai": + messagebox.showinfo("Info", "Pesanan sudah selesai dilayani!") + return + + # ========== LANJUTAN DARI ARTIFACTS SEBELUMNYA ========== +# Paste kode ini setelah fungsi change_order_status + + if new_status == "Selesai" and current_status == "Menunggu": + if not messagebox.askyesno("Konfirmasi", "Pesanan belum diproses. Langsung selesai?"): + return + + update_transaksi_status(trans_id, new_status) + messagebox.showinfo("Berhasil", f"Status pesanan diubah menjadi: {new_status}") + self.reload_waiter_orders() + + # ========== TAB: FAVORITES (PEMBELI) ========== + def build_favorites_tab(self, parent): + """Tab menu favorit untuk pembeli""" + for w in parent.winfo_children(): + w.destroy() + + ttk.Label(parent, text="⭐ Menu Favorit Saya", + font=("Arial", 16, "bold")).pack(pady=10) + + ttk.Label(parent, text="Menu yang paling sering Anda pesan", + font=("Arial", 10)).pack(pady=5) + + # Treeview favorites + cols = ("Nama Menu", "Kategori", "Harga", "Sering Dipesan") + self.fav_tree = ttk.Treeview(parent, columns=cols, show='headings', height=12) + for c in cols: + self.fav_tree.heading(c, text=c) + w = 200 if c == "Nama Menu" else 120 + self.fav_tree.column(c, width=w) + self.fav_tree.pack(fill='both', expand=True, padx=10, pady=10) + + # Tombol pesan cepat + btn_frm = ttk.Frame(parent) + btn_frm.pack(pady=10) + ttk.Label(btn_frm, text="Pesan Cepat - Jumlah:").pack(side='left', padx=5) + self.fav_qty_var = tk.StringVar(value="1") + ttk.Entry(btn_frm, textvariable=self.fav_qty_var, width=8).pack(side='left', padx=5) + ttk.Button(btn_frm, text="🚀 Pesan Langsung", + command=self.quick_order_from_fav).pack(side='left', padx=10) + ttk.Button(btn_frm, text="🔄 Refresh", + command=self.reload_favorites).pack(side='left', padx=5) + + self.reload_favorites() + + def reload_favorites(self): + """Reload menu favorit user""" + for item in self.fav_tree.get_children(): + self.fav_tree.delete(item) + + favs = get_user_favorites(self.session['id'], limit=10) + + if not favs: + self.fav_tree.insert("", tk.END, values=( + "Belum ada menu favorit", "-", "-", "0" + )) + return + + for fav in favs: + menu = fav['menu'] + mid, nama, kategori, harga, stok, foto, tersedia, disc = menu + self.fav_tree.insert("", tk.END, values=( + nama, + kategori, + f"Rp {harga:,.0f}", + f"{fav['count']}x" + ), tags=(str(mid),)) + + def quick_order_from_fav(self): + """Pesan langsung dari menu favorit""" + sel = self.fav_tree.selection() + if not sel: + messagebox.showwarning("Pilih Menu", "Pilih menu favorit terlebih dahulu!") + return + + item_vals = self.fav_tree.item(sel)['values'] + if item_vals[0] == "Belum ada menu favorit": + return + + # Ambil menu_id dari tags + menu_id = int(self.fav_tree.item(sel)['tags'][0]) + menu = menu_get(menu_id) + + if not menu: + messagebox.showerror("Error", "Menu tidak ditemukan!") + return + + mid, nama, kategori, harga, stok, foto, tersedia, disc = menu + + if not tersedia or stok == 0: + messagebox.showwarning("Stok Habis", f"{nama} sedang tidak tersedia!") + return + + try: + qty = int(self.fav_qty_var.get()) + if qty <= 0: + raise ValueError() + except: + messagebox.showerror("Error", "Jumlah harus angka positif!") + return + + if qty > stok: + messagebox.showerror("Stok Tidak Cukup", f"Stok hanya tersedia {stok}") + return + + # Tanya nomor meja + nomor_meja = tk.simpledialog.askstring("Nomor Meja", "Masukkan nomor meja Anda:") + if not nomor_meja: + return + + # Buat transaksi langsung + cart_item = [{ + 'menu_id': mid, + 'nama': nama, + 'harga': harga, + 'qty': qty, + 'subtotal': harga * qty + }] + + try: + trans_id = create_transaksi(self.session['id'], nomor_meja, cart_item) + add_to_favorites(self.session['id'], mid) + + messagebox.showinfo("Berhasil", + f"✅ Pesanan Cepat Berhasil!\n\n" + f"{nama} x{qty}\n" + f"Total: Rp {harga * qty:,.0f}\n" + f"Meja: {nomor_meja}\n\n" + f"ID Transaksi: {trans_id}") + + self.reload_favorites() + + except Exception as e: + messagebox.showerror("Error", f"Gagal membuat pesanan: {e}") + + # ========== UPDATE DASHBOARD FRAME ========== + # GANTI fungsi dashboard_frame yang lama dengan ini: + + def dashboard_frame(self): + for w in self.root.winfo_children(): + w.destroy() + + # Header + top = ttk.Frame(self.root) + top.pack(fill='x') + ttk.Label(top, text=f"👤 User: {self.session['username']} | Role: {self.session['role'].upper()}", + font=("Arial", 12, "bold")).pack(side='left', padx=15, pady=8) + ttk.Button(top, text="🚪 Logout", command=self.logout).pack(side='right', padx=15) + + # Notebook tabs + main = ttk.Notebook(self.root) + main.pack(fill='both', expand=True, padx=10, pady=10) + + role = self.session['role'] + + # Setup tabs berdasarkan role + if role == 'pembeli': + self.tab_order = ttk.Frame(main) + self.tab_favorites = ttk.Frame(main) + main.add(self.tab_order, text="🛒 Pesan Menu") + main.add(self.tab_favorites, text="⭐ Menu Favorit") + self.build_order_tab(self.tab_order) + self.build_favorites_tab(self.tab_favorites) + + elif role == 'waiter': + self.tab_waiter = ttk.Frame(main) + main.add(self.tab_waiter, text="📋 Dashboard Waiter") + self.build_waiter_tab(self.tab_waiter) + + elif role == 'admin': + self.tab_menu_view = ttk.Frame(main) + self.tab_menu_manage = ttk.Frame(main) + self.tab_promo = ttk.Frame(main) + self.tab_waiter = ttk.Frame(main) + main.add(self.tab_menu_view, text="📖 Menu - View") + main.add(self.tab_menu_manage, text="⚙️ Menu - Manage") + main.add(self.tab_promo, text="🎁 Promo - Manage") + main.add(self.tab_waiter, text="📋 Dashboard Waiter") + self.build_menu_view_tab(self.tab_menu_view) + self.build_menu_manage_tab(self.tab_menu_manage) + self.build_promo_tab(self.tab_promo) + self.build_waiter_tab(self.tab_waiter) + + else: # kasir, owner + self.tab_menu_view = ttk.Frame(main) + main.add(self.tab_menu_view, text="📖 Menu - View") + self.build_menu_view_tab(self.tab_menu_view)