From 3c7a82827a40b106e355c088147d67f580d0a254 Mon Sep 17 00:00:00 2001
From: nn2-minh <Nguyen12.Minh@live.uwe.ac.uk>
Date: Mon, 31 Mar 2025 21:44:38 +0700
Subject: [PATCH] update front end for owner

---
 .../components/product/create_product.py      | 125 +++++++-----
 app/frontend/components/shop/create_shop.py   | 134 +++++++------
 app/frontend/components/shop/view_shop.py     | 182 +++++++----------
 app/frontend/components/user_details.py       | 187 ++++--------------
 app/frontend/main.py                          |  40 ++--
 5 files changed, 286 insertions(+), 382 deletions(-)

diff --git a/app/frontend/components/product/create_product.py b/app/frontend/components/product/create_product.py
index b95400c..f34f6cf 100644
--- a/app/frontend/components/product/create_product.py
+++ b/app/frontend/components/product/create_product.py
@@ -1,69 +1,92 @@
 import customtkinter as ctk
+from tkinter import filedialog, messagebox
 import requests
-from tkinter import messagebox
+import os
 
-
-def product_frame(parent, switch_func, API_URL, token):
+def create_product_frame(parent, switch_func, API_URL, token):
+    """
+    Frame to create a new product.
+    Fields: Title, Price, Description, Stock, and Product Image.
+    On success, navigates back to the shop view.
+    """
     frame = ctk.CTkFrame(parent)
+    title = ctk.CTkLabel(frame, text="Create New Product", font=("Helvetica", 18, "bold"))
+    title.pack(pady=10)
 
-    ctk.CTkLabel(frame, text="Product Management", font=("Helvetica", 18, "bold")).pack(
-        pady=10
-    )
-
-    ctk.CTkLabel(frame, text="Product Name:").pack(pady=5)
-    entry_name = ctk.CTkEntry(frame)
-    entry_name.pack(pady=5)
+    # Product Title
+    prod_title_label = ctk.CTkLabel(frame, text="Product Title:")
+    prod_title_label.pack(pady=5)
+    prod_title_entry = ctk.CTkEntry(frame, width=300)
+    prod_title_entry.pack(pady=5)
 
-    ctk.CTkLabel(frame, text="Price:").pack(pady=5)
-    entry_price = ctk.CTkEntry(frame)
-    entry_price.pack(pady=5)
+    # Price
+    price_label = ctk.CTkLabel(frame, text="Price:")
+    price_label.pack(pady=5)
+    price_entry = ctk.CTkEntry(frame, width=300)
+    price_entry.pack(pady=5)
 
-    ctk.CTkLabel(frame, text="Stock:").pack(pady=5)
-    entry_stock = ctk.CTkEntry(frame)
-    entry_stock.pack(pady=5)
+    # Description
+    desc_label = ctk.CTkLabel(frame, text="Description:")
+    desc_label.pack(pady=5)
+    desc_entry = ctk.CTkEntry(frame, width=300)
+    desc_entry.pack(pady=5)
 
-    def create_product():
-        name = entry_name.get().strip()
-        price = entry_price.get().strip()
-        stock = entry_stock.get().strip()
+    # Stock Quantity
+    stock_label = ctk.CTkLabel(frame, text="Stock Quantity:")
+    stock_label.pack(pady=5)
+    stock_entry = ctk.CTkEntry(frame, width=300)
+    stock_entry.pack(pady=5)
 
-        if not name or not price or not stock:
-            messagebox.showwarning("Input Error", "All fields are required!")
-            return
+    # Product Image Upload
+    image_path = ctk.StringVar(value="No file selected")
+    def browse_image():
+        filename = filedialog.askopenfilename(
+            title="Select Product Image", 
+            filetypes=[("Image Files", "*.png;*.jpg;*.jpeg;*.gif")]
+        )
+        if filename:
+            image_path.set(filename)
+    browse_button = ctk.CTkButton(frame, text="Browse Image", command=browse_image)
+    browse_button.pack(pady=5)
+    image_label = ctk.CTkLabel(frame, textvariable=image_path)
+    image_label.pack(pady=5)
 
-        try:
-            price = float(price)
-            stock = int(stock)
-        except ValueError:
-            messagebox.showwarning(
-                "Input Error", "Price must be a number and Stock must be an integer."
-            )
+    def submit_product():
+        title_val = prod_title_entry.get().strip()
+        price_val = price_entry.get().strip()
+        desc_val = desc_entry.get().strip()
+        stock_val = stock_entry.get().strip()
+        if not title_val or not price_val or not stock_val:
+            messagebox.showerror("Error", "Title, Price, and Stock are required")
             return
 
