diff --git a/README.md b/README.md
index e6f391a67fdeb8f900d22d3500df1922031dfafa..d45c9661804c16d0cf01e851fb27386d29230cd6 100644
--- a/README.md
+++ b/README.md
@@ -17,3 +17,23 @@ create `.env` file based on `.env.example` in the main directory
 - open terminal and use \
   `uvicorn app.backend.main:app --reload`
 - open `127.0.0.1:8000/docs` on your browser
+
+# 5: Admin Dashboard
+
+The application includes an admin dashboard with the following features:
+
+- User Management: View and delete regular user accounts
+- Shop Owner Management: View and delete shop owner accounts, including viewing their shops
+- Category Management: Create, update, and delete product categories
+
+## Default Admin Credentials
+
+- Username/Email: admin@example.com
+- Password: admin
+
+The default admin user is automatically created on first run of the application.
+
+To run the full application (backend + frontend):
+```
+python run_app.py
+```
diff --git a/app/backend/main.py b/app/backend/main.py
index a3d7cf5fcb1c4aeda5bcb822f6236951f9420992..8359b4538585e168370676b6c59ce2ae7c870bb2 100644
--- a/app/backend/main.py
+++ b/app/backend/main.py
@@ -14,6 +14,7 @@ from app.backend.routes import (
     order,
     payment,
     cart,
+    admin,
 )
 from app.backend.database import init_db
 from core.config import settings
@@ -41,6 +42,8 @@ app.include_router(order.router, prefix="/order", tags=["order"])
 app.include_router(order.router, prefix="/orders", tags=["orders"])
 # Use dedicated cart router
 app.include_router(cart.router, prefix="/cart", tags=["cart"])
+# Admin routes
+app.include_router(admin.router, prefix="/admin", tags=["admin"])
 
 
 @app.get("/")
diff --git a/app/backend/routes/admin.py b/app/backend/routes/admin.py
new file mode 100644
index 0000000000000000000000000000000000000000..698f4544a782367308cfbad89efe0de9a305439e
--- /dev/null
+++ b/app/backend/routes/admin.py
@@ -0,0 +1,179 @@
+from fastapi import APIRouter, Depends, HTTPException
+from sqlmodel import Session, select
+from app.backend.models.models import User, Shop, Category
+from app.backend.database import get_session
+from app.backend.routes.auth import get_current_user
+from typing import List
+
+router = APIRouter()
+
+
+def verify_admin(current_user: User):
+    """Verify that the current user is an admin"""
+    if current_user.role != "admin":
+        raise HTTPException(
+            status_code=403, detail="Unauthorized. Admin access required."
+        )
+
+
+@router.get("/users")
+def get_all_users(
+    session: Session = Depends(get_session),
+    current_user: User = Depends(get_current_user),
+):
+    """Get all users"""
+    verify_admin(current_user)
+
+    users = session.exec(select(User)).all()
+    return users
+
+
+@router.get("/users/{user_id}")
+def get_user(
+    user_id: int,
+    session: Session = Depends(get_session),
+    current_user: User = Depends(get_current_user),
+):
+    """Get a specific user"""
+    verify_admin(current_user)
+
+    user = session.get(User, user_id)
+    if not user:
+        raise HTTPException(status_code=404, detail="User not found")
+    return user
+
+
+@router.delete("/users/{user_id}")
+def delete_user(
+    user_id: int,
+    session: Session = Depends(get_session),
+    current_user: User = Depends(get_current_user),
+):
+    """Delete a user (ban)"""
+    verify_admin(current_user)
+
+    # Prevent admin from deleting themselves
+    if user_id == current_user.id:
+        raise HTTPException(status_code=400, detail="Cannot delete own account")
+
+    # Prevent admin from deleting other admins
+    user = session.get(User, user_id)
+    if not user:
+        raise HTTPException(status_code=404, detail="User not found")
+
+    if user.role == "admin":
+        raise HTTPException(status_code=400, detail="Cannot delete admin accounts")
+
+    # Delete the user
+    session.delete(user)
+    session.commit()
+
+    return {"message": "User deleted successfully"}
+
+
+@router.get("/owners")
+def get_shop_owners(
+    session: Session = Depends(get_session),
+    current_user: User = Depends(get_current_user),
+):
+    """Get all shop owners"""
+    verify_admin(current_user)
+
+    # Get users with role="shop_owner"
+    shop_owners = session.exec(select(User).where(User.role == "shop_owner")).all()
+
+    # For each shop owner, get their shops
+    for owner in shop_owners:
+        owner.shops = session.exec(select(Shop).where(Shop.owner_id == owner.id)).all()
+
+    return shop_owners
+
+
+@router.get("/owners/{owner_id}")
+def get_shop_owner(
+    owner_id: int,
+    session: Session = Depends(get_session),
+    current_user: User = Depends(get_current_user),
+):
+    """Get a specific shop owner"""
+    verify_admin(current_user)
+
+    owner = session.get(User, owner_id)
+    if not owner:
+        raise HTTPException(status_code=404, detail="Shop owner not found")
+
+    if owner.role != "shop_owner":
+        raise HTTPException(status_code=400, detail="User is not a shop owner")
+
+    # Get the owner's shops
+    owner.shops = session.exec(select(Shop).where(Shop.owner_id == owner.id)).all()
+
+    return owner
+
+
+@router.get("/owners/{owner_id}/shops")
+def get_owner_shops(
+    owner_id: int,
+    session: Session = Depends(get_session),
+    current_user: User = Depends(get_current_user),
+):
+    """Get shops owned by a specific shop owner"""
+    verify_admin(current_user)
+
+    # Check if the owner exists
+    owner = session.get(User, owner_id)
+    if not owner:
+        raise HTTPException(status_code=404, detail="Shop owner not found")
+
+    if owner.role != "shop_owner":
+        raise HTTPException(status_code=400, detail="User is not a shop owner")
+
+    # Get the owner's shops
+    shops = session.exec(select(Shop).where(Shop.owner_id == owner_id)).all()
+
+    return shops
+
+
+@router.delete("/owners/{owner_id}")
+def delete_shop_owner(
+    owner_id: int,
+    session: Session = Depends(get_session),
+    current_user: User = Depends(get_current_user),
+):
+    """Delete a shop owner (ban)"""
+    verify_admin(current_user)
+
+    # Prevent admin from deleting themselves
+    if owner_id == current_user.id:
+        raise HTTPException(status_code=400, detail="Cannot delete own account")
+
+    # Verify the owner exists
+    owner = session.get(User, owner_id)
+    if not owner:
+        raise HTTPException(status_code=404, detail="Shop owner not found")
+
+    if owner.role != "shop_owner":
+        raise HTTPException(status_code=400, detail="User is not a shop owner")
+
+    # Delete all shops owned by this user first
+    shops = session.exec(select(Shop).where(Shop.owner_id == owner_id)).all()
+    for shop in shops:
+        session.delete(shop)
+
+    # Delete the owner
+    session.delete(owner)
+    session.commit()
+
+    return {"message": "Shop owner deleted successfully"}
+
+
+@router.get("/categories")
+def get_all_categories(
+    session: Session = Depends(get_session),
+    current_user: User = Depends(get_current_user),
+):
+    """Get all categories for admin panel"""
+    verify_admin(current_user)
+
+    categories = session.exec(select(Category)).all()
+    return categories
diff --git a/app/backend/routes/category.py b/app/backend/routes/category.py
index 69a0e433508bdbfa646dd23aa727ca9a97904291..056165ddee49627d7b42879b4da403dbc2876f92 100644
--- a/app/backend/routes/category.py
+++ b/app/backend/routes/category.py
@@ -1,9 +1,11 @@
 from fastapi import APIRouter, Depends, HTTPException, Form
-from sqlmodel import Session
-from app.backend.models.models import Category, User
+from sqlmodel import Session, select
+from app.backend.models.models import Category, User, Product
 from app.backend.schemas.category import CategoryRead
 from app.backend.database import get_session
 from app.backend.routes.auth import get_current_user
+from typing import List
+from sqlalchemy.exc import IntegrityError
 
 router = APIRouter()
 
@@ -23,11 +25,26 @@ def create_category(
 ):
     verify_admin(current_user)
 
+    # Check if category with this name already exists
+    existing_category = session.exec(
+        select(Category).where(Category.name == name)
+    ).first()
+    if existing_category:
+        raise HTTPException(
+            status_code=400, detail=f"Category with name '{name}' already exists"
+        )
+
     category = Category(name=name)
     session.add(category)
-    session.commit()
-    session.refresh(category)
-    return category
+    try:
+        session.commit()
+        session.refresh(category)
+        return category
+    except IntegrityError:
+        session.rollback()
+        raise HTTPException(
+            status_code=400, detail=f"Category with name '{name}' already exists"
+        )
 
 
 @router.get("/get/{category_id}", response_model=CategoryRead)
@@ -51,12 +68,27 @@ def update_category(
         raise HTTPException(status_code=404, detail="Category not found")
 
     if name:
+        # Check if another category already has this name
+        existing_category = session.exec(
+            select(Category).where(Category.name == name, Category.id != category_id)
+        ).first()
+        if existing_category:
+            raise HTTPException(
+                status_code=400, detail=f"Category with name '{name}' already exists"
+            )
         category.name = name
 
     session.add(category)
-    session.commit()
-    session.refresh(category)
-    return category
+    try:
+        session.commit()
+        session.refresh(category)
+        return category
+    except IntegrityError:
+        session.rollback()
+        raise HTTPException(
+            status_code=400,
+            detail="Failed to update category. Name may be a duplicate.",
+        )
 
 
 @router.delete("/delete/{category_id}")
@@ -70,6 +102,26 @@ def delete_category(
     category = session.get(Category, category_id)
     if not category:
         raise HTTPException(status_code=404, detail="Category not found")
+
+    # Check if any products are using this category
+    products_using_category = session.exec(
+        select(Product).where(Product.category_id == category_id)
+    ).all()
+
+    if products_using_category:
+        product_count = len(products_using_category)
+        raise HTTPException(
+            status_code=400,
+            detail=f"Cannot delete category: {product_count} products are using this category. Please reassign or delete those products first.",
+        )
+
     session.delete(category)
     session.commit()
     return {"message": "Category deleted successfully"}
+
+
+@router.get("")
+def get_all_categories(session: Session = Depends(get_session)):
+    """Get all categories"""
+    categories = session.exec(select(Category)).all()
+    return categories
diff --git a/app/backend/routes/product.py b/app/backend/routes/product.py
index 2108a7c7465749f29c6a1d643d8440c3baa4da05..23c3d86d508b3c9337503b5b644d0836897ea82d 100644
--- a/app/backend/routes/product.py
+++ b/app/backend/routes/product.py
@@ -1,5 +1,6 @@
 from fastapi import APIRouter, Depends, HTTPException, UploadFile, File, Form
-from sqlmodel import Session, func
+from sqlmodel import Session, func, select
+from sqlalchemy.orm import joinedload
 from datetime import datetime
 from app.backend.models.models import (
     Product,
@@ -8,6 +9,7 @@ from app.backend.models.models import (
     Shop,
     OrderItem,
     CartItem,
+    Category,
 )
 from app.backend.schemas.product import ProductRead, ProductUpdate
 from app.backend.database import get_session
@@ -50,7 +52,7 @@ def create_product(
     )
     session.add(product)
     session.commit()
-    session.refresh(product)
+    session.refresh(product, ["category"])
 
     # Directory: static/shop_{shop.name}/product_{product.name}/
     shop_dir = os.path.join(settings.static_dir, f"shop_{shop.name}")
@@ -96,6 +98,9 @@ def read_all_products(order: str = "desc", session: Session = Depends(get_sessio
     )
     products = (
         session.query(Product)
+        .options(
+            joinedload(Product.category)
+        )  # Explicitly load the category relationship
         .outerjoin(OrderItem, Product.id == OrderItem.product_id)
         .group_by(Product.id)
         .order_by(order_by)
@@ -119,6 +124,9 @@ def get_shop_products(
     if shop.owner_id != current_user.id:
         products = (
             session.query(Product)
+            .options(
+                joinedload(Product.category)
+            )  # Explicitly load the category relationship
             .filter(
                 Product.shop_id == shop_id,
                 Product.stock > 0,  # Only available products
@@ -127,7 +135,14 @@ def get_shop_products(
         )
     else:
         # Shop owner can see all their products
-        products = session.query(Product).filter(Product.shop_id == shop_id).all()
+        products = (
+            session.query(Product)
+            .options(
+                joinedload(Product.category)
+            )  # Explicitly load the category relationship
+            .filter(Product.shop_id == shop_id)
+            .all()
+        )
 
     return products
 
@@ -137,6 +152,9 @@ def read_product(product_id: int, session: Session = Depends(get_session)):
     product = session.get(Product, product_id)
     if not product:
         raise HTTPException(status_code=404, detail="Product not found")
+
+    # Make sure category is loaded
+    session.refresh(product, ["category"])
     return product
 
 
@@ -147,7 +165,7 @@ def update_product(
     description: str = Form(...),
     price: float = Form(...),
     stock: int = Form(...),
-    category_id: int = Form(...),
+    category_id: int = Form(None),
     images: list[UploadFile] = File(...),
     session: Session = Depends(get_session),
     current_user: User = Depends(get_current_user),
@@ -166,7 +184,7 @@ def update_product(
 
     session.add(product)
     session.commit()
-    session.refresh(product)
+    session.refresh(product, ["category"])
 
     shop = session.get(Shop, product.shop_id)
     shop_dir = os.path.join(settings.static_dir, f"shop_{shop.name}")
diff --git a/app/backend/schemas/category.py b/app/backend/schemas/category.py
index 79fb6d00805529d7b177b9e4e5a0e7ea9ec409cb..1b4cf0db23eddb5c8ceb2116252305c4dec86f93 100644
--- a/app/backend/schemas/category.py
+++ b/app/backend/schemas/category.py
@@ -1,10 +1,13 @@
+from pydantic import BaseModel, ConfigDict
 from sqlmodel import SQLModel
 from typing import Optional
 
 
-class CategoryBase(SQLModel):
+class CategoryBase(BaseModel):
     name: str
 
+    model_config = ConfigDict(from_attributes=True)
+
 
 class CategoryCreate(CategoryBase):
     pass
@@ -13,6 +16,8 @@ class CategoryCreate(CategoryBase):
 class CategoryRead(CategoryBase):
     id: int
 
+    model_config = ConfigDict(from_attributes=True)
+
 
 class CategoryUpdate(SQLModel):
     name: Optional[str] = None
diff --git a/app/backend/schemas/product.py b/app/backend/schemas/product.py
index d76f9454afc8f55e6c45db69d8da40257944d21c..bb7d0b3ac7be9defd620cda17d2c343d0ad70ca2 100644
--- a/app/backend/schemas/product.py
+++ b/app/backend/schemas/product.py
@@ -1,8 +1,19 @@
 from pydantic import BaseModel, ConfigDict
-from typing import Optional, List
+from typing import Optional, List, ForwardRef
 from datetime import datetime
 
 
+class CategoryBase(BaseModel):
+    id: int
+    name: str
+
+    model_config = ConfigDict(from_attributes=True)
+
+
+# Forward references for circular relationships
+ProductImageRead = ForwardRef("ProductImageRead")
+
+
 class ProductBase(BaseModel):
     shop_id: int
     category_id: Optional[int] = None
@@ -19,7 +30,8 @@ class ProductCreate(ProductBase):
 class ProductRead(ProductBase):
     id: int
     created_at: datetime
-    images: List["ProductImageRead"] = []
+    images: List[ProductImageRead] = []
+    category: Optional[CategoryBase] = None
 
     model_config = ConfigDict(from_attributes=True)
 
diff --git a/app/backend/scripts/__init__.py b/app/backend/scripts/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..d089d7f8cf9257c24fd29ef9ab1b7d17988c7b13
--- /dev/null
+++ b/app/backend/scripts/__init__.py
@@ -0,0 +1,2 @@
+# Scripts for backend initialization and maintenance
+from .admin_init import init_admin 
\ No newline at end of file
diff --git a/app/backend/scripts/admin_init.py b/app/backend/scripts/admin_init.py
new file mode 100644
index 0000000000000000000000000000000000000000..5a52ec5d0d2c1cf0d936b00a1a2a50701e13b785
--- /dev/null
+++ b/app/backend/scripts/admin_init.py
@@ -0,0 +1,47 @@
+import sys
+import os
+
+# Add the parent directory to the path to allow importing from the backend
+sys.path.append(
+    os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+)
+
+from backend.database import get_session, engine
+from backend.models.models import SQLModel, User
+from backend.utils.hashing import hash_password
+from sqlmodel import select, Session
+
+
+def init_admin():
+    """Initialize a default admin user if no admin user exists"""
+    print("Initializing admin user...")
+
+    # Create all tables if they don't exist
+    SQLModel.metadata.create_all(engine)
+
+    with Session(engine) as session:
+        # Check if admin user already exists
+        admin = session.exec(select(User).where(User.role == "admin")).first()
+
+        if admin:
+            print("Admin user already exists.")
+            return
+
+        print("Creating default admin user...")
+        # Create default admin user with username and password both "admin"
+        hashed_password = hash_password("admin")
+        admin_user = User(
+            username="admin",
+            email="admin@example.com",
+            password=hashed_password,
+            phone_number="1234567890",
+            role="admin",
+        )
+
+        session.add(admin_user)
+        session.commit()
+        print("Default admin user created successfully!")
+
+
+if __name__ == "__main__":
+    init_admin()
diff --git a/app/frontend/components/admin/__init__.py b/app/frontend/components/admin/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..1f6bf6cc3bef5c81fa3b5b6bfa49d799e93a9a2d
--- /dev/null
+++ b/app/frontend/components/admin/__init__.py
@@ -0,0 +1,5 @@
+# Admin dashboard components
+from .dashboard import admin_dashboard_frame
+from .user_management import admin_user_management_frame
+from .shop_owner_management import admin_shop_owner_management_frame
+from .category import category_frame 
\ No newline at end of file
diff --git a/app/frontend/components/admin/category.py b/app/frontend/components/admin/category.py
index 29c239edd842ce2052b965c4c4ad1bd86d79c67f..3504aa38db65021accc1a065211c3b3827e63d34 100644
--- a/app/frontend/components/admin/category.py
+++ b/app/frontend/components/admin/category.py
@@ -1,117 +1,491 @@
 import customtkinter as ctk
+from CTkMessagebox import CTkMessagebox
 import requests
-from tkinter import messagebox
+from tkinter import ttk
+from datetime import datetime
 
 
 def category_frame(parent, switch_func, API_URL, access_token):
     frame = ctk.CTkFrame(parent)
 
+    # Update token function for consistency with other frames
+    def update_token(new_token):
+        nonlocal access_token
+        headers["Authorization"] = f"Bearer {new_token}"
+        access_token = new_token
+
+    frame.update_token = update_token
+
+    # Main container with padding
+    main_container = ctk.CTkFrame(frame, fg_color="transparent")
+    main_container.pack(padx=40, pady=30, fill="both", expand=True)
+
+    # Header section
+    header_frame = ctk.CTkFrame(main_container, corner_radius=15, fg_color="#9c27b0")
+    header_frame.pack(fill="x", pady=(0, 20))
+
+    # Title and description
+    title_frame = ctk.CTkFrame(header_frame, fg_color="transparent")
+    title_frame.pack(padx=20, pady=15)
+
+    ctk.CTkLabel(
+        title_frame,
+        text="Category Management",
+        font=("Helvetica", 24, "bold"),
+        text_color="#ffffff",
+    ).pack(anchor="w")
+
+    ctk.CTkLabel(
+        title_frame,
+        text="Create, view, update and delete product categories",
+        font=("Helvetica", 14),
+        text_color="#e0e0e0",
+    ).pack(anchor="w")
+
+    # Two column layout
+    content_frame = ctk.CTkFrame(main_container)
+    content_frame.pack(fill="both", expand=True)
+
+    # Left column - category form
+    form_frame = ctk.CTkFrame(content_frame, fg_color="transparent")
+    form_frame.pack(side="left", fill="both", expand=True, padx=20, pady=20)
+
+    # Form section title
     ctk.CTkLabel(
-        frame, text="Category Management", font=("Helvetica", 18, "bold")
-    ).pack(pady=10)
+        form_frame, text="Category Details", font=("Helvetica", 16, "bold")
+    ).pack(anchor="w", pady=(0, 15))
+
+    # Form fields with better spacing and styling
+    input_frame = ctk.CTkFrame(form_frame, fg_color="#f5f5f5", corner_radius=10)
+    input_frame.pack(fill="x", pady=10)
+
+    # Category name input
+    name_frame = ctk.CTkFrame(input_frame, fg_color="transparent")
+    name_frame.pack(fill="x", padx=20, pady=15)
+
+    ctk.CTkLabel(
+        name_frame,
+        text="Category Name:",
+        font=("Helvetica", 12, "bold"),
+        text_color="#333333",
+    ).pack(side="left", padx=(0, 10))
+
+    entry_name = ctk.CTkEntry(
+        name_frame, width=250, height=35, placeholder_text="Enter category name"
+    )
+    entry_name.pack(side="left", fill="x", expand=True)
+
+    # Category ID input (for update/delete)
+    id_frame = ctk.CTkFrame(input_frame, fg_color="transparent")
+    id_frame.pack(fill="x", padx=20, pady=15)
+
+    ctk.CTkLabel(
+        id_frame,
+        text="Category ID:",
+        font=("Helvetica", 12, "bold"),
+        text_color="#333333",
+    ).pack(side="left", padx=(0, 10))
+
+    entry_id = ctk.CTkEntry(
+        id_frame, width=150, height=35, placeholder_text="For update/delete"
+    )
+    entry_id.pack(side="left")
+
+    # Buttons frame
+    buttons_frame = ctk.CTkFrame(form_frame, fg_color="transparent")
+    buttons_frame.pack(fill="x", pady=15)
+
+    # Row 1 of buttons
+    buttons_row1 = ctk.CTkFrame(buttons_frame, fg_color="transparent")
+    buttons_row1.pack(fill="x", pady=5)
+
+    create_button = ctk.CTkButton(
+        buttons_row1,
+        text="Create Category",
+        font=("Helvetica", 12, "bold"),
+        height=40,
+        fg_color="#4caf50",
+        hover_color="#388e3c",
+        corner_radius=8,
+    )
+    create_button.pack(side="left", padx=(0, 10), fill="x", expand=True)
 
-    ctk.CTkLabel(frame, text="Category Name:").pack(pady=5)
-    entry_name = ctk.CTkEntry(frame)
-    entry_name.pack(pady=5)
+    update_button = ctk.CTkButton(
+        buttons_row1,
+        text="Update Category",
+        font=("Helvetica", 12, "bold"),
+        height=40,
+        fg_color="#ff9800",
+        hover_color="#f57c00",
+        corner_radius=8,
+    )
+    update_button.pack(side="left", fill="x", expand=True)
 
-    ctk.CTkLabel(frame, text="Category ID (for update/delete):").pack(pady=5)
-    entry_id = ctk.CTkEntry(frame)
-    entry_id.pack(pady=5)
+    # Row 2 of buttons
+    buttons_row2 = ctk.CTkFrame(buttons_frame, fg_color="transparent")
+    buttons_row2.pack(fill="x", pady=5)
 
+    list_button = ctk.CTkButton(
+        buttons_row2,
+        text="List Categories",
+        font=("Helvetica", 12, "bold"),
+        height=40,
+        fg_color="#3a7ebf",
+        hover_color="#2a6da9",
+        corner_radius=8,
+    )
+    list_button.pack(side="left", padx=(0, 10), fill="x", expand=True)
+
+    delete_button = ctk.CTkButton(
+        buttons_row2,
+        text="Delete Category",
+        font=("Helvetica", 12, "bold"),
+        height=40,
+        fg_color="#f44336",
+        hover_color="#d32f2f",
+        corner_radius=8,
+    )
+    delete_button.pack(side="left", fill="x", expand=True)
+
+    # Right column - category list table
+    table_frame = ctk.CTkFrame(content_frame)
+    table_frame.pack(side="right", fill="both", expand=True, padx=20, pady=20)
+
+    # Table title
+    ctk.CTkLabel(
+        table_frame, text="Category List", font=("Helvetica", 16, "bold")
+    ).pack(anchor="w", padx=15, pady=15)
+
+    # Create TreeView for categories
+    tree_container = ctk.CTkFrame(table_frame)
+    tree_container.pack(fill="both", expand=True, padx=15, pady=(0, 15))
+
+    # Configure Treeview style
+    style = ttk.Style()
+    style.theme_use("clam")  # Use clam theme as base
+
+    # Configure the Treeview colors to match app theme
+    style.configure(
+        "Treeview",
+        background="#2b2b2b",
+        foreground="#ffffff",
+        fieldbackground="#2b2b2b",
+        borderwidth=0,
+        rowheight=35,
+    )
+
+    # Configure the headings
+    style.configure(
+        "Treeview.Heading",
+        background="#9c27b0",
+        foreground="#ffffff",
+        borderwidth=0,
+        font=("Helvetica", 12, "bold"),
+    )
+
+    # Selection color
+    style.map("Treeview", background=[("selected", "#9c27b0")])
+
+    # Create scrollbar
+    scrollbar = ttk.Scrollbar(tree_container)
+    scrollbar.pack(side="right", fill="y")
+
+    # Create the TreeView
+    columns = ("id", "name", "total_products")
+    category_tree = ttk.Treeview(
+        tree_container, columns=columns, show="headings", yscrollcommand=scrollbar.set
+    )
+
+    # Configure scrollbar
+    scrollbar.config(command=category_tree.yview)
+
+    # Define headings
+    category_tree.heading("id", text="ID")
+    category_tree.heading("name", text="Category Name")
+    category_tree.heading("total_products", text="Products")
+
+    # Define column widths
+    category_tree.column("id", width=60, anchor="center")
+    category_tree.column("name", width=200)
+    category_tree.column("total_products", width=80, anchor="center")
+
+    # Add tag configurations
+    category_tree.tag_configure("odd", background="#252525")
+    category_tree.tag_configure("even", background="#2d2d2d")
+
+    category_tree.pack(fill="both", expand=True)
+
+    # Footer with back button
+    footer_frame = ctk.CTkFrame(main_container, fg_color="transparent", height=50)
+    footer_frame.pack(fill="x", pady=(15, 0))
+
+    back_button = ctk.CTkButton(
+        footer_frame,
+        text="Back to Admin Dashboard",
+        command=lambda: switch_func("admin_dashboard"),
+        font=("Helvetica", 12, "bold"),
+        height=40,
+        corner_radius=8,
+        fg_color="#555555",
+        hover_color="#444444",
+    )
+    back_button.pack(side="left")
+
+    # Set up auth headers
     headers = {"Authorization": f"Bearer {access_token}"} if access_token else {}
 
+    # Enhanced category functions with table updates
+    def fetch_categories():
+        """Fetch and display categories in the treeview"""
+        try:
+            response = requests.get(f"{API_URL}/admin/categories", headers=headers)
+            if response.status_code == 200:
+                # Clear existing items
+                for item in category_tree.get_children():
+                    category_tree.delete(item)
+
+                categories = response.json()
+
+                if categories:
+                    for i, cat in enumerate(categories):
+                        # Get product count (placeholder - would need backend support)
+                        product_count = len(cat.get("products", []))
+
+                        # Add with alternating row colors
+                        tag = "even" if i % 2 == 0 else "odd"
+                        category_tree.insert(
+                            "",
+                            "end",
+                            values=(cat["id"], cat["name"], product_count),
+                            tags=(tag,),
+                        )
+                else:
+                    # Empty message could be displayed here
+                    pass
+
+                return categories
+            elif response.status_code == 403:
+                CTkMessagebox(
+                    title="Error",
+                    message="Unauthorized. Admin access required.",
+                    icon="cancel",
+                )
+                return []
+            else:
+                CTkMessagebox(
+                    title="Error", message="Failed to fetch categories", icon="cancel"
+                )
+                return []
+        except requests.exceptions.RequestException as e:
+            CTkMessagebox(
+                title="Error",
+                message=f"Failed to connect to server: {e}",
+                icon="cancel",
+            )
+            return []
+
     def create_category():
         name = entry_name.get().strip()
         if not name:
-            messagebox.showwarning("Input Error", "Category name is required!")
+            CTkMessagebox(
+                title="Input Error",
+                message="Category name is required!",
+                icon="warning",
+            )
             return
 
         try:
             response = requests.post(
-                f"{API_URL}/category", data={"name": name}, headers=headers
+                f"{API_URL}/category/create", data={"name": name}, headers=headers
             )
             if response.status_code == 200:
-                messagebox.showinfo(
-                    "Success", f"Category '{name}' created successfully!"
+                CTkMessagebox(
+                    title="Success",
+                    message=f"Category '{name}' created successfully!",
+                    icon="check",
                 )
                 entry_name.delete(0, "end")
-            else:
-                messagebox.showerror(
-                    "Error", response.json().get("detail", "Failed to create category")
+                fetch_categories()  # Refresh the list
+            elif response.status_code == 403:
+                CTkMessagebox(
+                    title="Error",
+                    message="Unauthorized. Admin access required.",
+                    icon="cancel",
                 )
-        except requests.exceptions.RequestException as e:
-            messagebox.showerror("Error", f"Failed to connect to server: {e}")
-
-    def list_categories():
-        try:
-            response = requests.get(f"{API_URL}/category", headers=headers)
-            if response.status_code == 200:
-                categories = response.json()
-                if categories:
-                    category_list = "\n".join(
-                        [f"{cat['id']}: {cat['name']}" for cat in categories]
-                    )
-                    messagebox.showinfo("Categories", category_list)
-                else:
-                    messagebox.showinfo("Categories", "No categories available.")
             else:
-                messagebox.showerror("Error", "Failed to fetch categories")
+                error_detail = "Failed to create category"
+                try:
+                    error_data = response.json()
+                    if "detail" in error_data:
+                        error_detail = error_data["detail"]
+                except:
+                    pass
+                CTkMessagebox(title="Error", message=error_detail, icon="cancel")
         except requests.exceptions.RequestException as e:
-            messagebox.showerror("Error", f"Failed to connect to server: {e}")
+            CTkMessagebox(
+                title="Error",
+                message=f"Failed to connect to server: {e}",
+                icon="cancel",
+            )
+
+    def list_categories_dialog():
+        """Show categories in a dialog and also update the treeview"""
+        categories = fetch_categories()
+
+        if categories:
+            category_list = "\n".join(
+                [f"{cat['id']}: {cat['name']}" for cat in categories]
+            )
+            CTkMessagebox(title="Categories", message=category_list, icon="info")
+        else:
+            CTkMessagebox(
+                title="Categories", message="No categories available.", icon="info"
+            )
 
     def update_category():
         category_id = entry_id.get().strip()
         name = entry_name.get().strip()
         if not category_id.isdigit():
-            messagebox.showwarning("Input Error", "Enter a valid Category ID!")
+            CTkMessagebox(
+                title="Input Error",
+                message="Enter a valid Category ID!",
+                icon="warning",
+            )
             return
         if not name:
-            messagebox.showwarning(
-                "Input Error", "Category name is required for update!"
+            CTkMessagebox(
+                title="Input Error",
+                message="Category name is required for update!",
+                icon="warning",
             )
             return
 
         try:
             response = requests.put(
-                f"{API_URL}/category/{category_id}",
+                f"{API_URL}/category/put/{category_id}",
                 data={"name": name},
                 headers=headers,
             )
             if response.status_code == 200:
-                messagebox.showinfo("Success", "Category updated successfully!")
+                CTkMessagebox(
+                    title="Success",
+                    message="Category updated successfully!",
+                    icon="check",
+                )
                 entry_id.delete(0, "end")
                 entry_name.delete(0, "end")
-            else:
-                messagebox.showerror(
-                    "Error", response.json().get("detail", "Failed to update category")
+                fetch_categories()  # Refresh the list
+            elif response.status_code == 403:
+                CTkMessagebox(
+                    title="Error",
+                    message="Unauthorized. Admin access required.",
+                    icon="cancel",
                 )
+            else:
+                error_detail = "Failed to update category"
+                try:
+                    error_data = response.json()
+                    if "detail" in error_data:
+                        error_detail = error_data["detail"]
+                except:
+                    pass
+                CTkMessagebox(title="Error", message=error_detail, icon="cancel")
         except requests.exceptions.RequestException as e:
-            messagebox.showerror("Error", f"Failed to connect to server: {e}")
+            CTkMessagebox(
+                title="Error",
+                message=f"Failed to connect to server: {e}",
+                icon="cancel",
+            )
 
     def delete_category():
         category_id = entry_id.get().strip()
         if not category_id.isdigit():
-            messagebox.showwarning("Input Error", "Enter a valid Category ID!")
+            CTkMessagebox(
+                title="Input Error",
+                message="Enter a valid Category ID!",
+                icon="warning",
+            )
             return
 
         try:
             response = requests.delete(
-                f"{API_URL}/category/{category_id}", headers=headers
+                f"{API_URL}/category/delete/{category_id}", headers=headers
             )
             if response.status_code == 200:
-                messagebox.showinfo("Success", "Category deleted successfully!")
+                CTkMessagebox(
+                    title="Success",
+                    message="Category deleted successfully!",
+                    icon="check",
+                )
                 entry_id.delete(0, "end")
-            else:
-                messagebox.showerror(
-                    "Error", response.json().get("detail", "Failed to delete category")
+                fetch_categories()  # Refresh the list
+            elif response.status_code == 403:
+                CTkMessagebox(
+                    title="Error",
+                    message="Unauthorized. Admin access required.",
+                    icon="cancel",
                 )
+            elif response.status_code == 400:
+                try:
+                    error_data = response.json()
+                    error_message = error_data.get(
+                        "detail", "Failed to delete category"
+                    )
+
+                    # Check if the error is about products using the category
+                    if "products are using this category" in error_message:
+                        CTkMessagebox(
+                            title="Cannot Delete Category",
+                            message=error_message,
+                            icon="warning",
+                        )
+                    else:
+                        CTkMessagebox(
+                            title="Error", message=error_message, icon="cancel"
+                        )
+                except:
+                    CTkMessagebox(
+                        title="Error",
+                        message="Failed to delete category. Please try again.",
+                        icon="cancel",
+                    )
+            else:
+                error_detail = "Failed to delete category"
+                try:
+                    error_data = response.json()
+                    if "detail" in error_data:
+                        error_detail = error_data["detail"]
+                except:
+                    pass
+                CTkMessagebox(title="Error", message=error_detail, icon="cancel")
         except requests.exceptions.RequestException as e:
-            messagebox.showerror("Error", f"Failed to connect to server: {e}")
+            CTkMessagebox(
+                title="Error",
+                message=f"Failed to connect to server: {e}",
+                icon="cancel",
+            )
+
+    # Helper function to fill form from selected category
+    def on_category_select(event):
+        selected_item = category_tree.selection()
+        if selected_item:
+            values = category_tree.item(selected_item[0])["values"]
+            entry_id.delete(0, "end")
+            entry_id.insert(0, values[0])
+
+            entry_name.delete(0, "end")
+            entry_name.insert(0, values[1])
+
+    # Bind the selection event
+    category_tree.bind("<<TreeviewSelect>>", on_category_select)
+
+    # Connect buttons to functions
+    create_button.configure(command=create_category)
+    list_button.configure(command=list_categories_dialog)
+    update_button.configure(command=update_category)
+    delete_button.configure(command=delete_category)
 
-    ctk.CTkButton(frame, text="Create Category", command=create_category).pack(pady=5)
-    ctk.CTkButton(frame, text="List Categories", command=list_categories).pack(pady=5)
-    ctk.CTkButton(frame, text="Update Category", command=update_category).pack(pady=5)
-    ctk.CTkButton(frame, text="Delete Category", command=delete_category).pack(pady=5)
-    ctk.CTkButton(frame, text="Back", command=lambda: switch_func("")).pack(pady=5)
+    # Initial fetch of categories
+    frame.after(100, fetch_categories)
 
     return frame
diff --git a/app/frontend/components/admin/category_management.py b/app/frontend/components/admin/category_management.py
new file mode 100644
index 0000000000000000000000000000000000000000..ac130e5027364e2fc6a36667cc5de065cd8d3d10
--- /dev/null
+++ b/app/frontend/components/admin/category_management.py
@@ -0,0 +1,561 @@
+import customtkinter as ctk
+from tkinter import ttk
+from CTkMessagebox import CTkMessagebox
+import requests
+from datetime import datetime
+
+
+def admin_category_management_frame(parent, switch_func, API_URL, access_token):
+    """
+    Admin dashboard component for managing product categories
+    """
+    frame = ctk.CTkFrame(parent)
+
+    # Store the token for later use
+    def update_token(new_token):
+        nonlocal access_token
+        access_token = new_token
+
+    frame.update_token = update_token
+
+    # Create main container with padding
+    main_container = ctk.CTkFrame(frame, fg_color="transparent")
+    main_container.pack(padx=40, pady=30, fill="both", expand=True)
+
+    # Header section
+    header_frame = ctk.CTkFrame(main_container, corner_radius=15, fg_color="#2e8b57")
+    header_frame.pack(fill="x", pady=(0, 20))
+
+    # Title and description
+    title_frame = ctk.CTkFrame(header_frame, fg_color="transparent")
+    title_frame.pack(padx=20, pady=15)
+
+    ctk.CTkLabel(
+        title_frame,
+        text="Category Management",
+        font=("Helvetica", 24, "bold"),
+        text_color="#ffffff",
+    ).pack(anchor="w")
+
+    ctk.CTkLabel(
+        title_frame,
+        text="Manage marketplace product categories",
+        font=("Helvetica", 14),
+        text_color="#e0e0e0",
+    ).pack(anchor="w")
+
+    # Control panel
+    control_panel = ctk.CTkFrame(main_container, corner_radius=10, height=80)
+    control_panel.pack(fill="x", pady=(0, 15))
+
+    # Left side - search
+    search_frame = ctk.CTkFrame(control_panel, fg_color="transparent")
+    search_frame.pack(side="left", padx=20, pady=15, fill="y")
+
+    ctk.CTkLabel(search_frame, text="Search:", font=("Helvetica", 12, "bold")).pack(
+        side="left", padx=(0, 10)
+    )
+
+    search_entry = ctk.CTkEntry(
+        search_frame, width=250, height=35, placeholder_text="Search categories..."
+    )
+    search_entry.pack(side="left", padx=(0, 10))
+
+    search_button = ctk.CTkButton(
+        search_frame,
+        text="Search",
+        font=("Helvetica", 12, "bold"),
+        height=35,
+        corner_radius=8,
+        fg_color="#2e8b57",
+        hover_color="#1f6e42",
+    )
+    search_button.pack(side="left")
+
+    # Right side - actions
+    actions_frame = ctk.CTkFrame(control_panel, fg_color="transparent")
+    actions_frame.pack(side="right", padx=20, pady=15, fill="y")
+
+    add_button = ctk.CTkButton(
+        actions_frame,
+        text="Add Category",
+        font=("Helvetica", 12, "bold"),
+        height=35,
+        width=120,
+        corner_radius=8,
+        fg_color="#4caf50",
+        hover_color="#388e3c",
+    )
+    add_button.pack(side="left", padx=(0, 10))
+
+    edit_button = ctk.CTkButton(
+        actions_frame,
+        text="Edit",
+        font=("Helvetica", 12, "bold"),
+        height=35,
+        width=80,
+        corner_radius=8,
+        fg_color="#3a7ebf",
+        hover_color="#2a6da9",
+    )
+    edit_button.pack(side="left", padx=(0, 10))
+
+    delete_button = ctk.CTkButton(
+        actions_frame,
+        text="Delete",
+        font=("Helvetica", 12, "bold"),
+        height=35,
+        width=80,
+        corner_radius=8,
+        fg_color="#f44336",
+        hover_color="#d32f2f",
+    )
+    delete_button.pack(side="left")
+
+    # Data table frame
+    table_frame = ctk.CTkFrame(main_container, corner_radius=10)
+    table_frame.pack(fill="both", expand=True)
+
+    # Configure Treeview style
+    style = ttk.Style()
+    style.theme_use("clam")  # Use clam theme as base
+
+    # Configure the Treeview colors to match app theme
+    style.configure(
+        "Treeview",
+        background="#2b2b2b",
+        foreground="#ffffff",
+        fieldbackground="#2b2b2b",
+        borderwidth=0,
+        rowheight=40,
+    )
+
+    # Configure the headings
+    style.configure(
+        "Treeview.Heading",
+        background="#2e8b57",
+        foreground="#ffffff",
+        borderwidth=0,
+        font=("Helvetica", 12, "bold"),
+    )
+
+    # Selection color
+    style.map("Treeview", background=[("selected", "#2e8b57")])
+
+    # Create scrollbar
+    scrollbar = ttk.Scrollbar(table_frame)
+    scrollbar.pack(side="right", fill="y")
+
+    # Create Treeview
+    columns = (
+        "id",
+        "name",
+        "description",
+        "product_count",
+        "created_at",
+        "parent_category",
+    )
+    category_tree = ttk.Treeview(
+        table_frame, columns=columns, show="headings", yscrollcommand=scrollbar.set
+    )
+
+    # Configure scrollbar
+    scrollbar.config(command=category_tree.yview)
+
+    # Define column headings
+    category_tree.heading("id", text="ID")
+    category_tree.heading("name", text="Category Name")
+    category_tree.heading("description", text="Description")
+    category_tree.heading("product_count", text="Products")
+    category_tree.heading("created_at", text="Created At")
+    category_tree.heading("parent_category", text="Parent Category")
+
+    # Define column widths and alignment
+    category_tree.column("id", width=60, anchor="center")
+    category_tree.column("name", width=150)
+    category_tree.column("description", width=200)
+    category_tree.column("product_count", width=80, anchor="center")
+    category_tree.column("created_at", width=150, anchor="center")
+    category_tree.column("parent_category", width=150)
+
+    category_tree.pack(fill="both", expand=True, padx=5, pady=5)
+
+    # Footer with back button
+    footer_frame = ctk.CTkFrame(main_container, fg_color="transparent", height=50)
+    footer_frame.pack(fill="x", pady=(15, 0))
+
+    back_button = ctk.CTkButton(
+        footer_frame,
+        text="Back to Admin Dashboard",
+        command=lambda: switch_func("admin_dashboard"),
+        font=("Helvetica", 12, "bold"),
+        height=40,
+        corner_radius=8,
+        fg_color="#555555",
+        hover_color="#444444",
+    )
+    back_button.pack(side="left")
+
+    # Function to fetch categories
+    def fetch_categories(search_term=None):
+        """Fetch categories from backend"""
+        headers = {"Authorization": f"Bearer {access_token}"}
+
+        params = {}
+        if search_term:
+            params["search"] = search_term
+
+        try:
+            response = requests.get(
+                f"{API_URL}/admin/categories", headers=headers, params=params
+            )
+
+            if response.status_code == 200:
+                # Clear current items
+                for item in category_tree.get_children():
+                    category_tree.delete(item)
+
+                categories = response.json()
+
+                for category in categories:
+                    # Format date
+                    created_at = "N/A"
+                    if "created_at" in category:
+                        try:
+                            dt = datetime.fromisoformat(
+                                category["created_at"].replace("Z", "+00:00")
+                            )
+                            created_at = dt.strftime("%Y-%m-%d %H:%M")
+                        except:
+                            pass
+
+                    # Handle parent category
+                    parent_category = category.get("parent_name", "None")
+
+                    # Insert into tree
+                    category_tree.insert(
+                        "",
+                        "end",
+                        values=(
+                            category["id"],
+                            category.get("name", "Unnamed Category"),
+                            category.get("description", ""),
+                            category.get("product_count", 0),
+                            created_at,
+                            parent_category,
+                        ),
+                    )
+            else:
+                CTkMessagebox(
+                    title="Error", message="Failed to fetch categories", icon="cancel"
+                )
+        except Exception as e:
+            CTkMessagebox(
+                title="Error", message=f"An error occurred: {str(e)}", icon="cancel"
+            )
+
+    # Function to handle search
+    def on_search():
+        search_term = search_entry.get() if search_entry.get() else None
+        fetch_categories(search_term)
+
+    # Function to delete a category
+    def delete_category():
+        selected_item = category_tree.selection()
+        if not selected_item:
+            CTkMessagebox(
+                title="Warning",
+                message="Please select a category to delete",
+                icon="warning",
+            )
+            return
+
+        # Get selected category details
+        category_id = category_tree.item(selected_item[0])["values"][0]
+        category_name = category_tree.item(selected_item[0])["values"][1]
+
+        # Confirm deletion
+        confirm = CTkMessagebox(
+            title="Confirm Deletion",
+            message=f"Are you sure you want to delete category '{category_name}'?\nThis action cannot be undone.",
+            icon="question",
+            option_1="Cancel",
+            option_2="Delete",
+        )
+
+        if confirm.get() != "Delete":
+            return
+
+        try:
+            response = requests.delete(
+                f"{API_URL}/category/delete/{category_id}",
+                headers={"Authorization": f"Bearer {access_token}"},
+            )
+
+            if response.status_code == 200:
+                CTkMessagebox(
+                    title="Success",
+                    message=f"Category '{category_name}' deleted successfully!",
+                    icon="check",
+                )
+                fetch_categories()
+            else:
+                try:
+                    error_data = response.json()
+                    error_message = error_data.get(
+                        "detail", "Failed to delete category. Please try again."
+                    )
+
+                    # Check if the error is about products using the category
+                    if "products are using this category" in error_message:
+                        CTkMessagebox(
+                            title="Cannot Delete Category",
+                            message=error_message,
+                            icon="warning",
+                        )
+                    else:
+                        CTkMessagebox(
+                            title="Error", message=error_message, icon="cancel"
+                        )
+                except:
+                    CTkMessagebox(
+                        title="Error",
+                        message="Failed to delete category. Please try again.",
+                        icon="cancel",
+                    )
+        except Exception as e:
+            CTkMessagebox(
+                title="Error", message=f"An error occurred: {str(e)}", icon="cancel"
+            )
+
+    # Function to add a new category
+    def add_category():
+        show_category_dialog("Add Category", None)
+
+    # Function to edit a category
+    def edit_category():
+        selected_items = category_tree.selection()
+        if not selected_items:
+            CTkMessagebox(
+                title="Warning",
+                message="Please select a category to edit",
+                icon="warning",
+            )
+            return
+
+        category_id = category_tree.item(selected_items[0])["values"][0]
+        headers = {"Authorization": f"Bearer {access_token}"}
+
+        try:
+            response = requests.get(
+                f"{API_URL}/admin/categories/{category_id}", headers=headers
+            )
+
+            if response.status_code == 200:
+                category = response.json()
+                show_category_dialog("Edit Category", category)
+            else:
+                CTkMessagebox(
+                    title="Error",
+                    message="Failed to fetch category details",
+                    icon="cancel",
+                )
+        except Exception as e:
+            CTkMessagebox(
+                title="Error", message=f"An error occurred: {str(e)}", icon="cancel"
+            )
+
+    def show_category_dialog(title, category=None):
+        """Show dialog for adding/editing a category"""
+        dialog = ctk.CTkToplevel(frame)
+        dialog.title(title)
+        dialog.geometry("500x400")
+        dialog.resizable(False, False)
+        dialog.transient(frame)
+        dialog.grab_set()
+
+        # Form container
+        form_frame = ctk.CTkFrame(dialog, fg_color="transparent")
+        form_frame.pack(padx=20, pady=20, fill="both", expand=True)
+
+        # Category name
+        name_label = ctk.CTkLabel(
+            form_frame, text="Category Name:", font=("Helvetica", 12, "bold")
+        )
+        name_label.pack(anchor="w", pady=(0, 5))
+
+        name_entry = ctk.CTkEntry(form_frame, width=460, height=35)
+        name_entry.pack(fill="x", pady=(0, 15))
+
+        # Description
+        desc_label = ctk.CTkLabel(
+            form_frame, text="Description:", font=("Helvetica", 12, "bold")
+        )
+        desc_label.pack(anchor="w", pady=(0, 5))
+
+        desc_entry = ctk.CTkTextbox(form_frame, width=460, height=100)
+        desc_entry.pack(fill="x", pady=(0, 15))
+
+        # Parent category
+        parent_label = ctk.CTkLabel(
+            form_frame,
+            text="Parent Category (optional):",
+            font=("Helvetica", 12, "bold"),
+        )
+        parent_label.pack(anchor="w", pady=(0, 5))
+
+        # Get all categories for parent dropdown
+        def get_all_categories():
+            try:
+                headers = {"Authorization": f"Bearer {access_token}"}
+                response = requests.get(f"{API_URL}/admin/categories", headers=headers)
+
+                if response.status_code == 200:
+                    categories = response.json()
+                    parent_options = ["None"]
+
+                    for cat in categories:
+                        # Don't include itself as a parent option when editing
+                        if category and cat["id"] == category["id"]:
+                            continue
+                        parent_options.append(f"{cat['name']} (ID: {cat['id']})")
+
+                    return parent_options
+                else:
+                    return ["None"]
+            except:
+                return ["None"]
+
+        parent_options = get_all_categories()
+        parent_var = ctk.StringVar(value="None")
+
+        parent_menu = ctk.CTkOptionMenu(
+            form_frame,
+            values=parent_options,
+            variable=parent_var,
+            width=460,
+            height=35,
+            dropdown_font=("Helvetica", 12),
+        )
+        parent_menu.pack(fill="x", pady=(0, 20))
+
+        # Fill fields if editing
+        if category:
+            name_entry.insert(0, category.get("name", ""))
+            desc_entry.insert("1.0", category.get("description", ""))
+
+            # Set parent category if it exists
+            if "parent_id" in category and category["parent_id"]:
+                for option in parent_options:
+                    if f"(ID: {category['parent_id']})" in option:
+                        parent_var.set(option)
+                        break
+
+        # Buttons
+        button_frame = ctk.CTkFrame(form_frame, fg_color="transparent")
+        button_frame.pack(fill="x", pady=(10, 0))
+
+        cancel_button = ctk.CTkButton(
+            button_frame,
+            text="Cancel",
+            font=("Helvetica", 12, "bold"),
+            width=100,
+            fg_color="#9e9e9e",
+            hover_color="#757575",
+            command=dialog.destroy,
+        )
+        cancel_button.pack(side="left", padx=(0, 10))
+
+        # Save function
+        def save_category():
+            name = name_entry.get().strip()
+            description = desc_entry.get("1.0", "end-1c").strip()
+            parent = parent_var.get()
+
+            if not name:
+                CTkMessagebox(
+                    title="Warning", message="Category name is required", icon="warning"
+                )
+                return
+
+            # Extract parent ID if selected
+            parent_id = None
+            if parent != "None":
+                try:
+                    parent_id = int(parent.split("ID: ")[1].split(")")[0])
+                except:
+                    pass
+
+            # Prepare data
+            data = {"name": name, "description": description, "parent_id": parent_id}
+
+            headers = {"Authorization": f"Bearer {access_token}"}
+
+            try:
+                if category:  # Editing existing category
+                    response = requests.put(
+                        f"{API_URL}/category/put/{category['id']}",
+                        headers=headers,
+                        data={"name": name},  # Use data format for form data
+                    )
+                else:  # Adding new category
+                    response = requests.post(
+                        f"{API_URL}/category/create",
+                        headers=headers,
+                        data={"name": name},  # Use data format for form data
+                    )
+
+                if response.status_code in [200, 201]:
+                    dialog.destroy()
+                    CTkMessagebox(
+                        title="Success",
+                        message="Category updated successfully"
+                        if category
+                        else "Category added successfully",
+                    )
+                    fetch_categories()  # Refresh the list
+                else:
+                    error_detail = "Failed to save category"
+                    try:
+                        error_data = response.json()
+                        if "detail" in error_data:
+                            error_detail = error_data["detail"]
+                    except:
+                        pass
+                    CTkMessagebox(title="Error", message=error_detail, icon="cancel")
+            except Exception as e:
+                CTkMessagebox(
+                    title="Error", message=f"An error occurred: {str(e)}", icon="cancel"
+                )
+
+        save_button = ctk.CTkButton(
+            button_frame,
+            text="Save",
+            font=("Helvetica", 12, "bold"),
+            width=100,
+            fg_color="#2e8b57",
+            hover_color="#1f6e42",
+            command=save_category,
+        )
+        save_button.pack(side="right")
+
+    # Connect UI elements to functions
+    search_button.configure(command=on_search)
+    add_button.configure(command=add_category)
+    edit_button.configure(command=edit_category)
+    delete_button.configure(command=delete_category)
+
+    # Initial data fetch
+    def on_frame_shown():
+        fetch_categories()
+
+    frame.after(100, on_frame_shown)
+
+    # Add refresh method to frame for external calls
+    def refresh_data(*args):
+        """Public method to refresh category data"""
+        fetch_categories()
+
+    frame.refresh_data = refresh_data
+
+    return frame
diff --git a/app/frontend/components/admin/dashboard.py b/app/frontend/components/admin/dashboard.py
new file mode 100644
index 0000000000000000000000000000000000000000..3a25bcfacc3de04fd8a5abf3e801ee23e5ff22d6
--- /dev/null
+++ b/app/frontend/components/admin/dashboard.py
@@ -0,0 +1,245 @@
+import customtkinter as ctk
+from CTkMessagebox import CTkMessagebox
+import requests
+from PIL import Image, ImageTk
+import os
+
+
+def admin_dashboard_frame(parent, switch_func, API_URL, access_token):
+    """
+    Main admin dashboard with buttons to access different admin functions
+    """
+    frame = ctk.CTkFrame(parent)
+
+    # Store the token for later use
+    def update_token(new_token):
+        nonlocal access_token
+        access_token = new_token
+
+    frame.update_token = update_token
+
+    # Create main container with padding
+    main_container = ctk.CTkFrame(frame, fg_color="transparent")
+    main_container.pack(padx=40, pady=30, fill="both", expand=True)
+
+    # Header section with gradient effect
+    header_frame = ctk.CTkFrame(main_container, corner_radius=15, fg_color="#1f538d")
+    header_frame.pack(pady=(0, 20), fill="x")
+
+    # Header content
+    header_content = ctk.CTkFrame(header_frame, fg_color="transparent")
+    header_content.pack(padx=20, pady=20)
+
+    # Try to load an admin icon if available
+    icon_path = os.path.join(
+        os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__)))),
+        "static",
+        "icons",
+        "admin.png",
+    )
+
+    try:
+        if os.path.exists(icon_path):
+            admin_icon = ctk.CTkImage(Image.open(icon_path), size=(64, 64))
+            icon_label = ctk.CTkLabel(header_content, image=admin_icon, text="")
+            icon_label.pack(pady=(0, 10))
+    except Exception as e:
+        print(f"Could not load admin icon: {e}")
+
+    # Header text
+    ctk.CTkLabel(
+        header_content,
+        text="Admin Dashboard",
+        font=("Helvetica", 28, "bold"),
+        text_color="#ffffff",
+    ).pack(pady=(0, 5))
+
+    ctk.CTkLabel(
+        header_content,
+        text="Manage your application from this control panel",
+        font=("Helvetica", 14),
+        text_color="#e0e0e0",
+    ).pack()
+
+    # Welcome message with admin name
+    def get_admin_name():
+        headers = {"Authorization": f"Bearer {access_token}"}
+        try:
+            resp = requests.get(f"{API_URL}/auth/profile", headers=headers)
+            if resp.status_code == 200:
+                profile = resp.json()
+                return profile.get("username", "Admin")
+        except Exception:
+            pass
+        return "Admin"
+
+    welcome_frame = ctk.CTkFrame(
+        main_container, corner_radius=10, fg_color="#f0f9ff", height=60
+    )
+    welcome_frame.pack(fill="x", pady=(0, 20))
+
+    ctk.CTkLabel(
+        welcome_frame,
+        text=f"Welcome, {get_admin_name()}!",
+        font=("Helvetica", 16),
+        text_color="#1a1a1a",
+    ).pack(padx=20, pady=15)
+
+    # Dashboard cards section
+    cards_frame = ctk.CTkFrame(main_container, fg_color="transparent")
+    cards_frame.pack(fill="both", expand=True)
+
+    # Configure grid for cards
+    cards_frame.grid_columnconfigure(0, weight=1)
+    cards_frame.grid_columnconfigure(1, weight=1)
+    cards_frame.grid_rowconfigure(0, weight=1)
+    cards_frame.grid_rowconfigure(1, weight=1)
+
+    # Check admin access
+    def check_admin():
+        headers = {"Authorization": f"Bearer {access_token}"}
+        try:
+            resp = requests.get(f"{API_URL}/auth/role", headers=headers)
+            if resp.status_code == 200:
+                role_data = resp.json()
+                if role_data.get("role") != "admin":
+                    CTkMessagebox(
+                        title="Access Denied",
+                        message="You need admin privileges to access this dashboard",
+                        icon="cancel",
+                    )
+                    switch_func("dashboard")
+                    return False
+            else:
+                CTkMessagebox(
+                    title="Error",
+                    message="Failed to verify admin privileges",
+                    icon="cancel",
+                )
+                switch_func("login")
+                return False
+        except Exception as e:
+            CTkMessagebox(
+                title="Error",
+                message=f"Failed to connect to server: {e}",
+                icon="cancel",
+            )
+            return False
+        return True
+
+    # Create dashboard cards
+    def create_card(row, col, title, description, icon_text, command, color="#3a7ebf"):
+        card = ctk.CTkFrame(
+            cards_frame,
+            corner_radius=12,
+            fg_color=color,
+            border_width=1,
+            border_color="#2a5a8f",
+        )
+        card.grid(row=row, column=col, padx=10, pady=10, sticky="nsew")
+
+        # Create icon circle
+        icon_frame = ctk.CTkFrame(
+            card, width=50, height=50, corner_radius=25, fg_color="#ffffff"
+        )
+        icon_frame.place(relx=0.1, rely=0.5, anchor="w")
+
+        # Icon text (could be replaced with an actual icon)
+        ctk.CTkLabel(
+            icon_frame, text=icon_text, font=("Helvetica", 18, "bold"), text_color=color
+        ).place(relx=0.5, rely=0.5, anchor="center")
+
+        # Card content
+        content_frame = ctk.CTkFrame(card, fg_color="transparent")
+        content_frame.place(relx=0.6, rely=0.5, anchor="center")
+
+        ctk.CTkLabel(
+            content_frame,
+            text=title,
+            font=("Helvetica", 18, "bold"),
+            text_color="#ffffff",
+        ).pack(pady=(0, 5))
+
+        ctk.CTkLabel(
+            content_frame,
+            text=description,
+            font=("Helvetica", 12),
+            text_color="#e6e6e6",
+        ).pack()
+
+        # Make entire card clickable
+        card.bind("<Button-1>", lambda e: command() if check_admin() else None)
+        for widget in card.winfo_children():
+            widget.bind("<Button-1>", lambda e: command() if check_admin() else None)
+            for subwidget in widget.winfo_children():
+                subwidget.bind(
+                    "<Button-1>", lambda e: command() if check_admin() else None
+                )
+
+    # Create the cards
+    create_card(
+        0,
+        0,
+        "User Management",
+        "View and manage user accounts",
+        "👤",
+        lambda: switch_func("admin_user_management"),
+        "#3a7ebf",
+    )
+
+    create_card(
+        0,
+        1,
+        "Shop Owner Management",
+        "Manage shop owner accounts",
+        "🏪",
+        lambda: switch_func("admin_shop_owner_management"),
+        "#2e8b57",
+    )
+
+    create_card(
+        1,
+        0,
+        "Category Management",
+        "Manage product categories",
+        "🏷️",
+        lambda: switch_func("category"),
+        "#9c27b0",
+    )
+
+    create_card(
+        1,
+        1,
+        "System Statistics",
+        "View system analytics and data",
+        "��",
+        lambda: CTkMessagebox(
+            title="Coming Soon",
+            message="System statistics will be available in a future update.",
+            icon="info",
+        ),
+        "#e91e63",
+    )
+
+    # Footer with logout button
+    footer_frame = ctk.CTkFrame(main_container, fg_color="transparent", height=50)
+    footer_frame.pack(fill="x", pady=(20, 0))
+
+    # Logout button
+    logout_btn = ctk.CTkButton(
+        footer_frame,
+        text="Logout",
+        command=lambda: switch_func("login"),
+        fg_color="#f44336",
+        hover_color="#d32f2f",
+        font=("Helvetica", 14, "bold"),
+        corner_radius=8,
+        border_width=0,
+        height=40,
+    )
+    logout_btn.pack(side="right")
+
+    # Check admin access on load
+    frame.after(100, check_admin)
+
+    return frame
diff --git a/app/frontend/components/admin/product_management.py b/app/frontend/components/admin/product_management.py
new file mode 100644
index 0000000000000000000000000000000000000000..cc9ba172dbd84487ed7a0d8f5863baaaa29fd717
--- /dev/null
+++ b/app/frontend/components/admin/product_management.py
@@ -0,0 +1,744 @@
+import customtkinter as ctk
+from tkinter import ttk, messagebox
+import requests
+from datetime import datetime
+import os
+import base64
+from PIL import Image, ImageTk
+from io import BytesIO
+from CTkMessagebox import CTkMessagebox
+
+
+def admin_product_management_frame(parent, switch_func, API_URL, access_token):
+    """
+    Admin dashboard component for managing products in the marketplace
+    """
+    frame = ctk.CTkFrame(parent)
+
+    # Store the token for later use
+    def update_token(new_token):
+        nonlocal access_token
+        access_token = new_token
+
+    frame.update_token = update_token
+
+    # Create main container with padding
+    main_container = ctk.CTkFrame(frame, fg_color="transparent")
+    main_container.pack(padx=40, pady=30, fill="both", expand=True)
+
+    # Header section
+    header_frame = ctk.CTkFrame(main_container, corner_radius=15, fg_color="#2e8b57")
+    header_frame.pack(fill="x", pady=(0, 20))
+
+    # Title and description
+    title_frame = ctk.CTkFrame(header_frame, fg_color="transparent")
+    title_frame.pack(padx=20, pady=15)
+
+    ctk.CTkLabel(
+        title_frame,
+        text="Product Management",
+        font=("Helvetica", 24, "bold"),
+        text_color="#ffffff",
+    ).pack(anchor="w")
+
+    ctk.CTkLabel(
+        title_frame,
+        text="Manage marketplace products",
+        font=("Helvetica", 14),
+        text_color="#e0e0e0",
+    ).pack(anchor="w")
+
+    # Search and filter panel
+    filter_panel = ctk.CTkFrame(main_container, corner_radius=10, height=80)
+    filter_panel.pack(fill="x", pady=(0, 15))
+
+    # Left side - search
+    search_frame = ctk.CTkFrame(filter_panel, fg_color="transparent")
+    search_frame.pack(side="left", padx=20, pady=15, fill="y")
+
+    ctk.CTkLabel(search_frame, text="Search:", font=("Helvetica", 12, "bold")).pack(
+        side="left", padx=(0, 10)
+    )
+
+    search_entry = ctk.CTkEntry(
+        search_frame, width=250, height=35, placeholder_text="Search products..."
+    )
+    search_entry.pack(side="left", padx=(0, 10))
+
+    search_button = ctk.CTkButton(
+        search_frame,
+        text="Search",
+        font=("Helvetica", 12, "bold"),
+        height=35,
+        corner_radius=8,
+        fg_color="#2e8b57",
+        hover_color="#1f6e42",
+    )
+    search_button.pack(side="left")
+
+    # Right side - actions
+    actions_frame = ctk.CTkFrame(filter_panel, fg_color="transparent")
+    actions_frame.pack(side="right", padx=20, pady=15, fill="y")
+
+    filter_menu = ctk.CTkOptionMenu(
+        actions_frame,
+        values=["All Products", "Approved", "Pending", "Rejected"],
+        font=("Helvetica", 12),
+        width=150,
+        height=35,
+        dropdown_font=("Helvetica", 12),
+    )
+    filter_menu.pack(side="left", padx=(0, 10))
+    filter_menu.set("All Products")
+
+    sort_menu = ctk.CTkOptionMenu(
+        actions_frame,
+        values=[
+            "Newest First",
+            "Oldest First",
+            "Price: High to Low",
+            "Price: Low to High",
+        ],
+        font=("Helvetica", 12),
+        width=150,
+        height=35,
+        dropdown_font=("Helvetica", 12),
+    )
+    sort_menu.pack(side="left")
+    sort_menu.set("Newest First")
+
+    # Action buttons panel
+    action_buttons = ctk.CTkFrame(main_container, fg_color="transparent")
+    action_buttons.pack(fill="x", pady=(0, 15))
+
+    approve_button = ctk.CTkButton(
+        action_buttons,
+        text="Approve",
+        font=("Helvetica", 12, "bold"),
+        height=35,
+        width=100,
+        corner_radius=8,
+        fg_color="#4caf50",
+        hover_color="#388e3c",
+    )
+    approve_button.pack(side="left", padx=(0, 10))
+
+    reject_button = ctk.CTkButton(
+        action_buttons,
+        text="Reject",
+        font=("Helvetica", 12, "bold"),
+        height=35,
+        width=100,
+        corner_radius=8,
+        fg_color="#f44336",
+        hover_color="#d32f2f",
+    )
+    reject_button.pack(side="left", padx=(0, 10))
+
+    view_button = ctk.CTkButton(
+        action_buttons,
+        text="View Details",
+        font=("Helvetica", 12, "bold"),
+        height=35,
+        width=120,
+        corner_radius=8,
+        fg_color="#3a7ebf",
+        hover_color="#2a6da9",
+    )
+    view_button.pack(side="left")
+
+    # Data table frame
+    table_frame = ctk.CTkFrame(main_container, corner_radius=10)
+    table_frame.pack(fill="both", expand=True)
+
+    # Configure Treeview style
+    style = ttk.Style()
+    style.theme_use("clam")  # Use clam theme as base
+
+    # Configure the Treeview colors to match app theme
+    style.configure(
+        "Treeview",
+        background="#2b2b2b",
+        foreground="#ffffff",
+        fieldbackground="#2b2b2b",
+        borderwidth=0,
+        rowheight=40,
+    )
+
+    # Configure the headings
+    style.configure(
+        "Treeview.Heading",
+        background="#2e8b57",
+        foreground="#ffffff",
+        borderwidth=0,
+        font=("Helvetica", 12, "bold"),
+    )
+
+    # Selection color
+    style.map("Treeview", background=[("selected", "#2e8b57")])
+
+    # Create scrollbar
+    scrollbar = ttk.Scrollbar(table_frame)
+    scrollbar.pack(side="right", fill="y")
+
+    # Create Treeview - Reordered columns
+    columns = (
+        "id",
+        "name",
+        "category",
+        "price",
+        "owner",
+        "status",
+        "created_at",
+        "image",
+    )
+    product_tree = ttk.Treeview(
+        table_frame, columns=columns, show="headings", yscrollcommand=scrollbar.set
+    )
+
+    # Configure scrollbar
+    scrollbar.config(command=product_tree.yview)
+
+    # Define column headings - Reordered
+    product_tree.heading("id", text="ID")
+    product_tree.heading("name", text="Product Name")
+    product_tree.heading("category", text="Category")
+    product_tree.heading("price", text="Price")
+    product_tree.heading("owner", text="Shop Owner")
+    product_tree.heading("status", text="Status")
+    product_tree.heading("created_at", text="Created At")
+    product_tree.heading("image", text="Image")
+
+    # Define column widths and alignment - Reordered
+    product_tree.column("id", width=60, anchor="center")
+    product_tree.column("name", width=200)
+    product_tree.column("category", width=150)
+    product_tree.column("price", width=80, anchor="center")
+    product_tree.column("owner", width=150)
+    product_tree.column("status", width=100, anchor="center")
+    product_tree.column("created_at", width=150, anchor="center")
+    product_tree.column("image", width=80, anchor="center")
+
+    # Add tag configurations for different status types
+    product_tree.tag_configure("approved", background="#1a472a")  # Dark green
+    product_tree.tag_configure("pending", background="#5d4037")  # Brown
+    product_tree.tag_configure("rejected", background="#b71c1c")  # Dark red
+
+    product_tree.pack(fill="both", expand=True, padx=5, pady=5)
+
+    # Store images to prevent garbage collection
+    image_refs = []
+
+    # Footer with back button
+    footer_frame = ctk.CTkFrame(main_container, fg_color="transparent", height=50)
+    footer_frame.pack(fill="x", pady=(15, 0))
+
+    back_button = ctk.CTkButton(
+        footer_frame,
+        text="Back to Admin Dashboard",
+        command=lambda: switch_func("admin_dashboard"),
+        font=("Helvetica", 12, "bold"),
+        height=40,
+        corner_radius=8,
+        fg_color="#555555",
+        hover_color="#444444",
+    )
+    back_button.pack(side="left")
+
+    # Function to fetch products
+    def fetch_products(status_filter=None, sort_option=None, search_term=None):
+        """
+        Fetch products from backend with filters
+        """
+        headers = {"Authorization": f"Bearer {access_token}"}
+
+        # Build query params
+        params = {}
+        if status_filter and status_filter != "All Products":
+            params["status"] = status_filter.lower()
+        if sort_option:
+            if sort_option == "Newest First":
+                params["sort"] = "created_at_desc"
+            elif sort_option == "Oldest First":
+                params["sort"] = "created_at_asc"
+            elif sort_option == "Price: High to Low":
+                params["sort"] = "price_desc"
+            elif sort_option == "Price: Low to High":
+                params["sort"] = "price_asc"
+        if search_term:
+            params["search"] = search_term
+
+        try:
+            response = requests.get(
+                f"{API_URL}/admin/products", headers=headers, params=params
+            )
+
+            if response.status_code == 200:
+                # Clear current items
+                for item in product_tree.get_children():
+                    product_tree.delete(item)
+
+                # Clear image references
+                image_refs.clear()
+
+                products = response.json()
+
+                for product in products:
+                    # Format price
+                    price = f"${product.get('price', 0):.2f}"
+
+                    # Format date
+                    created_at = "N/A"
+                    if "created_at" in product:
+                        try:
+                            dt = datetime.fromisoformat(
+                                product["created_at"].replace("Z", "+00:00")
+                            )
+                            created_at = dt.strftime("%Y-%m-%d %H:%M")
+                        except:
+                            pass
+
+                    # Status for styling
+                    status = product.get("status", "pending").lower()
+
+                    # Get image if available
+                    img_text = "No Image"
+                    if product.get("images") and len(product["images"]) > 0:
+                        img_text = "Has Image"
+
+                    # Get category
+                    category = product.get("category", {}).get("name", "Uncategorized")
+
+                    # Get owner name
+                    owner = product.get("shop", {}).get("name", "Unknown")
+
+                    # Insert into tree - Reordered values to match new column order
+                    item_id = product_tree.insert(
+                        "",
+                        "end",
+                        values=(
+                            product["id"],
+                            product.get("name", "Unnamed Product"),
+                            category,
+                            price,
+                            owner,
+                            status.capitalize(),
+                            created_at,
+                            img_text,
+                        ),
+                        tags=(status,),
+                    )
+
+                    # Try to load the image
+                    if product.get("images") and len(product["images"]) > 0:
+                        try:
+                            image_url = product["images"][0].get("image_url")
+                            if image_url:
+                                response = requests.get(image_url)
+                                if response.status_code == 200:
+                                    img_data = response.content
+                                    img = Image.open(BytesIO(img_data))
+                                    img = img.resize((30, 30))
+                                    photo_img = ImageTk.PhotoImage(img)
+
+                                    # Store reference to prevent garbage collection
+                                    image_refs.append(photo_img)
+
+                                    # Use item id to identify which item to update
+                                    product_tree.item(
+                                        item_id,
+                                        values=(
+                                            product["id"],
+                                            product.get("name", "Unnamed Product"),
+                                            category,
+                                            price,
+                                            owner,
+                                            status.capitalize(),
+                                            created_at,
+                                            "",  # Will be replaced by image
+                                        ),
+                                    )
+
+                                    # Create image for the item
+                                    product_tree.item(item_id, image=photo_img)
+                        except Exception as e:
+                            print(f"[DEBUG] Error loading product image: {e}")
+            else:
+                CTkMessagebox(
+                    title="Error", message="Failed to fetch products", icon="cancel"
+                )
+        except Exception as e:
+            CTkMessagebox(
+                title="Error", message=f"An error occurred: {str(e)}", icon="cancel"
+            )
+
+    # Function to handle filter changes
+    def on_filter_change(*args):
+        status_filter = filter_menu.get()
+        sort_option = sort_menu.get()
+        search_term = search_entry.get() if search_entry.get() else None
+        fetch_products(status_filter, sort_option, search_term)
+
+    # Function to handle search
+    def on_search():
+        status_filter = filter_menu.get()
+        sort_option = sort_menu.get()
+        search_term = search_entry.get() if search_entry.get() else None
+        fetch_products(status_filter, sort_option, search_term)
+
+    # Function to approve a product
+    def approve_product():
+        selected_items = product_tree.selection()
+        if not selected_items:
+            CTkMessagebox(
+                title="Warning",
+                message="Please select a product to approve",
+                icon="warning",
+            )
+            return
+
+        product_id = product_tree.item(selected_items[0])["values"][0]
+        headers = {"Authorization": f"Bearer {access_token}"}
+
+        try:
+            response = requests.put(
+                f"{API_URL}/admin/products/{product_id}/approve", headers=headers
+            )
+
+            if response.status_code == 200:
+                CTkMessagebox(
+                    title="Success",
+                    message="Product approved successfully",
+                    icon="check",
+                )
+                on_filter_change()  # Refresh the list
+            else:
+                CTkMessagebox(
+                    title="Error", message="Failed to approve product", icon="cancel"
+                )
+        except Exception as e:
+            CTkMessagebox(
+                title="Error", message=f"An error occurred: {str(e)}", icon="cancel"
+            )
+
+    # Function to reject a product
+    def reject_product():
+        selected_items = product_tree.selection()
+        if not selected_items:
+            CTkMessagebox(
+                title="Warning",
+                message="Please select a product to reject",
+                icon="warning",
+            )
+            return
+
+        product_id = product_tree.item(selected_items[0])["values"][0]
+        product_name = product_tree.item(selected_items[0])["values"][1]
+
+        # Create rejection dialog
+        reject_dialog = ctk.CTkToplevel(frame)
+        reject_dialog.title("Reject Product")
+        reject_dialog.geometry("500x300")
+        reject_dialog.resizable(False, False)
+        reject_dialog.transient(frame)
+        reject_dialog.grab_set()
+
+        # Dialog content
+        ctk.CTkLabel(
+            reject_dialog,
+            text=f"Reject Product: {product_name}",
+            font=("Helvetica", 18, "bold"),
+        ).pack(pady=(20, 10))
+
+        ctk.CTkLabel(
+            reject_dialog,
+            text="Please provide a reason for rejection:",
+            font=("Helvetica", 14),
+        ).pack(pady=(0, 10))
+
+        reason_textbox = ctk.CTkTextbox(reject_dialog, width=400, height=100)
+        reason_textbox.pack(padx=20, pady=10)
+
+        # Button frame
+        button_frame = ctk.CTkFrame(reject_dialog, fg_color="transparent")
+        button_frame.pack(pady=20)
+
+        def on_cancel():
+            reject_dialog.destroy()
+
+        def on_submit():
+            rejection_reason = reason_textbox.get("1.0", "end-1c").strip()
+            if not rejection_reason:
+                CTkMessagebox(
+                    title="Warning",
+                    message="Please provide a reason for rejection",
+                    icon="warning",
+                    parent=reject_dialog,
+                )
+                return
+
+            headers = {"Authorization": f"Bearer {access_token}"}
+            data = {"reason": rejection_reason}
+
+            try:
+                response = requests.put(
+                    f"{API_URL}/admin/products/{product_id}/reject",
+                    headers=headers,
+                    json=data,
+                )
+
+                if response.status_code == 200:
+                    reject_dialog.destroy()
+                    CTkMessagebox(
+                        title="Success",
+                        message="Product rejected successfully",
+                        icon="check",
+                    )
+                    on_filter_change()  # Refresh the list
+                else:
+                    CTkMessagebox(
+                        title="Error",
+                        message="Failed to reject product",
+                        icon="cancel",
+                        parent=reject_dialog,
+                    )
+            except Exception as e:
+                CTkMessagebox(
+                    title="Error",
+                    message=f"An error occurred: {str(e)}",
+                    icon="cancel",
+                    parent=reject_dialog,
+                )
+
+        ctk.CTkButton(
+            button_frame,
+            text="Cancel",
+            command=on_cancel,
+            font=("Helvetica", 12, "bold"),
+            fg_color="#9e9e9e",
+            hover_color="#757575",
+            width=120,
+            height=35,
+        ).pack(side="left", padx=10)
+
+        ctk.CTkButton(
+            button_frame,
+            text="Reject Product",
+            command=on_submit,
+            font=("Helvetica", 12, "bold"),
+            fg_color="#f44336",
+            hover_color="#d32f2f",
+            width=150,
+            height=35,
+        ).pack(side="left", padx=10)
+
+    # Function to view product details
+    def view_product_details():
+        selected_items = product_tree.selection()
+        if not selected_items:
+            CTkMessagebox(
+                title="Warning",
+                message="Please select a product to view",
+                icon="warning",
+            )
+            return
+
+        product_id = product_tree.item(selected_items[0])["values"][0]
+        headers = {"Authorization": f"Bearer {access_token}"}
+
+        try:
+            response = requests.get(
+                f"{API_URL}/admin/products/{product_id}", headers=headers
+            )
+
+            if response.status_code == 200:
+                product = response.json()
+                show_product_details(product)
+            else:
+                CTkMessagebox(
+                    title="Error",
+                    message="Failed to fetch product details",
+                    icon="cancel",
+                )
+        except Exception as e:
+            CTkMessagebox(
+                title="Error", message=f"An error occurred: {str(e)}", icon="cancel"
+            )
+
+    # Function to show product details dialog
+    def show_product_details(product):
+        detail_dialog = ctk.CTkToplevel(frame)
+        detail_dialog.title("Product Details")
+        detail_dialog.geometry("800x600")
+        detail_dialog.resizable(True, True)
+        detail_dialog.transient(frame)
+        detail_dialog.grab_set()
+
+        # Create scrollable frame to handle large content
+        main_scroll = ctk.CTkScrollableFrame(detail_dialog)
+        main_scroll.pack(fill="both", expand=True, padx=20, pady=20)
+
+        # Title
+        ctk.CTkLabel(
+            main_scroll,
+            text=product.get("name", "Unnamed Product"),
+            font=("Helvetica", 24, "bold"),
+        ).pack(anchor="w", pady=(0, 20))
+
+        # Top section: Images and Basic Info
+        top_frame = ctk.CTkFrame(main_scroll, fg_color="transparent")
+        top_frame.pack(fill="x", pady=(0, 20))
+
+        # Left side - Images
+        image_frame = ctk.CTkFrame(top_frame, width=300, height=300, fg_color="#333")
+        image_frame.pack(side="left", padx=(0, 20))
+        image_frame.pack_propagate(False)  # Force dimensions
+
+        # If has images, display the first one
+        if product.get("images") and len(product["images"]) > 0:
+            try:
+                image_url = product["images"][0].get("image_url")
+                if image_url:
+                    response = requests.get(image_url)
+                    if response.status_code == 200:
+                        img_data = response.content
+                        img = Image.open(BytesIO(img_data))
+
+                        # Maintain aspect ratio
+                        img.thumbnail((280, 280))
+
+                        photo_img = ImageTk.PhotoImage(img)
+
+                        img_label = ctk.CTkLabel(image_frame, text="", image=photo_img)
+                        img_label.image = photo_img  # Keep reference
+                        img_label.place(relx=0.5, rely=0.5, anchor="center")
+                    else:
+                        ctk.CTkLabel(image_frame, text="Image not available").place(
+                            relx=0.5, rely=0.5, anchor="center"
+                        )
+            except:
+                ctk.CTkLabel(image_frame, text="Error loading image").place(
+                    relx=0.5, rely=0.5, anchor="center"
+                )
+        else:
+            ctk.CTkLabel(image_frame, text="No Image Available").place(
+                relx=0.5, rely=0.5, anchor="center"
+            )
+
+        # Right side - Basic info in a structured form
+        info_frame = ctk.CTkFrame(top_frame, fg_color="transparent")
+        info_frame.pack(side="left", fill="both", expand=True)
+
+        # Fields grid
+        info_grid = ctk.CTkFrame(info_frame, fg_color="transparent")
+        info_grid.pack(fill="both", expand=True)
+
+        def add_field(label, value, row):
+            label_widget = ctk.CTkLabel(
+                info_grid,
+                text=f"{label}:",
+                font=("Helvetica", 14, "bold"),
+                width=150,
+                anchor="e",
+            )
+            label_widget.grid(row=row, column=0, sticky="e", padx=(0, 20), pady=8)
+
+            value_widget = ctk.CTkLabel(
+                info_grid, text=str(value), font=("Helvetica", 14), anchor="w"
+            )
+            value_widget.grid(row=row, column=1, sticky="w", pady=8)
+
+        # Basic details
+        add_field("Product ID", product["id"], 0)
+        add_field("Product Name", product.get("name", "Unnamed Product"), 1)
+        add_field("Price", f"${product.get('price', 0):.2f}", 2)
+        add_field("Status", product.get("status", "Pending").capitalize(), 3)
+
+        # Shop information
+        shop = product.get("shop", {})
+        add_field("Shop", shop.get("name", "Unknown"), 4)
+        add_field("Shop Owner", shop.get("owner_name", "Unknown"), 5)
+
+        # Category
+        category = product.get("category", {})
+        add_field("Category", category.get("name", "Uncategorized"), 6)
+
+        # Created date
+        created_at = "N/A"
+        if "created_at" in product:
+            try:
+                dt = datetime.fromisoformat(
+                    product["created_at"].replace("Z", "+00:00")
+                )
+                created_at = dt.strftime("%Y-%m-%d %H:%M")
+            except:
+                pass
+        add_field("Created At", created_at, 7)
+
+        # Description section
+        desc_frame = ctk.CTkFrame(main_scroll, fg_color="transparent")
+        desc_frame.pack(fill="x", pady=(0, 20))
+
+        ctk.CTkLabel(
+            desc_frame, text="Description", font=("Helvetica", 18, "bold")
+        ).pack(anchor="w", pady=(0, 10))
+
+        desc_box = ctk.CTkTextbox(desc_frame, height=100)
+        desc_box.pack(fill="x")
+        desc_box.insert("1.0", product.get("description", "No description provided"))
+        desc_box.configure(state="disabled")  # Make it read-only
+
+        # Action buttons
+        buttons_frame = ctk.CTkFrame(main_scroll, fg_color="transparent")
+        buttons_frame.pack(fill="x", pady=(20, 0))
+
+        close_button = ctk.CTkButton(
+            buttons_frame,
+            text="Close",
+            command=detail_dialog.destroy,
+            height=35,
+            width=100,
+        )
+        close_button.pack(side="right", padx=(10, 0))
+
+        # Add Approve/Reject buttons if product is pending
+        if product.get("status", "").lower() == "pending":
+            reject_button = ctk.CTkButton(
+                buttons_frame,
+                text="Reject",
+                command=lambda: detail_dialog.destroy() or reject_product(),
+                fg_color="#f44336",
+                hover_color="#d32f2f",
+                height=35,
+                width=100,
+            )
+            reject_button.pack(side="right", padx=(10, 0))
+
+            approve_button = ctk.CTkButton(
+                buttons_frame,
+                text="Approve",
+                command=lambda: detail_dialog.destroy() or approve_product(),
+                fg_color="#4caf50",
+                hover_color="#388e3c",
+                height=35,
+                width=100,
+            )
+            approve_button.pack(side="right", padx=(10, 0))
+
+    # Connect UI elements to functions
+    filter_menu.configure(command=on_filter_change)
+    sort_menu.configure(command=on_filter_change)
+    search_button.configure(command=on_search)
+
+    # Connect action buttons
+    approve_button.configure(command=approve_product)
+    reject_button.configure(command=reject_product)
+    view_button.configure(command=view_product_details)
+
+    # Initial data fetch
+    def on_frame_shown():
+        fetch_products()
+
+    frame.after(100, on_frame_shown)
+
+    return frame
diff --git a/app/frontend/components/admin/shop_owner_management.py b/app/frontend/components/admin/shop_owner_management.py
new file mode 100644
index 0000000000000000000000000000000000000000..4c872a016e2fbf85743be82699c337fc6c6dcf2e
--- /dev/null
+++ b/app/frontend/components/admin/shop_owner_management.py
@@ -0,0 +1,496 @@
+from tkinter import ttk
+import customtkinter as ctk
+from CTkMessagebox import CTkMessagebox
+import requests
+from datetime import datetime
+
+
+def admin_shop_owner_management_frame(parent, switch_func, API_URL, access_token):
+    """
+    Admin dashboard component for managing shop owners
+    """
+    frame = ctk.CTkFrame(parent)
+
+    # Store the token for later use
+    def update_token(new_token):
+        nonlocal access_token
+        access_token = new_token
+
+    frame.update_token = update_token
+
+    # Create main container with padding
+    main_container = ctk.CTkFrame(frame, fg_color="transparent")
+    main_container.pack(padx=40, pady=30, fill="both", expand=True)
+
+    # Header section
+    header_frame = ctk.CTkFrame(main_container, corner_radius=15, fg_color="#2e8b57")
+    header_frame.pack(fill="x", pady=(0, 20))
+
+    # Title and description
+    title_frame = ctk.CTkFrame(header_frame, fg_color="transparent")
+    title_frame.pack(padx=20, pady=15)
+
+    ctk.CTkLabel(
+        title_frame,
+        text="Shop Owner Management",
+        font=("Helvetica", 24, "bold"),
+        text_color="#ffffff",
+    ).pack(anchor="w")
+
+    ctk.CTkLabel(
+        title_frame,
+        text="Manage shop owner accounts and their shops",
+        font=("Helvetica", 14),
+        text_color="#e0e0e0",
+    ).pack(anchor="w")
+
+    # Search and actions panel
+    control_panel = ctk.CTkFrame(main_container, corner_radius=10, height=80)
+    control_panel.pack(fill="x", pady=(0, 15))
+
+    # Left side - search
+    search_frame = ctk.CTkFrame(control_panel, fg_color="transparent")
+    search_frame.pack(side="left", padx=20, pady=15, fill="y")
+
+    ctk.CTkLabel(search_frame, text="Search:", font=("Helvetica", 12, "bold")).pack(
+        side="left", padx=(0, 10)
+    )
+
+    search_entry = ctk.CTkEntry(
+        search_frame,
+        width=250,
+        height=35,
+        placeholder_text="Search by username or email",
+    )
+    search_entry.pack(side="left", padx=(0, 10))
+
+    search_button = ctk.CTkButton(
+        search_frame,
+        text="Search",
+        font=("Helvetica", 12, "bold"),
+        height=35,
+        corner_radius=8,
+        fg_color="#2e8b57",
+        hover_color="#1f6e42",
+    )
+    search_button.pack(side="left")
+
+    # Right side - actions
+    actions_frame = ctk.CTkFrame(control_panel, fg_color="transparent")
+    actions_frame.pack(side="right", padx=20, pady=15, fill="y")
+
+    view_shops_button = ctk.CTkButton(
+        actions_frame,
+        text="View Shops",
+        font=("Helvetica", 12, "bold"),
+        height=35,
+        width=120,
+        corner_radius=8,
+        fg_color="#3a7ebf",
+        hover_color="#2a6da9",
+    )
+    view_shops_button.pack(side="left", padx=(0, 10))
+
+    refresh_button = ctk.CTkButton(
+        actions_frame,
+        text="Refresh",
+        font=("Helvetica", 12, "bold"),
+        height=35,
+        width=100,
+        corner_radius=8,
+        fg_color="#4caf50",
+        hover_color="#388e3c",
+    )
+    refresh_button.pack(side="left", padx=(0, 10))
+
+    delete_button = ctk.CTkButton(
+        actions_frame,
+        text="Delete Owner",
+        font=("Helvetica", 12, "bold"),
+        height=35,
+        width=120,
+        corner_radius=8,
+        fg_color="#f44336",
+        hover_color="#d32f2f",
+    )
+    delete_button.pack(side="left")
+
+    # Data table frame
+    table_frame = ctk.CTkFrame(main_container, corner_radius=10)
+    table_frame.pack(fill="both", expand=True, pady=(15, 0))
+
+    # Configure Treeview style
+    style = ttk.Style()
+    style.theme_use("clam")  # Use clam theme as base
+
+    # Configure the Treeview colors to match app theme
+    style.configure(
+        "Treeview",
+        background="#2b2b2b",
+        foreground="#ffffff",
+        fieldbackground="#2b2b2b",
+        borderwidth=0,
+        rowheight=35,
+    )
+
+    # Configure the headings
+    style.configure(
+        "Treeview.Heading",
+        background="#2e8b57",
+        foreground="#ffffff",
+        borderwidth=0,
+        font=("Helvetica", 12, "bold"),
+    )
+
+    # Selection color
+    style.map("Treeview", background=[("selected", "#2e8b57")])
+
+    # Create scrollbar
+    scrollbar = ttk.Scrollbar(table_frame)
+    scrollbar.pack(side="right", fill="y")
+
+    # Create Treeview with styled tags
+    columns = ("id", "username", "email", "phone", "role")
+    owner_tree = ttk.Treeview(
+        table_frame, columns=columns, show="headings", yscrollcommand=scrollbar.set
+    )
+
+    # Configure scrollbar
+    scrollbar.config(command=owner_tree.yview)
+
+    # Define column headings
+    owner_tree.heading("id", text="ID")
+    owner_tree.heading("username", text="Username")
+    owner_tree.heading("email", text="Email")
+    owner_tree.heading("phone", text="Phone Number")
+    owner_tree.heading("role", text="Role")
+
+    # Define column widths
+    owner_tree.column("id", width=60, anchor="center")
+    owner_tree.column("username", width=150)
+    owner_tree.column("email", width=200)
+    owner_tree.column("phone", width=150)
+    owner_tree.column("role", width=100, anchor="center")
+
+    # Add tag configurations
+    owner_tree.tag_configure("owner", background="#252525")
+    owner_tree.tag_configure("highlight", background="#1a4731")
+    owner_tree.tag_configure("match", background="#1f3d5a")
+
+    owner_tree.pack(fill="both", expand=True, padx=5, pady=5)
+
+    # Footer with back button
+    footer_frame = ctk.CTkFrame(main_container, fg_color="transparent", height=50)
+    footer_frame.pack(fill="x", pady=(15, 0))
+
+    back_button = ctk.CTkButton(
+        footer_frame,
+        text="Back to Admin Dashboard",
+        command=lambda: switch_func("admin_dashboard"),
+        font=("Helvetica", 12, "bold"),
+        height=40,
+        corner_radius=8,
+        fg_color="#555555",
+        hover_color="#444444",
+    )
+    back_button.pack(side="left")
+
+    # Add endpoints to the backend for these actions
+    def fetch_shop_owners():
+        """Fetch all shop owners from the backend"""
+        headers = {"Authorization": f"Bearer {access_token}"}
+
+        try:
+            response = requests.get(f"{API_URL}/admin/owners", headers=headers)
+
+            if response.status_code == 200:
+                # Clear existing items
+                for item in owner_tree.get_children():
+                    owner_tree.delete(item)
+
+                shop_owners = response.json()
+
+                # Filter users by role (only shop owners)
+                row_count = 0
+                for owner in shop_owners:
+                    # Format date
+                    created_at = "N/A"
+                    if "created_at" in owner:
+                        try:
+                            dt = datetime.fromisoformat(
+                                owner["created_at"].replace("Z", "+00:00")
+                            )
+                            created_at = dt.strftime("%Y-%m-%d %H:%M")
+                        except:
+                            pass
+
+                    # Get number of shops if available
+                    shop_count = len(owner.get("shops", []))
+
+                    # Add with alternating tags for zebra striping
+                    tag = "owner" if row_count % 2 == 0 else ""
+                    if shop_count > 0:
+                        tag = "highlight"  # Highlight owners with shops
+
+                    owner_tree.insert(
+                        "",
+                        "end",
+                        values=(
+                            owner["id"],
+                            owner.get("username", "Unknown"),
+                            owner.get("email", ""),
+                            owner.get("phone_number", ""),
+                            owner.get("role", "shop_owner"),
+                        ),
+                        tags=(tag,),
+                    )
+                    row_count += 1
+            else:
+                CTkMessagebox(
+                    title="Error",
+                    message=response.json().get(
+                        "detail", "Failed to fetch shop owners"
+                    ),
+                    icon="cancel",
+                )
+        except Exception as e:
+            CTkMessagebox(
+                title="Connection Error",
+                message=f"Failed to connect to server: {e}",
+                icon="cancel",
+            )
+
+    def delete_shop_owner():
+        """Delete (ban) the selected shop owner"""
+        selected_item = owner_tree.selection()
+        if not selected_item:
+            CTkMessagebox(
+                title="Warning",
+                message="Please select a shop owner to delete",
+                icon="warning",
+            )
+            return
+
+        owner_id = owner_tree.item(selected_item[0])["values"][0]
+        username = owner_tree.item(selected_item[0])["values"][1]
+
+        # Confirm deletion
+        confirm = CTkMessagebox(
+            title="Confirm Deletion",
+            message=f"Are you sure you want to delete shop owner '{username}'?\n\nThis will also delete all their shops and products.\n\nThis action cannot be undone!",
+            icon="question",
+            option_1="Cancel",
+            option_2="Delete",
+        )
+
+        if confirm.get() != "Delete":
+            return
+
+        try:
+            headers = {"Authorization": f"Bearer {access_token}"}
+            response = requests.delete(
+                f"{API_URL}/admin/owners/{owner_id}", headers=headers
+            )
+
+            if response.status_code == 200:
+                CTkMessagebox(
+                    title="Success",
+                    message="Shop owner deleted successfully",
+                    icon="check",
+                )
+                fetch_shop_owners()  # Refresh the list
+            else:
+                CTkMessagebox(
+                    title="Error",
+                    message=response.json().get(
+                        "detail", "Failed to delete shop owner"
+                    ),
+                    icon="cancel",
+                )
+        except Exception as e:
+            CTkMessagebox(
+                title="Connection Error",
+                message=f"Failed to connect to server: {e}",
+                icon="cancel",
+            )
+
+    def view_shops():
+        """View shops owned by the selected shop owner"""
+        selected_item = owner_tree.selection()
+        if not selected_item:
+            CTkMessagebox(
+                title="Warning",
+                message="Please select a shop owner first",
+                icon="warning",
+            )
+            return
+
+        # Get selected owner ID and username
+        owner_id = owner_tree.item(selected_item[0])["values"][0]
+        username = owner_tree.item(selected_item[0])["values"][1]
+
+        # Create a popup to display shops
+        show_shops_dialog(owner_id, username)
+
+    def show_shops_dialog(owner_id, username):
+        # Fetch shops for this owner
+        shops = fetch_owner_shops(owner_id)
+
+        if not shops:
+            CTkMessagebox(
+                title="Shops", message=f"Owner '{username}' has no shops.", icon="info"
+            )
+            return
+
+        # Create popup dialog
+        dialog = ctk.CTkToplevel()
+        dialog.title(f"Shops owned by {username}")
+        dialog.geometry("600x400")
+        dialog.transient(frame)  # Make dialog modal
+        dialog.grab_set()
+
+        # Create a header
+        header_frame = ctk.CTkFrame(dialog, fg_color="#2e8b57", height=50)
+        header_frame.pack(fill="x", padx=10, pady=10)
+
+        ctk.CTkLabel(
+            header_frame,
+            text=f"Shops owned by {username}",
+            font=("Helvetica", 16, "bold"),
+            text_color="white",
+        ).pack(padx=20, pady=10)
+
+        # Create scrollable frame for shops
+        shops_frame = ctk.CTkScrollableFrame(dialog)
+        shops_frame.pack(fill="both", expand=True, padx=10, pady=10)
+
+        # Add each shop as a card
+        for shop in shops:
+            shop_card = ctk.CTkFrame(shops_frame, corner_radius=10, fg_color="#333333")
+            shop_card.pack(fill="x", padx=5, pady=5)
+
+            # Shop details
+            details_frame = ctk.CTkFrame(shop_card, fg_color="transparent")
+            details_frame.pack(fill="both", expand=True, padx=15, pady=15)
+
+            # Shop name
+            ctk.CTkLabel(
+                details_frame,
+                text=shop.get("name", "Unnamed Shop"),
+                font=("Helvetica", 14, "bold"),
+                text_color="#2e8b57",
+            ).pack(anchor="w")
+
+            # Description
+            description = shop.get("description", "No description")
+            ctk.CTkLabel(
+                details_frame,
+                text=f"Description: {description}",
+                font=("Helvetica", 12),
+                text_color="white",
+                wraplength=550,
+            ).pack(anchor="w", pady=(5, 0))
+
+            # Address
+            address = shop.get("address", "No address")
+            ctk.CTkLabel(
+                details_frame,
+                text=f"Address: {address}",
+                font=("Helvetica", 12),
+                text_color="white",
+            ).pack(anchor="w", pady=(5, 0))
+
+            # Created date
+            created_at = "N/A"
+            if "created_at" in shop:
+                try:
+                    dt = datetime.fromisoformat(
+                        shop["created_at"].replace("Z", "+00:00")
+                    )
+                    created_at = dt.strftime("%Y-%m-%d %H:%M")
+                except:
+                    pass
+
+            ctk.CTkLabel(
+                details_frame,
+                text=f"Created: {created_at}",
+                font=("Helvetica", 12),
+                text_color="#999999",
+            ).pack(anchor="w", pady=(5, 0))
+
+        # Close button
+        close_button = ctk.CTkButton(
+            dialog,
+            text="Close",
+            command=dialog.destroy,
+            font=("Helvetica", 12, "bold"),
+            height=40,
+            corner_radius=8,
+            fg_color="#555555",
+            hover_color="#444444",
+        )
+        close_button.pack(pady=(0, 10))
+
+    def fetch_owner_shops(owner_id):
+        try:
+            headers = {"Authorization": f"Bearer {access_token}"}
+            response = requests.get(
+                f"{API_URL}/admin/owners/{owner_id}/shops", headers=headers
+            )
+
+            if response.status_code == 200:
+                return response.json()
+            else:
+                CTkMessagebox(
+                    title="Error",
+                    message=response.json().get("detail", "Failed to fetch shops"),
+                    icon="cancel",
+                )
+                return []
+        except Exception as e:
+            CTkMessagebox(
+                title="Connection Error",
+                message=f"Failed to connect to server: {e}",
+                icon="cancel",
+            )
+            return []
+
+    def search_owners():
+        """Search owners based on the search term"""
+        search_term = search_entry.get().lower()
+        if not search_term:
+            fetch_shop_owners()
+            return
+
+        # Filter the treeview based on the search term
+        for item in owner_tree.get_children():
+            values = owner_tree.item(item)["values"]
+            # Check if search term is in username or email
+            if (
+                search_term in str(values[1]).lower()
+                or search_term in str(values[2]).lower()
+            ):
+                owner_tree.item(item, tags=("match",))
+            else:
+                owner_tree.detach(item)  # Hide non-matching items
+
+    # Connect functions to buttons
+    search_button.configure(command=search_owners)
+    refresh_button.configure(command=fetch_shop_owners)
+    delete_button.configure(command=delete_shop_owner)
+    view_shops_button.configure(command=view_shops)
+
+    # Fetch shop owners when the frame is shown
+    def on_frame_shown():
+        fetch_shop_owners()
+
+    frame.after(100, on_frame_shown)
+
+    # Add refresh method to frame for external calls
+    def refresh_data(*args):
+        """Public method to refresh shop owner data"""
+        fetch_shop_owners()
+
+    frame.refresh_data = refresh_data
+
+    return frame
diff --git a/app/frontend/components/admin/user_management.py b/app/frontend/components/admin/user_management.py
new file mode 100644
index 0000000000000000000000000000000000000000..8d9a3f425e103ebb47e4dcc5a9a5c30cf777bc11
--- /dev/null
+++ b/app/frontend/components/admin/user_management.py
@@ -0,0 +1,321 @@
+from tkinter import ttk
+import customtkinter as ctk
+from CTkMessagebox import CTkMessagebox
+import requests
+from datetime import datetime
+
+
+def admin_user_management_frame(parent, switch_func, API_URL, access_token):
+    """
+    Admin dashboard component for managing regular users
+    """
+    frame = ctk.CTkFrame(parent)
+
+    # Store the token for later use
+    def update_token(new_token):
+        nonlocal access_token
+        access_token = new_token
+
+    frame.update_token = update_token
+
+    # Create main container with padding
+    main_container = ctk.CTkFrame(frame, fg_color="transparent")
+    main_container.pack(padx=40, pady=30, fill="both", expand=True)
+
+    # Header section
+    header_frame = ctk.CTkFrame(main_container, corner_radius=15, fg_color="#1f538d")
+    header_frame.pack(fill="x", pady=(0, 20))
+
+    # Title and description
+    title_frame = ctk.CTkFrame(header_frame, fg_color="transparent")
+    title_frame.pack(padx=20, pady=15)
+
+    ctk.CTkLabel(
+        title_frame,
+        text="User Management",
+        font=("Helvetica", 24, "bold"),
+        text_color="#ffffff",
+    ).pack(anchor="w")
+
+    ctk.CTkLabel(
+        title_frame,
+        text="View and manage user accounts",
+        font=("Helvetica", 14),
+        text_color="#e0e0e0",
+    ).pack(anchor="w")
+
+    # Search and actions panel
+    control_panel = ctk.CTkFrame(main_container, corner_radius=10, height=80)
+    control_panel.pack(fill="x", pady=(0, 15))
+
+    # Left side - search
+    search_frame = ctk.CTkFrame(control_panel, fg_color="transparent")
+    search_frame.pack(side="left", padx=20, pady=15, fill="y")
+
+    ctk.CTkLabel(search_frame, text="Search:", font=("Helvetica", 12, "bold")).pack(
+        side="left", padx=(0, 10)
+    )
+
+    search_entry = ctk.CTkEntry(
+        search_frame,
+        width=250,
+        height=35,
+        placeholder_text="Search by username or email",
+    )
+    search_entry.pack(side="left", padx=(0, 10))
+
+    search_button = ctk.CTkButton(
+        search_frame,
+        text="Search",
+        font=("Helvetica", 12, "bold"),
+        height=35,
+        corner_radius=8,
+        fg_color="#3a7ebf",
+        hover_color="#2a6da9",
+    )
+    search_button.pack(side="left")
+
+    # Right side - actions
+    actions_frame = ctk.CTkFrame(control_panel, fg_color="transparent")
+    actions_frame.pack(side="right", padx=20, pady=15, fill="y")
+
+    refresh_button = ctk.CTkButton(
+        actions_frame,
+        text="Refresh",
+        font=("Helvetica", 12, "bold"),
+        height=35,
+        width=100,
+        corner_radius=8,
+        fg_color="#4caf50",
+        hover_color="#388e3c",
+    )
+    refresh_button.pack(side="left", padx=(0, 10))
+
+    delete_button = ctk.CTkButton(
+        actions_frame,
+        text="Delete User",
+        font=("Helvetica", 12, "bold"),
+        height=35,
+        width=120,
+        corner_radius=8,
+        fg_color="#f44336",
+        hover_color="#d32f2f",
+    )
+    delete_button.pack(side="left")
+
+    # Data table frame
+    table_frame = ctk.CTkFrame(main_container, corner_radius=10)
+    table_frame.pack(fill="both", expand=True, pady=(15, 0))
+
+    # Configure Treeview style
+    style = ttk.Style()
+    style.theme_use("clam")  # Use clam theme as base
+
+    # Configure the Treeview colors to match app theme
+    style.configure(
+        "Treeview",
+        background="#2b2b2b",
+        foreground="#ffffff",
+        fieldbackground="#2b2b2b",
+        borderwidth=0,
+        rowheight=35,
+    )
+
+    # Configure the headings
+    style.configure(
+        "Treeview.Heading",
+        background="#1f538d",
+        foreground="#ffffff",
+        borderwidth=0,
+        font=("Helvetica", 12, "bold"),
+    )
+
+    # Selection color
+    style.map("Treeview", background=[("selected", "#3a7ebf")])
+
+    # Create scrollbar
+    scrollbar = ttk.Scrollbar(table_frame)
+    scrollbar.pack(side="right", fill="y")
+
+    # Create Treeview with styled tags
+    columns = ("id", "username", "email", "phone", "role")
+    user_tree = ttk.Treeview(
+        table_frame, columns=columns, show="headings", yscrollcommand=scrollbar.set
+    )
+
+    # Configure scrollbar
+    scrollbar.config(command=user_tree.yview)
+
+    # Define column headings
+    user_tree.heading("id", text="ID")
+    user_tree.heading("username", text="Username")
+    user_tree.heading("email", text="Email")
+    user_tree.heading("phone", text="Phone Number")
+    user_tree.heading("role", text="Role")
+
+    # Define column widths
+    user_tree.column("id", width=60, anchor="center")
+    user_tree.column("username", width=150)
+    user_tree.column("email", width=200)
+    user_tree.column("phone", width=150)
+    user_tree.column("role", width=100, anchor="center")
+
+    # Add tag configurations
+    user_tree.tag_configure("user", background="#252525")
+    user_tree.tag_configure("match", background="#1f3d5a")
+
+    user_tree.pack(fill="both", expand=True, padx=5, pady=5)
+
+    # Footer with back button
+    footer_frame = ctk.CTkFrame(main_container, fg_color="transparent", height=50)
+    footer_frame.pack(fill="x", pady=(15, 0))
+
+    back_button = ctk.CTkButton(
+        footer_frame,
+        text="Back to Admin Dashboard",
+        command=lambda: switch_func("admin_dashboard"),
+        font=("Helvetica", 12, "bold"),
+        height=40,
+        corner_radius=8,
+        fg_color="#555555",
+        hover_color="#444444",
+    )
+    back_button.pack(side="left")
+
+    # Add endpoints to the backend for these actions
+    def fetch_users():
+        """Fetch all regular users from the backend"""
+        headers = {"Authorization": f"Bearer {access_token}"}
+
+        try:
+            response = requests.get(f"{API_URL}/admin/users", headers=headers)
+
+            if response.status_code == 200:
+                # Clear existing items
+                for item in user_tree.get_children():
+                    user_tree.delete(item)
+
+                users = response.json()
+
+                # Filter users by role (only regular users, not admins)
+                row_count = 0
+                for user in users:
+                    if user["role"] == "buyer":
+                        # Add row with alternating tags for zebra striping
+                        tag = "user" if row_count % 2 == 0 else ""
+                        user_tree.insert(
+                            "",
+                            "end",
+                            values=(
+                                user["id"],
+                                user["username"],
+                                user["email"],
+                                user.get("phone_number", "N/A"),
+                                user["role"],
+                            ),
+                            tags=(tag,),
+                        )
+                        row_count += 1
+            else:
+                CTkMessagebox(
+                    title="Error",
+                    message=response.json().get("detail", "Failed to fetch users"),
+                    icon="cancel",
+                )
+        except requests.exceptions.RequestException as e:
+            CTkMessagebox(
+                title="Connection Error",
+                message=f"Failed to connect to server: {e}",
+                icon="cancel",
+            )
+
+    def delete_user():
+        """Delete (ban) the selected user"""
+        selected_item = user_tree.selection()
+        if not selected_item:
+            CTkMessagebox(
+                title="Warning",
+                message="Please select a user to delete",
+                icon="warning",
+            )
+            return
+
+        user_id = user_tree.item(selected_item[0])["values"][0]
+        username = user_tree.item(selected_item[0])["values"][1]
+
+        # Confirm deletion
+        confirm = CTkMessagebox(
+            title="Confirm Deletion",
+            message=f"Are you sure you want to delete user '{username}'?",
+            icon="question",
+            option_1="Cancel",
+            option_2="Delete",
+        )
+
+        if confirm.get() != "Delete":
+            return
+
+        # Send delete request
+        headers = {"Authorization": f"Bearer {access_token}"}
+
+        try:
+            response = requests.delete(
+                f"{API_URL}/admin/users/{user_id}", headers=headers
+            )
+
+            if response.status_code == 200:
+                CTkMessagebox(
+                    title="Success", message="User deleted successfully", icon="check"
+                )
+                fetch_users()  # Refresh the list
+            else:
+                CTkMessagebox(
+                    title="Error",
+                    message=response.json().get("detail", "Failed to delete user"),
+                    icon="cancel",
+                )
+        except requests.exceptions.RequestException as e:
+            CTkMessagebox(
+                title="Connection Error",
+                message=f"Failed to connect to server: {e}",
+                icon="cancel",
+            )
+
+    def search_users():
+        """Search users based on the search term"""
+        search_term = search_entry.get().lower()
+        if not search_term:
+            fetch_users()
+            return
+
+        # Filter the treeview based on the search term
+        for item in user_tree.get_children():
+            values = user_tree.item(item)["values"]
+            # Check if search term is in username or email
+            if (
+                search_term in str(values[1]).lower()
+                or search_term in str(values[2]).lower()
+            ):
+                user_tree.item(item, tags=("match",))
+            else:
+                user_tree.detach(item)  # Hide non-matching items
+
+    # Connect functions to buttons
+    search_button.configure(command=search_users)
+    refresh_button.configure(command=fetch_users)
+    delete_button.configure(command=delete_user)
+
+    # Fetch users when the frame is shown
+    def on_frame_shown():
+        fetch_users()
+
+    frame.after(100, on_frame_shown)
+
+    # Add refresh method to frame for external calls
+    def refresh_data(*args):
+        """Public method to refresh user data"""
+        fetch_users()
+
+    frame.refresh_data = refresh_data
+
+    return frame
diff --git a/app/frontend/components/owner/owner_dashboard.py b/app/frontend/components/owner/owner_dashboard.py
index 284d4d2a1badf07dbc297be9ce867af26e77024c..341019a831f9f242bf189252cfa2d4ec491990ec 100644
--- a/app/frontend/components/owner/owner_dashboard.py
+++ b/app/frontend/components/owner/owner_dashboard.py
@@ -307,8 +307,8 @@ def owner_dashboard_frame(parent, switch_func, API_URL, token):
     headers_frame.pack(fill="x")
 
     # Create the headers
-    header_texts = ["Image", "Title", "Product Name", "Price", "Quantity"]
-    header_widths = [0.15, 0.25, 0.25, 0.15, 0.2]  # Adjusted proportional widths
+    header_texts = ["Image", "Title", "Product Name", "Category", "Price", "Quantity"]
+    header_widths = [0.15, 0.2, 0.2, 0.15, 0.15, 0.15]  # Adjusted proportional widths
 
     for i, text in enumerate(header_texts):
         header_cell = ctk.CTkFrame(headers_frame, fg_color="transparent")
@@ -387,10 +387,39 @@ def owner_dashboard_frame(parent, switch_func, API_URL, token):
         )
         name_label.place(relx=0.5, rely=0.5, anchor="center")
 
+        # Category cell
+        category_cell = ctk.CTkFrame(row, fg_color="transparent")
+        category_cell.place(
+            relx=sum(header_widths[:3]), rely=0, relwidth=header_widths[3], relheight=1
+        )
+
+        category_name = "Uncategorized"
+        try:
+            # Debug the category data
+            print(f"DEBUG - Processing category for product {product.get('name')}:")
+            print(f"  Category ID: {product.get('category_id')}")
+            print(f"  Category object: {product.get('category')}")
+
+            if product.get("category") is not None and product["category"].get("name"):
+                category_name = product["category"]["name"]
+                print(f"  Using category name: {category_name}")
+            else:
+                print("  Using default: Uncategorized")
+        except Exception as e:
+            print(f"Error processing category: {e}")
+
+        category_label = ctk.CTkLabel(
+            category_cell,
+            text=category_name,
+            font=("Helvetica", 12),
+            text_color="#A0A0A0",  # Light gray color for category
+        )
+        category_label.place(relx=0.5, rely=0.5, anchor="center")
+
         # Price cell
         price_cell = ctk.CTkFrame(row, fg_color="transparent")
         price_cell.place(
-            relx=sum(header_widths[:3]), rely=0, relwidth=header_widths[3], relheight=1
+            relx=sum(header_widths[:4]), rely=0, relwidth=header_widths[4], relheight=1
         )
 
         price_label = ctk.CTkLabel(
@@ -404,7 +433,7 @@ def owner_dashboard_frame(parent, switch_func, API_URL, token):
         # Quantity cell
         qty_cell = ctk.CTkFrame(row, fg_color="transparent")
         qty_cell.place(
-            relx=sum(header_widths[:4]), rely=0, relwidth=header_widths[4], relheight=1
+            relx=sum(header_widths[:5]), rely=0, relwidth=header_widths[5], relheight=1
         )
 
         qty_label = ctk.CTkLabel(
@@ -509,6 +538,35 @@ def owner_dashboard_frame(parent, switch_func, API_URL, token):
                     if products_resp.status_code == 200:
                         products = products_resp.json()
 
+                        # Debug output to see product data
+                        print("DEBUG: Products response received:")
+                        try:
+                            # Print the raw response
+                            print(
+                                f"Raw response: {products_resp.text[:200]}..."
+                            )  # First 200 chars only
+
+                            # Print product details for first few products
+                            for i, p in enumerate(
+                                products[:2]
+                            ):  # Just print the first 2 to keep it manageable
+                                print(f"Product {i + 1}: {p.get('name')}")
+                                print(f"  Category ID: {p.get('category_id')}")
+                                print(
+                                    f"  Has Category Object: {p.get('category') is not None}"
+                                )
+                                if p.get("category"):
+                                    print(
+                                        f"  Category Name: {p.get('category').get('name')}"
+                                    )
+                                else:
+                                    print("  No category object")
+                                print("  Full Product Data:")
+                                print(f"  {p}")
+                                print("---")
+                        except Exception as e:
+                            print(f"Error while debugging product data: {e}")
+
                         # Clear existing product rows
                         clear_product_rows()
 
diff --git a/app/frontend/components/owner/owner_orders.py b/app/frontend/components/owner/owner_orders.py
index e2c59a71665e1898cef297e26475cf89220b6c1c..9314034d7ec22293f90b460e80d1ef0a09eb3174 100644
--- a/app/frontend/components/owner/owner_orders.py
+++ b/app/frontend/components/owner/owner_orders.py
@@ -280,13 +280,31 @@ def owner_orders_frame(parent, switch_func, API_URL, token):
             product_name = item.get("product", {}).get("name", "Unknown Product")
             quantity = item.get("quantity", 0)
 
+            # Get category name
+            category_name = "Uncategorized"
+            if item.get("product", {}).get("category", {}) and item["product"][
+                "category"
+            ].get("name"):
+                category_name = item["product"]["category"]["name"]
+
+            product_frame = ctk.CTkFrame(products_list, fg_color="transparent")
+            product_frame.pack(anchor="w", fill="x")
+
             item_label = ctk.CTkLabel(
-                products_list,
+                product_frame,
                 text=f"{product_name} (x{quantity})",
                 font=("Helvetica", 12),
                 text_color="#ccc",
             )
-            item_label.pack(anchor="w")
+            item_label.pack(anchor="w", side="left")
+
+            category_label = ctk.CTkLabel(
+                product_frame,
+                text=f"[{category_name}]",
+                font=("Helvetica", 10),
+                text_color="#A0A0A0",  # Light gray for category
+            )
+            category_label.pack(anchor="w", side="left", padx=(5, 0))
 
         if len(items) > 2:
             more_label = ctk.CTkLabel(
diff --git a/app/frontend/components/owner/owner_products.py b/app/frontend/components/owner/owner_products.py
index fbcee050ce37d1cf6b193b67e824a588d912b298..bf49d962a3ce3b5dd5db0de764b0fe7fe2e8150b 100644
--- a/app/frontend/components/owner/owner_products.py
+++ b/app/frontend/components/owner/owner_products.py
@@ -152,15 +152,24 @@ def owner_products_frame(parent, switch_func, API_URL, token):
     headers_frame.pack_propagate(False)
 
     # Create the headers
-    header_texts = ["Image", "Title", "Product Name", "Price", "Quantity", "Action"]
+    header_texts = [
+        "Image",
+        "Title",
+        "Product Name",
+        "Category",
+        "Price",
+        "Quantity",
+        "Action",
+    ]
     header_widths = [
         0.15,
-        0.2,
-        0.2,
         0.15,
+        0.15,
+        0.15,
+        0.1,
         0.1,
         0.2,
-    ]  # Proportional widths adjusted for price
+    ]  # Proportional widths adjusted for category column
 
     for i, text in enumerate(header_texts):
         header_cell = ctk.CTkFrame(headers_frame, fg_color="transparent")
@@ -239,10 +248,39 @@ def owner_products_frame(parent, switch_func, API_URL, token):
         )
         name_label.place(relx=0.5, rely=0.5, anchor="center")
 
+        # Category cell
+        category_cell = ctk.CTkFrame(row, fg_color="transparent")
+        category_cell.place(
+            relx=sum(header_widths[:3]), rely=0, relwidth=header_widths[3], relheight=1
+        )
+
+        category_name = "Uncategorized"
+        try:
+            # Debug the category data
+            print(f"DEBUG - Processing category for product {product.get('name')}:")
+            print(f"  Category ID: {product.get('category_id')}")
+            print(f"  Category object: {product.get('category')}")
+
+            if product.get("category") is not None and product["category"].get("name"):
+                category_name = product["category"]["name"]
+                print(f"  Using category name: {category_name}")
+            else:
+                print("  Using default: Uncategorized")
+        except Exception as e:
+            print(f"Error processing category: {e}")
+
+        category_label = ctk.CTkLabel(
+            category_cell,
+            text=category_name,
+            font=("Helvetica", 12),
+            text_color="#A0A0A0",  # Light gray color for category
+        )
+        category_label.place(relx=0.5, rely=0.5, anchor="center")
+
         # Price cell
         price_cell = ctk.CTkFrame(row, fg_color="transparent")
         price_cell.place(
-            relx=sum(header_widths[:3]), rely=0, relwidth=header_widths[3], relheight=1
+            relx=sum(header_widths[:4]), rely=0, relwidth=header_widths[4], relheight=1
         )
 
         price_label = ctk.CTkLabel(
@@ -256,7 +294,7 @@ def owner_products_frame(parent, switch_func, API_URL, token):
         # Quantity cell
         qty_cell = ctk.CTkFrame(row, fg_color="transparent")
         qty_cell.place(
-            relx=sum(header_widths[:4]), rely=0, relwidth=header_widths[4], relheight=1
+            relx=sum(header_widths[:5]), rely=0, relwidth=header_widths[5], relheight=1
         )
 
         qty_label = ctk.CTkLabel(
@@ -270,7 +308,7 @@ def owner_products_frame(parent, switch_func, API_URL, token):
         # Action cell
         action_cell = ctk.CTkFrame(row, fg_color="transparent")
         action_cell.place(
-            relx=sum(header_widths[:5]), rely=0, relwidth=header_widths[5], relheight=1
+            relx=sum(header_widths[:6]), rely=0, relwidth=header_widths[6], relheight=1
         )
 
         # Action buttons container (centered within action cell)
@@ -441,6 +479,18 @@ def owner_products_frame(parent, switch_func, API_URL, token):
                     if prod_resp.status_code == 200:
                         products = prod_resp.json()
 
+                        # Debug output to see product data
+                        print("DEBUG: Products response received in owner_products:")
+                        for p in products[
+                            :2
+                        ]:  # Just print the first 2 to keep it manageable
+                            print(f"Product: {p.get('name')}")
+                            print(f"Category ID: {p.get('category_id')}")
+                            print(f"Category: {p.get('category')}")
+                            if p.get("category"):
+                                print(f"Category Name: {p.get('category').get('name')}")
+                            print("---")
+
                         # Clear existing product rows
                         clear_products_table()
 
diff --git a/app/frontend/components/product/create_product.py b/app/frontend/components/product/create_product.py
index adeb6f276996290857b141a571dd334668a54bc5..68e8f1b3eec7945a0849f6f32907ec2332b98d56 100644
--- a/app/frontend/components/product/create_product.py
+++ b/app/frontend/components/product/create_product.py
@@ -123,6 +123,66 @@ def create_product_frame(parent, switch_func, API_URL, token):
         left_col, "Stock Quantity", "Enter available stock..."
     )
 
+    # Category dropdown
+    category_frame = ctk.CTkFrame(left_col, fg_color="transparent")
+    category_frame.pack(fill="x", pady=(0, 15))
+
+    category_label = ctk.CTkLabel(
+        category_frame, text="Category", font=("Helvetica", 14), text_color="white"
+    )
+    category_label.pack(anchor="w")
+
+    # Dictionary to store category id -> name mapping
+    categories_data = {}
+    # List to store category names for the dropdown
+    category_options = ["Loading categories..."]
+
+    category_dropdown = ctk.CTkOptionMenu(
+        category_frame,
+        values=category_options,
+        height=40,
+        corner_radius=8,
+        fg_color="#3b3b3b",
+        button_color=SHOPPING,
+        button_hover_color="#0096ff",
+        dropdown_fg_color="#3b3b3b",
+        text_color="white",
+    )
+    category_dropdown.pack(fill="x", pady=(5, 0))
+
+    # Function to fetch categories from API
+    def fetch_categories():
+        headers = {"Authorization": f"Bearer {token}"}
+        try:
+            response = requests.get(f"{API_URL}/category", headers=headers)
+            if response.status_code == 200:
+                categories = response.json()
+
+                # Clear and update the categories dictionary
+                categories_data.clear()
+                category_names = []
+
+                if categories:
+                    for cat in categories:
+                        categories_data[cat["name"]] = cat["id"]
+                        category_names.append(cat["name"])
+                else:
+                    category_names = ["No categories available"]
+
+                # Update the dropdown
+                category_dropdown.configure(values=category_names)
+                if category_names:
+                    category_dropdown.set(category_names[0])
+            else:
+                messagebox.showerror(
+                    "Error",
+                    f"Failed to fetch categories. Status: {response.status_code}",
+                )
+        except Exception as e:
+            messagebox.showerror("Error", f"Failed to fetch categories: {e}")
+            category_dropdown.configure(values=["Error loading categories"])
+            category_dropdown.set("Error loading categories")
+
     # Description with multiline entry
     desc_frame = ctk.CTkFrame(left_col, fg_color="transparent")
     desc_frame.pack(fill="x", pady=(0, 15))
@@ -208,6 +268,10 @@ def create_product_frame(parent, switch_func, API_URL, token):
         price_val = price_entry.get().strip()
         desc_val = desc_entry.get("1.0", "end-1c").strip()
         stock_val = stock_entry.get().strip()
+        category_name = category_dropdown.get()
+
+        # Get the category ID from the selected name
+        category_id = categories_data.get(category_name)
 
         if not title_val or not price_val or not stock_val:
             messagebox.showerror("Error", "Title, Price, and Stock are required")
@@ -271,6 +335,7 @@ def create_product_frame(parent, switch_func, API_URL, token):
                 "description": desc_val,
                 "stock": stock_val,
                 "shop_id": shop_id,  # Include the shop_id
+                "category_id": category_id,  # Include the category_id
             }
             files = {}
             if os.path.isfile(image_path.get()):
@@ -326,4 +391,7 @@ def create_product_frame(parent, switch_func, API_URL, token):
     )
     submit_button.pack(side="right", fill="x", expand=True, padx=(5, 0))
 
+    # Fetch categories when frame is created
+    frame.after(100, fetch_categories)
+
     return frame
diff --git a/app/frontend/components/product/edit_product.py b/app/frontend/components/product/edit_product.py
index b3fcb0ae50c621566a511ae665048bb082760cf0..c15a367bfc8e6c2add878643b77cf7db23976bfe 100644
--- a/app/frontend/components/product/edit_product.py
+++ b/app/frontend/components/product/edit_product.py
@@ -125,6 +125,77 @@ def edit_product_frame(parent, switch_func, API_URL, token, product_id=None):
         left_col, "Stock Quantity", "Enter available stock..."
     )
 
+    # Category dropdown
+    category_frame = ctk.CTkFrame(left_col, fg_color="transparent")
+    category_frame.pack(fill="x", pady=(0, 15))
+
+    category_label = ctk.CTkLabel(
+        category_frame, text="Category", font=("Helvetica", 14), text_color="white"
+    )
+    category_label.pack(anchor="w")
+
+    # Dictionary to store category id -> name mapping
+    categories_data = {}
+    # Dictionary to store category name -> id mapping
+    categories_id_to_name = {}
+    # List to store category names for the dropdown
+    category_options = ["Loading categories..."]
+
+    category_dropdown = ctk.CTkOptionMenu(
+        category_frame,
+        values=category_options,
+        height=40,
+        corner_radius=8,
+        fg_color="#3b3b3b",
+        button_color=SHOPPING,
+        button_hover_color="#0096ff",
+        dropdown_fg_color="#3b3b3b",
+        text_color="white",
+    )
+    category_dropdown.pack(fill="x", pady=(5, 0))
+
+    # Function to fetch categories from API
+    def fetch_categories():
+        headers = {"Authorization": f"Bearer {token}"}
+        try:
+            response = requests.get(f"{API_URL}/category", headers=headers)
+            if response.status_code == 200:
+                categories = response.json()
+
+                # Clear and update the categories dictionaries
+                categories_data.clear()
+                categories_id_to_name.clear()
+                category_names = []
+
+                if categories:
+                    for cat in categories:
+                        cat_id = cat["id"]
+                        cat_name = cat["name"]
+                        categories_data[cat_name] = cat_id
+                        categories_id_to_name[cat_id] = cat_name
+                        category_names.append(cat_name)
+                else:
+                    category_names = ["No categories available"]
+
+                # Update the dropdown
+                category_dropdown.configure(values=category_names)
+
+                # If we have a category_id from the product, select it
+                if category_id and category_id in categories_id_to_name:
+                    category_name = categories_id_to_name[category_id]
+                    category_dropdown.set(category_name)
+                elif category_names:
+                    category_dropdown.set(category_names[0])
+            else:
+                messagebox.showerror(
+                    "Error",
+                    f"Failed to fetch categories. Status: {response.status_code}",
+                )
+        except Exception as e:
+            messagebox.showerror("Error", f"Failed to fetch categories: {e}")
+            category_dropdown.configure(values=["Error loading categories"])
+            category_dropdown.set("Error loading categories")
+
     # Description with multiline entry
     desc_frame = ctk.CTkFrame(left_col, fg_color="transparent")
     desc_frame.pack(fill="x", pady=(0, 15))
@@ -218,10 +289,15 @@ def edit_product_frame(parent, switch_func, API_URL, token, product_id=None):
     buttons_frame.pack(fill="x", pady=(20, 0))
 
     def submit_changes():
+        nonlocal product_id, shop_id, category_id
         title_val = prod_title_entry.get().strip()
         price_val = price_entry.get().strip()
         desc_val = desc_entry.get("1.0", "end-1c").strip()
         stock_val = stock_entry.get().strip()
+        category_name = category_dropdown.get()
+
+        # Get the category ID from the selected name
+        selected_category_id = categories_data.get(category_name, None)
 
         if not title_val or not price_val or not stock_val:
             messagebox.showerror("Error", "Title, Price, and Stock are required")
@@ -265,10 +341,14 @@ def edit_product_frame(parent, switch_func, API_URL, token, product_id=None):
             "description": desc_val,
             "stock": stock_val,
             "shop_id": shop_id,  # Use the loaded shop_id
-            "category_id": category_id
-            or 1,  # Use the loaded category_id or default to 1
         }
 
+        # Only add category_id to the data if it's a valid value
+        if selected_category_id is not None:
+            data["category_id"] = str(
+                selected_category_id
+            )  # Ensure it's a string for the form data
+
         # Prepare files for upload if a new image was selected
         files = {}
         if image_path and os.path.isfile(image_path):
@@ -287,6 +367,20 @@ def edit_product_frame(parent, switch_func, API_URL, token, product_id=None):
         # Make the API request
         headers = {"Authorization": f"Bearer {token}"}
         try:
+            # Debug output
+            print(f"DEBUG - Submitting product update:")
+            print(f"  Product ID: {product_id}")
+            print(f"  Name: {title_val}")
+            print(f"  Shop ID: {shop_id}")
+            print(f"  Category ID: {selected_category_id}")
+
+            # Check if product_id is None
+            if product_id is None:
+                messagebox.showerror(
+                    "Error", "Product ID is missing. Cannot update product."
+                )
+                return
+
             # Use PUT for updating existing product
             resp = requests.put(
                 f"{API_URL}/product/put/{product_id}",
@@ -379,6 +473,9 @@ def edit_product_frame(parent, switch_func, API_URL, token, product_id=None):
                 shop_id = product_data.get("shop_id")
                 category_id = product_data.get("category_id")
 
+                # Fetch categories to populate the dropdown with the current category selected
+                fetch_categories()
+
                 # Reset image path since we're loading a product
                 image_path = ""
 
@@ -427,13 +524,26 @@ def edit_product_frame(parent, switch_func, API_URL, token, product_id=None):
 
     # Load product data when frame is created
     if product_id:
+        print(f"DEBUG - Initial product_id: {product_id}")
         load_product_data()
 
     def refresh_data(new_product_id=None):
         nonlocal product_id
-        if new_product_id:
+        print(f"DEBUG - refresh_data called with new_product_id: {new_product_id}")
+        print(f"DEBUG - current product_id before refresh: {product_id}")
+
+        if new_product_id is not None:
             product_id = new_product_id
+            print(f"DEBUG - Updated product_id to: {product_id}")
             load_product_data()
+        else:
+            print("DEBUG - No new product ID provided, using existing ID")
+            if product_id is not None:
+                load_product_data()
+            else:
+                print("WARNING - No product ID available, cannot load product data")
+                messagebox.showerror("Error", "No product ID available to load data")
+                go_back()
 
     frame.refresh_data = refresh_data
 
diff --git a/app/frontend/components/product/view_product.py b/app/frontend/components/product/view_product.py
index 7891b788b3c41d2cb16e078123310f016a51d0df..d7bac1aba0107975bd186228885cbfb2d81af604 100644
--- a/app/frontend/components/product/view_product.py
+++ b/app/frontend/components/product/view_product.py
@@ -20,35 +20,25 @@ BACKEND_HOST = "http://127.0.0.1:8000"
 
 
 def fix_url(url):
-    """
-    If the provided URL does not start with http, assume it's a relative path.
-    Remove any unwanted prefix (e.g., "app/static/") and prepend the public URL.
-    """
-    print(f"[DEBUG] fix_url received: {url}")
-    result = ""
-
+    """Fix URLs to ensure they work with the backend"""
+    # Convert API URL to BACKEND_HOST for image URLs
     if not url:
-        print("[DEBUG] URL is None or empty")
         return ""
 
-    if url.startswith("http"):
-        print(f"[DEBUG] URL already starts with http, returning as is: {url}")
-        result = url
-    else:
-        # If the URL starts with "app/static/", remove that part.
-        prefix = "app/static/"
-        if url.startswith(prefix):
-            url = url[len(prefix) :]
-            print(f"[DEBUG] Removed prefix, now: {url}")
-
-        # Prepend the public URL
+    # For URLs that need the backend host prefix
+    if not url.startswith("http"):
+        # Strip app/static/ prefix if present
+        if url.startswith("app/static/"):
+            url = url[len("app/static/") :]
+
+        # Add the backend static prefix
         result = f"{BACKEND_HOST}/static/{url}"
         print(f"[DEBUG] Final URL after fixing: {result}")
 
     return result
 
 
-def view_shop_frame(parent, switch_func, API_URL, token, shop_id):
+def product_view_shop_frame(parent, switch_func, API_URL, token, shop_id):
     """
     CustomTkinter-based frame to display shop details and products.
     """
diff --git a/app/frontend/main.py b/app/frontend/main.py
index c4994778f96ae003a4e8e21e2fb4d9a4e79ccde6..709fbd1ea42109022fd7ec98f4d76895ad86e183 100644
--- a/app/frontend/main.py
+++ b/app/frontend/main.py
@@ -13,6 +13,9 @@ from components.product.create_product import create_product_frame
 from components.product.view_product import view_product_frame
 from components.product.edit_product import edit_product_frame
 from components.admin.category import category_frame
+from components.admin.dashboard import admin_dashboard_frame
+from components.admin.user_management import admin_user_management_frame
+from components.admin.shop_owner_management import admin_shop_owner_management_frame
 from components.dashboard import dashboard_frame
 from components.user_details import user_details_frame
 from components.user_orders import user_orders_frame
@@ -95,6 +98,9 @@ def switch_frame(frame_name, *args):
                 if user_role == "shop_owner":
                     print("User is a shop owner, redirecting to owner_dashboard")
                     frame_name = "owner_dashboard"
+                elif user_role == "admin":
+                    print("User is an admin, redirecting to admin_dashboard")
+                    frame_name = "admin_dashboard"
                 else:
                     print(
                         f"User is not a shop owner (role: {user_role}), proceeding to dashboard"
@@ -122,17 +128,11 @@ def switch_frame(frame_name, *args):
                 print(f"Updating token for frame: {frame_key}")
                 frame_obj.update_token(access_token)
 
-    # Role-based routing
-    print(
-        f"Checking role-based routing. Current user_role: {user_role}, target frame: {frame_name}"
-    )
-
     # Check if we're coming from an owner page trying to access the dashboard
     owner_going_to_shop = False
     if len(args) > 1 and args[1] == "from_owner_page" and frame_name == "dashboard":
         owner_going_to_shop = True
         print("Owner explicitly navigating to shop dashboard")
-
     # Only apply role-based routing if not bypassing
     if not skip_role_check:
         if (
@@ -143,12 +143,36 @@ def switch_frame(frame_name, *args):
             # Redirect shop owners to the owner dashboard, but only if not explicitly navigating to shop
             print("Redirecting shop owner from dashboard to owner_dashboard")
             frame_name = "owner_dashboard"
+        elif user_role == "shop_owner" and frame_name == "view_product":
+            # Always allow shop owners to view products
+            print("Shop owner viewing product - allowing access")
+            pass  # Just proceed with view_product frame
+        # Explicitly allow all users to access view_shop and view_product
+        elif frame_name in ["view_shop", "view_product"]:
+            print(
+                f"User with role {user_role} accessing {frame_name} - allowing access"
+            )
+            pass  # Allow access to view_shop and view_product for all roles
+        elif user_role == "admin" and frame_name == "dashboard":
+            # Redirect admins to the admin dashboard
+            print("Redirecting admin from dashboard to admin_dashboard")
+            frame_name = "admin_dashboard"
         elif user_role != "shop_owner" and frame_name == "owner_dashboard":
             # Prevent non-owners from accessing owner dashboard
             print(
                 f"Preventing non-owner (role: {user_role}) from accessing owner_dashboard"
             )
             frame_name = "dashboard"
+        elif user_role != "admin" and frame_name in [
+            "admin_dashboard",
+            "admin_user_management",
+            "admin_shop_owner_management",
+        ]:
+            # Prevent non-admins from accessing admin dashboards
+            print(
+                f"Preventing non-admin (role: {user_role}) from accessing admin pages"
+            )
+            frame_name = "dashboard"
 
     frame = frames.get(frame_name)
     if frame is None:
@@ -156,13 +180,49 @@ def switch_frame(frame_name, *args):
         return
 
     # If there's a refresh method on the frame and we have arguments, call it
-    if hasattr(frame, "refresh_data") and len(args) > 0:
-        print(f"Calling refresh_data on {frame_name}")
-        try:
-            frame.refresh_data(*args)
-        except Exception as e:
-            print(f"Error calling refresh_data on {frame_name}: {e}")
-            # Continue despite the error
+    if hasattr(frame, "refresh_data"):
+        # If the first argument is True, it explicitly requests a refresh
+        if len(args) > 0 and args[0] is True:
+            print(f"Explicitly refreshing {frame_name}")
+            frame.refresh_data(*args[1:] if len(args) > 1 else [])
+        # Otherwise, refresh when switching to admin components to keep data current
+        elif frame_name in [
+            "admin_dashboard",
+            "admin_user_management",
+            "admin_shop_owner_management",
+            "category",
+            "owner_dashboard",
+            "owner_products",
+            "owner_orders",
+        ]:
+            print(f"Auto-refreshing {frame_name}")
+            frame.refresh_data()
+        # Add special handling for view_shop and view_product
+        elif frame_name == "view_shop":
+            print(f"*** DEBUG: Switching to view_shop with args: {args}")
+            # If we have a shop_id, pass it to refresh_data
+            if len(args) > 0 and args[0] is not None:
+                shop_id = args[0]
+                print(f"*** DEBUG: Refreshing view_shop with shop_id: {shop_id}")
+                frame.refresh_data(shop_id)
+        elif frame_name == "view_product":
+            print(f"*** DEBUG: Switching to view_product with args: {args}")
+            # If we have product data, pass it to refresh_data
+            if len(args) > 0 and args[0] is not None:
+                product_data = args[0]
+                print(
+                    f"*** DEBUG: Refreshing view_product with product data: {product_data}"
+                )
+                frame.refresh_data(product_data)
+        elif frame_name == "edit_product":
+            print(f"*** DEBUG: Switching to edit_product with args: {args}")
+            # If we have a product_id, pass it to refresh_data
+            if len(args) > 0 and args[0] is not None:
+                product_id = args[0]
+                print(
+                    f"*** DEBUG: Refreshing edit_product with product_id: {product_id}"
+                )
+                frame.refresh_data(product_id)
 
     # Make sure we have a valid token for authenticated pages
     if frame_name not in ["login", "register"] and (
@@ -202,6 +262,8 @@ def initialize_authenticated_frames(token):
 
     # Recreate authenticated frames with the new token
     frames["create_shop"] = create_shop_frame(root, switch_frame, API_URL, token)
+    # For view_shop and view_product, we'll initialize them with None parameters, which will be
+    # replaced when switch_frame is called with actual shop/product IDs
     frames["view_shop"] = view_shop_frame(root, switch_frame, API_URL, token, None)
     frames["create_product"] = create_product_frame(root, switch_frame, API_URL, token)
     frames["edit_product"] = edit_product_frame(
@@ -220,6 +282,16 @@ def initialize_authenticated_frames(token):
     frames["user_details"] = user_details_frame(root, switch_frame, API_URL, token)
     frames["user_orders"] = user_orders_frame(root, switch_frame, API_URL, token)
     frames["user_payments"] = user_payments_frame(root, switch_frame, API_URL, token)
+    # Admin frames
+    frames["admin_dashboard"] = admin_dashboard_frame(
+        root, switch_frame, API_URL, token
+    )
+    frames["admin_user_management"] = admin_user_management_frame(
+        root, switch_frame, API_URL, token
+    )
+    frames["admin_shop_owner_management"] = admin_shop_owner_management_frame(
+        root, switch_frame, API_URL, token
+    )
 
     # Place all authenticated frames
     for key, frame in frames.items():
diff --git a/app/init.py b/app/init.py
new file mode 100644
index 0000000000000000000000000000000000000000..3a3ba782a4c3ce80de2b592e45e347b11e9e2421
--- /dev/null
+++ b/app/init.py
@@ -0,0 +1,23 @@
+import os
+import sys
+import subprocess
+
+# Add the current directory to the path
+sys.path.append(os.path.dirname(os.path.abspath(__file__)))
+
+# Import admin initialization
+from backend.scripts.admin_init import init_admin
+
+
+def main():
+    """Main initialization function"""
+    print("Running initialization scripts...")
+
+    # Initialize admin user
+    init_admin()
+
+    print("Initialization complete!")
+
+
+if __name__ == "__main__":
+    main()
diff --git a/app/tests/test_search.py b/app/tests/test_search.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/requirements.txt b/requirements.txt
index 1c5bb150f1acbbb5b29d84ddfede66a9ed8b7204..8bce77cb9555277ac11381eadb381a2ddc28e46e 100644
Binary files a/requirements.txt and b/requirements.txt differ
diff --git a/run_app.py b/run_app.py
index 523ca5b5dfc9c244f2bc780dcd31179b840aaaa0..e6c697f2d1706070b8f3f9589ce4c8c094618b13 100644
--- a/run_app.py
+++ b/run_app.py
@@ -2,6 +2,7 @@ import threading
 import uvicorn
 from app.backend.main import app  # Your FastAPI app
 import os
+from app.backend.scripts.admin_init import init_admin
 
 
 def run_fastapi():
@@ -13,6 +14,11 @@ def start_tkinter_app():
 
 
 if __name__ == "__main__":
+    # Initialize admin user
+    print("Initializing admin user...")
+    init_admin()
+    print("Admin initialization complete!")
+
     # Start FastAPI in a separate thread
     fastapi_thread = threading.Thread(target=run_fastapi, daemon=True)
     fastapi_thread.start()