+        # In a real scenario, you would pass the shop_id from view_shop.
+        # For now, use a placeholder shop_id (e.g., 1)
+        data = {
+            "name": title_val,
+            "price": price_val,
+            "description": desc_val,
+            "stock": stock_val,
+            "shop_id": 1  # Replace with the actual shop id
+        }
+        files = {}
+        if os.path.isfile(image_path.get()):
+            files["images"] = open(image_path.get(), "rb")
         headers = {"Authorization": f"Bearer {token}"}
-        data = {"name": name, "price": price, "stock": stock}
-
         try:
-            response = requests.post(f"{API_URL}/products", json=data, headers=headers)
-
-            if response.status_code == 200:
-                messagebox.showinfo(
-                    "Success", f"Product '{name}' created successfully!"
-                )
-                entry_name.delete(0, "end")
-                entry_price.delete(0, "end")
-                entry_stock.delete(0, "end")
+            resp = requests.post(f"{API_URL}/product/create", data=data, files=files, headers=headers)
+            if resp.status_code == 200:
+                messagebox.showinfo("Success", "Product created successfully!")
+                switch_func("view_shop")  # You might pass shop data if needed
             else:
-                error_message = response.json().get(
-                    "detail", "Failed to create product"
-                )
-                messagebox.showerror("Error", error_message)
-        except requests.exceptions.RequestException as e:
-            messagebox.showerror("Error", f"Failed to connect to server: {e}")
+                messagebox.showerror("Error", f"Failed to create product. Status: {resp.status_code}\n{resp.text}")
+        except Exception as e:
+            messagebox.showerror("Error", f"Request error: {e}")
+        finally:
+            if files:
+                files["images"].close()
 
-    ctk.CTkButton(frame, text="Create Product", command=create_product).pack(pady=15)
-    ctk.CTkButton(frame, text="Back", command=lambda: switch_func("view_shop")).pack(
-        pady=5
-    )
+    submit_button = ctk.CTkButton(frame, text="Create Product", command=submit_product)
+    submit_button.pack(pady=10)
 
     return frame
diff --git a/app/frontend/components/shop/create_shop.py b/app/frontend/components/shop/create_shop.py
index e73fb5b..32cbf0d 100644
--- a/app/frontend/components/shop/create_shop.py
+++ b/app/frontend/components/shop/create_shop.py
@@ -1,71 +1,91 @@
 import customtkinter as ctk
-from tkinter import messagebox, filedialog
+from tkinter import filedialog, messagebox
+import requests
 import os
-from utils.api_requests import create_shop_api  # Import API function
-
 
 def create_shop_frame(parent, switch_func, API_URL, token):
+    """
+    Frame for a user to create a shop.
+    This version stores the token in the frame and provides an update_token method.
+    """
     frame = ctk.CTkFrame(parent)
-    frame.access_token = token
+    
+    # Store the initial token in the frame
+    frame.token = token
 
+    # Define an update_token method so the global token can be propagated.
     def update_token(new_token):
-        frame.access_token = new_token
-
+        frame.token = new_token
     frame.update_token = update_token
 
-    selected_file_path = [None]
-
-    def select_file():
-        file_path = filedialog.askopenfilename(title="Select Shop Image")
-        if file_path:
-            selected_file_path[0] = file_path
-            file_label.configure(text=os.path.basename(file_path))
-        else:
-            selected_file_path[0] = None
-            file_label.configure(text="No file selected")
-
-    def create_shop():
-        name = entry_name.get()
-        description = entry_description.get()
-
-        if not name:
-            messagebox.showwarning("Input Error", "Shop name is required!")
-            return
-
-        # Call the API function from shop_api.py
-        status_code, response_data = create_shop_api(
-            name, description, selected_file_path[0], API_URL, frame.access_token
+    title = ctk.CTkLabel(frame, text="Create Your Shop", font=("Helvetica", 18, "bold"))
+    title.pack(pady=10)
+
+    # Shop Name Field
+    shop_name_label = ctk.CTkLabel(frame, text="Shop Name:")
+    shop_name_label.pack(pady=5)
+    shop_name_entry = ctk.CTkEntry(frame, width=300)
+    shop_name_entry.pack(pady=5)
+
+    # Address Field (using a default for demonstration)
+    address_label = ctk.CTkLabel(frame, text="Address:")
+    address_label.pack(pady=5)
+    address_entry = ctk.CTkEntry(frame, width=300)
+    address_entry.insert(0, "123 Main St")
+    address_entry.pack(pady=5)
+
+    # Shop Image Upload
+    image_path = ctk.StringVar(value="No file selected")
+    def browse_image():
+        filename = filedialog.askopenfilename(
+            title="Select Shop Image", 
+            filetypes=[("Image Files", "*.png;*.jpg;*.jpeg;*.gif")]
         )
+        if filename:
+            image_path.set(filename)
+    browse_button = ctk.CTkButton(frame, text="Browse Image", command=browse_image)
+    browse_button.pack(pady=5)
+    image_label = ctk.CTkLabel(frame, textvariable=image_path)
+    image_label.pack(pady=5)
+
+    def submit_shop():
+        # Use the token stored in the frame
+        current_token = frame.token
+        if not current_token:
+            messagebox.showerror("Error", "No access token found. Please log in again.")
+            return
 
-        if status_code == 200:
-            messagebox.showinfo("Shop Created", f"Shop '{name}' created successfully!")
-        else:
-            messagebox.showerror(
-                "Error", response_data.get("detail", "An error occurred")
-            )
-
-    ctk.CTkLabel(frame, text="Create Shop", font=("Helvetica", 18, "bold")).pack(
-        pady=10
-    )
-
-    ctk.CTkLabel(frame, text="Shop Name:").pack(pady=5)
-    entry_name = ctk.CTkEntry(frame, placeholder_text="Enter shop name")
-    entry_name.pack(pady=5)
-
-    ctk.CTkLabel(frame, text="Description:").pack(pady=5)
-    entry_description = ctk.CTkEntry(frame, placeholder_text="Enter shop description")
-    entry_description.pack(pady=5)
-
-    ctk.CTkButton(frame, text="Select Image", command=select_file).pack(pady=5)
-    file_label = ctk.CTkLabel(frame, text="No file selected")
-    file_label.pack(pady=5)
-
-    ctk.CTkButton(
-        frame, text="Create Shop", fg_color="green", command=create_shop
-    ).pack(pady=15)
+        name = shop_name_entry.get().strip()
+        address = address_entry.get().strip()
+        if not name or not address:
+            messagebox.showerror("Error", "Please fill all fields.")
+            return
 
-    ctk.CTkButton(
-        frame, text="Back", fg_color="transparent", command=lambda: switch_func("login")
-    ).pack(pady=5)
+        data = {
+            "name": name,
+            "address": address,
+            "description": "Default shop description"
+        }
+        files = {}
+        if os.path.isfile(image_path.get()):
+            files["file"] = open(image_path.get(), "rb")
+        headers = {"Authorization": f"Bearer {current_token}"}
+        print("Creating shop with token:", current_token)
+        try:
+            resp = requests.post(f"{API_URL}/shops/create", data=data, files=files, headers=headers)
+            if resp.status_code == 200:
+                shop = resp.json()
+                messagebox.showinfo("Success", "Shop created successfully!")
+                switch_func("view_shop", shop)  # Pass the shop data to the view shop frame
+            else:
+                messagebox.showerror("Error", f"Failed to create shop. Status: {resp.status_code}\n{resp.text}")
+        except Exception as e:
+            messagebox.showerror("Error", f"Request error: {e}")
+        finally:
+            if files:
+                files["file"].close()
+
+    submit_button = ctk.CTkButton(frame, text="Create Shop", command=submit_shop)
+    submit_button.pack(pady=10)
 
     return frame
diff --git a/app/frontend/components/shop/view_shop.py b/app/frontend/components/shop/view_shop.py
index 3c4ae23..8840001 100644
--- a/app/frontend/components/shop/view_shop.py
+++ b/app/frontend/components/shop/view_shop.py
@@ -1,119 +1,75 @@
 import customtkinter as ctk
+import requests
+from PIL import Image, ImageTk
 from tkinter import messagebox
-from PIL import ImageTk
-from utils.api_requests import (
-    fetch_shop_details,
-    fetch_shop_products,
-    load_image_from_url,
-)
-
-
-def view_shop_frame(parent, switch_func, API_URL, token):
+import io
+
+def view_shop_frame(parent, switch_func, shop_data, token, API_URL):
+    """
+    Frame to display the owner’s shop.
+    If shop_data is None, display a message that no shop has been created.
+    Otherwise, display the shop's details and its products.
+    """
     frame = ctk.CTkFrame(parent)
 
-    # Title
-    title_label = ctk.CTkLabel(frame, text="Your Shop", font=("Helvetica", 18, "bold"))
-    title_label.pack(pady=10)
-
-    # Shop Details
-    shop_name_label = ctk.CTkLabel(
-        frame, text="Shop Name: ", font=("Helvetica", 14, "bold")
-    )
-    shop_name_label.pack(pady=5)
-
-    shop_description_label = ctk.CTkLabel(
-        frame, text="Description: ", font=("Helvetica", 12)
-    )
-    shop_description_label.pack(pady=5)
-
-    shop_image_label = ctk.CTkLabel(frame, text="")  # Placeholder for shop image
-    shop_image_label.pack(pady=10)
-
-    # Product List Section
-    product_list_frame = ctk.CTkFrame(frame)
-    product_list_frame.pack(fill="both", expand=True, padx=10, pady=10)
-
-    def fetch_and_display_shop():
-        """Fetch shop details and update UI"""
-        shop_data = fetch_shop_details(API_URL, token)
-
-        if "error" in shop_data:
-            messagebox.showerror("Error", shop_data["error"])
-            return
-
-        shop_name_label.configure(text=f"Shop Name: {shop_data['name']}")
-        shop_description_label.configure(
-            text=f"Description: {shop_data.get('description', 'No description')}"
-        )
-
-        if "image_url" in shop_data and shop_data["image_url"]:
-            image = load_image_from_url(shop_data["image_url"])
-            if image:
-                img_tk = ImageTk.PhotoImage(image)
-                shop_image_label.configure(image=img_tk, text="")
-                shop_image_label.image = img_tk  # Prevent garbage collection
-
-        fetch_and_display_products(shop_data["id"])
-
-    def fetch_and_display_products(shop_id):
-        """Fetch products and display them in the UI"""
-        products = fetch_shop_products(API_URL, token, shop_id)
-
-        if "error" in products:
-            messagebox.showerror("Error", products["error"])
-            return
-
-        for widget in product_list_frame.winfo_children():
-            widget.destroy()
-
-        if not products:
-            ctk.CTkLabel(
-                product_list_frame, text="No products found.", font=("Helvetica", 12)
-            ).pack(pady=10)
-            return
-
-        for product in products:
-            product_frame = ctk.CTkFrame(product_list_frame)
-            product_frame.pack(fill="x", padx=5, pady=5)
-
-            # Product Image
-            img_label = ctk.CTkLabel(product_frame, text="")  # Placeholder
-            img_label.pack(side="left", padx=5)
-
-            if "images" in product and product["images"]:
-                image_url = product["images"][0]["image_url"]
-                image = load_image_from_url(image_url, size=(50, 50))
-                if image:
-                    img_tk = ImageTk.PhotoImage(image)
-                    img_label.configure(image=img_tk, text="")
-                    img_label.image = img_tk  # Prevent garbage collection
-
-            # Product Details
-            details_frame = ctk.CTkFrame(product_frame)
-            details_frame.pack(side="left", fill="x", expand=True, padx=10)
-
-            ctk.CTkLabel(
-                details_frame, text=product["name"], font=("Helvetica", 12, "bold")
-            ).pack(anchor="w")
-            ctk.CTkLabel(
-                details_frame,
-                text=f"Price: ${product['price']:.2f}",
-                font=("Helvetica", 12),
-            ).pack(anchor="w")
-
-    # Refresh Button
-    refresh_button = ctk.CTkButton(
-        frame, text="Refresh", command=fetch_and_display_shop
-    )
-    refresh_button.pack(pady=10)
-
-    # Back Button
-    back_button = ctk.CTkButton(
-        frame, text="Back", command=lambda: switch_func("login")
-    )
-    back_button.pack(pady=10)
-
-    # Fetch shop data on load
-    fetch_and_display_shop()
+    # If shop_data is None, show a message and a button to create a shop.
+    if shop_data is None:
+        msg = ctk.CTkLabel(frame, text="No shop created yet.", font=("Helvetica", 16, "bold"))
+        msg.pack(pady=20)
+        create_button = ctk.CTkButton(frame, text="Create Shop", command=lambda: switch_func("create_shop"))
+        create_button.pack(pady=10)
+        return frame
+
+    # Otherwise, proceed normally.
+    shop_name = shop_data.get("name", "No Name")
+    shop_image_url = shop_data.get("image_url", "")
+
+    # Header: Shop Image and Name
+    header_frame = ctk.CTkFrame(frame)
+    header_frame.pack(pady=10, fill="x")
+
+    image_label = ctk.CTkLabel(header_frame, text="")
+    image_label.pack(side="left", padx=10)
+    try:
+        resp = requests.get(shop_image_url)
+        if resp.status_code == 200:
+            pil_img = Image.open(io.BytesIO(resp.content)).resize((80, 80))
+            tk_img = ImageTk.PhotoImage(pil_img)
+            image_label.configure(image=tk_img, text="")
+            image_label.image = tk_img
+    except Exception as e:
+        print("Error loading shop image:", e)
+    name_label = ctk.CTkLabel(header_frame, text=shop_name, font=("Helvetica", 16, "bold"))
+    name_label.pack(side="left", padx=10)
+
+    # Button to create a new product
+    def goto_create_product():
+        switch_func("create_product", shop_data)
+    create_prod_button = ctk.CTkButton(frame, text="Add New Product", command=goto_create_product)
+    create_prod_button.pack(pady=10)
+
+    # Products list
+    products_frame = ctk.CTkScrollableFrame(frame, width=750, height=300)
+    products_frame.pack(padx=10, pady=10, fill="both", expand=True)
+
+    headers = {"Authorization": f"Bearer {token}"}
+    try:
+        resp = requests.get(f"{API_URL}/product/list?shop_id={shop_data.get('id')}", headers=headers)
+        if resp.status_code == 200:
+            products = resp.json()
+            if products:
+                for product in products:
+                    prod_frame = ctk.CTkFrame(products_frame, fg_color="#2b2b2b", corner_radius=5)
+                    prod_frame.pack(padx=5, pady=5, fill="x")
+                    prod_name = product.get("name", "No Name")
+                    prod_label = ctk.CTkLabel(prod_frame, text=prod_name, font=("Helvetica", 12, "bold"))
+                    prod_label.pack(side="left", padx=10)
+                    # Optionally, add more product details here
+            else:
+                ctk.CTkLabel(products_frame, text="No products found.").pack(pady=10)
+        else:
+            messagebox.showerror("Error", f"Failed to fetch products. Status: {resp.status_code}")
+    except Exception as e:
+        messagebox.showerror("Error", f"Request error: {e}")
 
     return frame
diff --git a/app/frontend/components/user_details.py b/app/frontend/components/user_details.py
index a6b1a8f..efa7fd2 100644
--- a/app/frontend/components/user_details.py
+++ b/app/frontend/components/user_details.py
@@ -8,168 +8,102 @@ SHOPPING = "#00c1ff"
 
 def user_details_frame(parent, switch_func, API_URL, token):
     """
-    A two-column user details page that matches the dashboard color scheme:
-      - Top bar with SHOPPING color (#00c1ff)
-      - Left sidebar with a dark background (#2b2b2b)
-      - Right content area (profile form, profile picture)
+    User details page with a "Become Shop Owner" button.
+    When clicked, it calls switch_func("create_shop") to navigate to shop creation.
     """
-
-    # Main container frame (transparent background, like dashboard)
+    # Main container frame
     frame = ctk.CTkFrame(parent, fg_color="transparent")
 
-    # ----------------- TOP BAR -----------------
+    # --- TOP BAR ---
     top_bar = ctk.CTkFrame(frame, fg_color=SHOPPING, height=40)
     top_bar.pack(fill="x", side="top")
 
-    top_label = ctk.CTkLabel(
-        top_bar,
-        text="My Profile",
-        text_color="white",
-        font=("Helvetica", 16, "bold"),
-    )
-    top_label.pack(side="left", padx=20)
+    top_label = ctk.CTkLabel(top_bar, text="My Profile", text_color="white", font=("Helvetica", 16, "bold"))
+    top_label.pack(side="left", padx=21)
 
     def go_back():
         switch_func("dashboard")
-
-    back_button = ctk.CTkButton(
-        top_bar,
-        text="Back",
-        fg_color="white",
-        text_color="black",
-        command=go_back,
-        width=60,
-        height=30,
-    )
+    back_button = ctk.CTkButton(top_bar, text="Back", fg_color="white", text_color="black",
+                                command=go_back, width=60, height=30)
     back_button.pack(side="right", padx=20, pady=5)
 
-    # ----------------- MAIN SECTION (Sidebar + Content) -----------------
+    # --- MAIN SECTION: Sidebar + Content ---
     main_section = ctk.CTkFrame(frame, fg_color="transparent")
     main_section.pack(fill="both", expand=True)
 
-    # ----------------- LEFT SIDEBAR -----------------
-
+    # LEFT SIDEBAR
     sidebar_frame = ctk.CTkFrame(main_section, width=200, fg_color="#2b2b2b")
     sidebar_frame.pack(side="left", fill="y")
-
-    sidebar_title = ctk.CTkLabel(
-        sidebar_frame, 
-        text="Menu", 
-        font=("Helvetica", 14, "bold"), 
-        text_color="white"
-    )
+    sidebar_title = ctk.CTkLabel(sidebar_frame, text="Menu", font=("Helvetica", 14, "bold"), text_color="white")
     sidebar_title.pack(pady=(10, 5))
-
-    nav_dashboard = ctk.CTkButton(
-        sidebar_frame,
-        text="Dashboard",
-        fg_color="#2b2b2b",
-        text_color="white",
-        hover_color="#3b3b3b",
-        command=go_back
-    )
+    nav_dashboard = ctk.CTkButton(sidebar_frame, text="Dashboard", fg_color="#2b2b2b", text_color="white",
+                                  hover_color="#3b3b3b", command=go_back)
     nav_dashboard.pack(fill="x", padx=10, pady=5)
-
-    nav_profile = ctk.CTkButton(
-        sidebar_frame,
-        text="My Profile",
-        fg_color="#3b3b3b",  # Active/selected state
-        text_color="white",
-        hover_color="#3b3b3b",
-        state="disabled"
-    )
+    nav_profile = ctk.CTkButton(sidebar_frame, text="My Profile", fg_color="#3b3b3b",
+                                text_color="white", hover_color="#3b3b3b", state="disabled")
     nav_profile.pack(fill="x", padx=10, pady=5)
-
-    nav_orders = ctk.CTkButton(
-        sidebar_frame,
-        text="My Orders",
-        fg_color="#2b2b2b",
-        text_color="white",
-        hover_color="#3b3b3b",
-        command=lambda: switch_func("user_orders")
-    )
+    nav_orders = ctk.CTkButton(sidebar_frame, text="My Orders", fg_color="#2b2b2b", text_color="white",
+                               hover_color="#3b3b3b", command=lambda: switch_func("user_orders"))
     nav_orders.pack(fill="x", padx=10, pady=5)
+    # NEW: Become Shop Owner button
+    become_owner = ctk.CTkButton(sidebar_frame, text="Become Shop Owner", fg_color="#2b2b2b",
+                                 text_color="white", hover_color="#3b3b3b", command=lambda: switch_func("create_shop"))
+    become_owner.pack(fill="x", padx=10, pady=5)
 
-    # ----------------- RIGHT CONTENT (User Details) -----------------
+    # RIGHT CONTENT (User Details Form)
     content_frame = ctk.CTkFrame(main_section, fg_color="transparent")
     content_frame.pack(side="left", fill="both", expand=True, padx=20, pady=20)
+    title_label = ctk.CTkLabel(content_frame, text="My Profile", font=("Helvetica", 18, "bold"), text_color="white")
+    title_label.pack(anchor="w", pady=(0,5))
+    subtitle_label = ctk.CTkLabel(content_frame, text="Manage your profile information to keep your account secure",
+                                  font=("Helvetica", 12), text_color="#cccccc")
+    subtitle_label.pack(anchor="w", pady=(0,15))
 
-    # Title / Subtitle
-    title_label = ctk.CTkLabel(
-        content_frame,
-        text="My Profile",
-        font=("Helvetica", 18, "bold"),
-        text_color="white"
-    )
-    title_label.pack(anchor="w", pady=(0, 5))
-
-    subtitle_label = ctk.CTkLabel(
-        content_frame,
-        text="Manage your profile information to keep your account secure",
-        font=("Helvetica", 12),
-        text_color="#cccccc"
-    )
-    subtitle_label.pack(anchor="w", pady=(0, 15))
-
-    # -- Split the right content into two frames: Left form & Right picture --
     right_main = ctk.CTkFrame(content_frame, fg_color="transparent")
     right_main.pack(fill="both", expand=True)
 
     # LEFT FORM
     form_frame = ctk.CTkFrame(right_main, fg_color="transparent")
-    form_frame.pack(side="left", fill="both", expand=True, padx=(0, 20))
-
+    form_frame.pack(side="left", fill="both", expand=True, padx=(0,20))
     # Username
     username_label = ctk.CTkLabel(form_frame, text="Username", font=("Helvetica", 12), text_color="white")
     username_label.pack(anchor="w")
     username_entry = ctk.CTkEntry(form_frame, placeholder_text="Enter your username...")
-    username_entry.pack(anchor="w", pady=(0, 10))
-
+    username_entry.pack(anchor="w", pady=(0,10))
     # Name
     name_label = ctk.CTkLabel(form_frame, text="Name", font=("Helvetica", 12), text_color="white")
     name_label.pack(anchor="w")
     name_entry = ctk.CTkEntry(form_frame, placeholder_text="Enter your name...")
-    name_entry.pack(anchor="w", pady=(0, 10))
-
+    name_entry.pack(anchor="w", pady=(0,10))
     # Email
     email_label = ctk.CTkLabel(form_frame, text="Email", font=("Helvetica", 12), text_color="white")
     email_label.pack(anchor="w")
     email_entry = ctk.CTkEntry(form_frame, placeholder_text="Enter your email...")
-    email_entry.pack(anchor="w", pady=(0, 10))
-
+    email_entry.pack(anchor="w", pady=(0,10))
     # Phone
     phone_label = ctk.CTkLabel(form_frame, text="Phone", font=("Helvetica", 12), text_color="white")
     phone_label.pack(anchor="w")
     phone_entry = ctk.CTkEntry(form_frame, placeholder_text="Enter your phone...")
-    phone_entry.pack(anchor="w", pady=(0, 10))
-
+    phone_entry.pack(anchor="w", pady=(0,10))
     # Gender
     gender_label = ctk.CTkLabel(form_frame, text="Gender", font=("Helvetica", 12), text_color="white")
-    gender_label.pack(anchor="w", pady=(10, 0))
-
-    gender_var = ctk.StringVar(value="Male")  # Default
+    gender_label.pack(anchor="w", pady=(10,0))
+    gender_var = ctk.StringVar(value="Male")
     gender_frame = ctk.CTkFrame(form_frame, fg_color="transparent")
     gender_frame.pack(anchor="w", pady=5)
-
     male_radio = ctk.CTkRadioButton(gender_frame, text="Male", variable=gender_var, value="Male", text_color="white")
     female_radio = ctk.CTkRadioButton(gender_frame, text="Female", variable=gender_var, value="Female", text_color="white")
     other_radio = ctk.CTkRadioButton(gender_frame, text="Other", variable=gender_var, value="Other", text_color="white")
     male_radio.pack(side="left", padx=5)
     female_radio.pack(side="left", padx=5)
     other_radio.pack(side="left", padx=5)
-
     # Birthday
     birthday_label = ctk.CTkLabel(form_frame, text="Date of Birth", font=("Helvetica", 12), text_color="white")
-    birthday_label.pack(anchor="w", pady=(10, 0))
+    birthday_label.pack(anchor="w", pady=(10,0))
     birthday_entry = ctk.CTkEntry(form_frame, placeholder_text="dd/mm/yyyy")
-    birthday_entry.pack(anchor="w", pady=(0, 10))
-
+    birthday_entry.pack(anchor="w", pady=(0,10))
     # Save Button
     def save_profile():
-        """
-        Example: Send a request to update user details.
-        Adjust the endpoint and payload for your backend.
-        """
         headers = {"Authorization": f"Bearer {token}"}
         payload = {
             "username": username_entry.get().strip(),
@@ -187,67 +121,35 @@ def user_details_frame(parent, switch_func, API_URL, token):
                 messagebox.showerror("Error", "Unable to update profile.")
         except Exception as e:
             messagebox.showerror("Error", f"Request error: {e}")
-
-    save_button = ctk.CTkButton(
-        form_frame,
-        text="Save",
-        fg_color=SHOPPING,  # #00c1ff
-        text_color="white",
-        command=save_profile,
-        width=80
-    )
-    save_button.pack(anchor="w", pady=(20, 10))
+    save_button = ctk.CTkButton(form_frame, text="Save", fg_color=SHOPPING, text_color="white",
+                                command=save_profile, width=80)
+    save_button.pack(anchor="w", pady=(20,10))
 
     # RIGHT PICTURE SECTION
     pic_frame = ctk.CTkFrame(right_main, fg_color="transparent")
     pic_frame.pack(side="left", fill="both", expand=True)
-
     pic_label = ctk.CTkLabel(pic_frame, text="Profile Picture", font=("Helvetica", 12, "bold"), text_color="white")
-    pic_label.pack(anchor="w", pady=(0, 10))
-
+    pic_label.pack(anchor="w", pady=(0,10))
     photo_label = ctk.CTkLabel(pic_frame, text="No image", text_color="white")
-    photo_label.pack(anchor="w", pady=(0, 10))
-
+    photo_label.pack(anchor="w", pady=(0,10))
     def choose_photo():
-        """
-        Let the user pick a photo from their files.
-        Then optionally upload it or just display it.
-        """
         file_path = filedialog.askopenfilename(
             title="Choose a Profile Picture",
             filetypes=[("Image Files", "*.png *.jpg *.jpeg *.gif")]
         )
         if file_path:
-            # Display chosen image
             try:
                 pil_img = Image.open(file_path).resize((100, 100))
                 tk_img = ImageTk.PhotoImage(pil_img)
                 photo_label.configure(image=tk_img, text="")
                 photo_label.image = tk_img
-
-                # Optionally, upload the file to your server:
-                # headers = {"Authorization": f"Bearer {token}"}
-                # with open(file_path, 'rb') as f:
-                #     requests.post(f'{API_URL}/user/upload_photo', files={'file': f}, headers=headers)
             except Exception as e:
                 print(f"Image load error: {e}")
                 messagebox.showerror("Error", "Cannot load the image.")
-
-    change_photo_button = ctk.CTkButton(
-        pic_frame,
-        text="Choose Image",
-        fg_color="white",
-        text_color="black",
-        command=choose_photo,
-        width=80
-    )
+    change_photo_button = ctk.CTkButton(pic_frame, text="Choose Image", fg_color="white", text_color="black",
+                                        command=choose_photo, width=80)
     change_photo_button.pack(anchor="w")
-
-    # Fetch existing user info (if needed)
     def fetch_user_info():
-        """
-        Fetch the user's existing data to populate the form fields.
-        """
         headers = {"Authorization": f"Bearer {token}"}
         try:
             resp = requests.get(f"{API_URL}/user/profile", headers=headers)
@@ -264,8 +166,6 @@ def user_details_frame(parent, switch_func, API_URL, token):
                 gender_var.set(data.get("gender", "Male"))
                 birthday_entry.delete(0, "end")
                 birthday_entry.insert(0, data.get("birthday", ""))
-
-                # If there's a profile picture URL, load it
                 pic_url = data.get("photo_url")
                 if pic_url:
                     try:
@@ -281,7 +181,6 @@ def user_details_frame(parent, switch_func, API_URL, token):
                 messagebox.showerror("Error", "Unable to retrieve user information.")
         except Exception as e:
             messagebox.showerror("Error", f"Request error: {e}")
-
     fetch_user_info()
 
     return frame
diff --git a/app/frontend/main.py b/app/frontend/main.py
index 65b8f0a..6a77c15 100644
--- a/app/frontend/main.py
+++ b/app/frontend/main.py
@@ -3,26 +3,35 @@ from components.auth.login import login_frame
 from components.auth.register import register_frame
 from components.shop.create_shop import create_shop_frame
 from components.shop.view_shop import view_shop_frame
-from components.product.create_product import product_frame
+from components.product.create_product import create_product_frame
 from components.admin.category import category_frame
 from components.dashboard import dashboard_frame
 from components.user_details import user_details_frame
 from components.user_orders import user_orders_frame
 
 API_URL = "http://127.0.0.1:8000"
-access_token = None
+access_token = None  # Global token
 
-
-def switch_frame(frame_name, token=None):
+def switch_frame(frame_name, *args):
+    """
+    Switch between frames.
+    Optionally, additional data (like shop_data) can be passed as extra arguments.
+    """
     global access_token
-    if token:
-        access_token = token
+    if args and args[0] and isinstance(args[0], str):
+        access_token = args[0]
+
+    frame = frames.get(frame_name)
+    if frame is None:
+        print(f"Frame {frame_name} not found!")
+        return
 
-    frame = frames.get(frame_name, login)
     if hasattr(frame, "update_token"):
         frame.update_token(access_token)
-    frame.tkraise()
+    if hasattr(frame, "refresh_data") and len(args) > 0:
+        frame.refresh_data(*args)
 
+    frame.tkraise()
 
 ctk.set_appearance_mode("dark")
 ctk.set_default_color_theme("blue")
@@ -31,12 +40,13 @@ root = ctk.CTk()
 root.title("Shopping App")
 root.geometry("1000x800")
 
-# Create Frames
+# Create Frames with the token parameter where needed.
 login = login_frame(root, switch_frame, API_URL)
 register = register_frame(root, switch_frame, API_URL)
-create_shop = create_shop_frame(root, switch_frame, API_URL, access_token)
-view_shop = view_shop_frame(root, switch_frame, API_URL, access_token)
-product = product_frame(root, switch_frame, API_URL, access_token)
+create_shop = create_shop_frame(root, switch_frame, API_URL, access_token)  # Accepts token
+# Pass a placeholder (None) for shop_data in view_shop_frame
+view_shop = view_shop_frame(root, switch_frame, None, access_token, API_URL)
+product = create_product_frame(root, switch_frame, API_URL, access_token)
 category = category_frame(root, switch_frame, API_URL, access_token)
 dashboard = dashboard_frame(root, switch_frame, API_URL, access_token)
 user_details = user_details_frame(root, switch_frame, API_URL, access_token)
@@ -55,11 +65,7 @@ frames = {
 }
 
 for frame in frames.values():
-    frame.place(
-        relx=0, rely=0, relwidth=1, relheight=1
-    )  # Adjusted height for full scaling
+    frame.place(relx=0, rely=0, relwidth=1, relheight=1)
 
-# Show the login frame first
 switch_frame("login")
-
 root.mainloop()
-- 
GitLab