in a time where speed and convenience dominate the shopping experience, I decided to build something different: Chicken Realtor, a quick-commerce web platform dedicated to selling fresh chicken meats online. This wasn’t just another eCommerce site — it’s a streamlined solution that connects buyers and sellers instantly using WhatsApp, while giving admins full control of products and orders through a custom dashboard.
In this blog post, I’ll walk you through how I planned, built, and deployed this smart poultry sales system.
💡 The Idea Behind Chicken Realtor
Many local meat businesses still rely on offline methods: phone calls, walk-ins, or inconsistent third-party apps. But what if they had a system that:
- Showed all available chicken products in a beautiful layout
- Let customers add items to a cart and quickly check out
- Used WhatsApp to finalize orders (no need for complex payment gateways)
- Gave the admin a full dashboard to manage inventory and view orders
That’s exactly what Chicken Realtor solves.
🔧 Tech Stack Used
I chose a tech stack that’s lightweight but powerful:
- Frontend: HTML, CSS (Tailwind CSS), JavaScript
- Backend: PHP with MySQL for database interactions
- Integration: WhatsApp Checkout via
wa.me
API - Hosting: cPanel + Shared Hosting for quick deployment
Frontend Features
- Product Categories: Boneless, Drumsticks, Wings, Full Chicken
- Dynamic Cart System: Users can increase/decrease quantity, see real-time updates
- Checkout via WhatsApp: Once ready, a pre-filled message is sent with product list + quantity + total + user info
- Responsive UI: Designed mobile-first using TailwindCSS
Backend & Admin Panel Features
- Admin Login: Secured with session-based auth
- Product Management: Add/edit/delete chicken items with image upload
- Order Tracker: View past orders placed via WhatsApp (stored in DB)
- Status Control: Update order status (Pending, Completed, Cancelled)
- CSV Export: Downloadable order report
Why WhatsApp Checkout?
- No payment gateway needed (less friction for the user)
- Direct communication between seller and buyer
- Familiar UX: Customers already use WhatsApp; no new app required
SEO & Performance Considerations
- Optimized image loading using
loading="lazy"
- Structured content with proper
H1
,H2
, andmeta
tags - Minimal JS for faster load
- Canonical tags and alt tags for accessibility
Index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Chicken Realtor - Home</title>
<link rel="preconnect" href="https://fonts.gstatic.com/" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?display=swap&family=Noto+Sans:wght@400;500;700;900&family=Space+Grotesk:wght@400;500;700">
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
<style>
/* Custom styles for the cart bubble and toast */
.cart-bubble {
position: absolute;
top: -5px;
right: -10px;
background-color: #f37a24;
color: white;
border-radius: 50%;
width: 20px;
height: 20px;
font-size: 12px;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
}
#toast {
position: fixed;
bottom: 80px;
left: 50%;
transform: translateX(-50%);
background-color: #1c130d;
color: white;
padding: 10px 20px;
border-radius: 8px;
z-index: 1000;
transition: opacity 0.5s;
}
</style>
</head>
<body class="bg-[#fcfaf8]" style="font-family: 'Space Grotesk', 'Noto Sans', sans-serif;">
<div class="relative flex size-full min-h-screen flex-col justify-between group/design-root overflow-x-hidden">
<!-- Main Content -->
<div>
<!-- Header -->
<div class="flex items-center bg-[#fcfaf8] p-4 pb-2 justify-between sticky top-0 z-10">
<div class="w-12"></div> <!-- Spacer -->
<h1 class="text-[#1c130d] text-lg font-bold leading-tight tracking-[-0.015em] flex-1 text-center">Chicken Realtor</h1>
<div class="flex w-12 items-center justify-end">
<a href="cart.html" id="cart-icon" class="relative flex max-w-[480px] cursor-pointer items-center justify-center overflow-hidden rounded-lg h-12 bg-transparent text-[#1c130d] gap-2 text-base font-bold leading-normal tracking-[0.015em] min-w-0 p-0">
<div class="text-[#1c130d]">
<svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" fill="currentColor" viewBox="0 0 256 256"><path d="M222.14,58.87A8,8,0,0,0,216,56H54.68L49.79,29.14A16,16,0,0,0,34.05,16H16a8,8,0,0,0,0,16h18L59.56,172.29a24,24,0,0,0,5.33,11.27,28,28,0,1,0,44.4,8.44h45.42A27.75,27.75,0,0,0,152,204a28,28,0,1,0,28-28H83.17a8,8,0,0,1-7.87-6.57L72.13,152h116a24,24,0,0,0,23.61-19.71l12.16-66.86A8,8,0,0,0,222.14,58.87ZM96,204a12,12,0,1,1-12-12A12,12,0,0,1,96,204Zm96,0a12,12,0,1,1-12-12A12,12,0,0,1,192,204Zm4-74.57A8,8,0,0,1,188.1,136H69.22L57.59,72H206.41Z"></path></svg>
</div>
<span class="cart-bubble hidden">0</span>
</a>
</div>
</div>
<!-- Search -->
<div class="px-4 py-3">
<label class="flex flex-col min-w-40 h-12 w-full">
<div class="flex w-full flex-1 items-stretch rounded-lg h-full">
<div class="text-[#9c6c49] flex border-none bg-[#f4ece7] items-center justify-center pl-4 rounded-l-lg border-r-0">
<svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" fill="currentColor" viewBox="0 0 256 256"><path d="M229.66,218.34l-50.07-50.06a88.11,88.11,0,1,0-11.31,11.31l50.06,50.07a8,8,0,0,0,11.32-11.32ZM40,112a72,72,0,1,1,72,72A72.08,72.08,0,0,1,40,112Z"></path></svg>
</div>
<input placeholder="Search for chicken" class="form-input flex w-full min-w-0 flex-1 resize-none overflow-hidden rounded-lg text-[#1c130d] focus:outline-0 focus:ring-0 border-none bg-[#f4ece7] focus:border-none h-full placeholder:text-[#9c6c49] px-4 rounded-l-none border-l-0 pl-2 text-base font-normal leading-normal" value="">
</div>
</label>
</div>
<!-- Categories -->
<div class="flex gap-3 p-3 overflow-x-auto">
<div class="flex h-8 shrink-0 items-center justify-center gap-x-2 rounded-lg bg-[#f4ece7] pl-4 pr-4"><p class="text-[#1c130d] text-sm font-medium leading-normal">Raw Chicken</p></div>
<div class="flex h-8 shrink-0 items-center justify-center gap-x-2 rounded-lg bg-[#f4ece7] pl-4 pr-4"><p class="text-[#1c130d] text-sm font-medium leading-normal">Marinated</p></div>
<div class="flex h-8 shrink-0 items-center justify-center gap-x-2 rounded-lg bg-[#f4ece7] pl-4 pr-4"><p class="text-[#1c130d] text-sm font-medium leading-normal">Chicken Parts</p></div>
</div>
<!-- Product List Container -->
<div id="product-list-container">
<!-- Products will be dynamically inserted here by script.js -->
</div>
</div>
<!-- Bottom Navigation -->
<div class="sticky bottom-0">
<div class="flex gap-2 border-t border-[#f4ece7] bg-[#fcfaf8] px-4 pb-3 pt-2">
<a class="flex flex-1 flex-col items-center justify-end gap-1 rounded-full text-[#1c130d]" href="index.html">
<div class="text-[#1c130d] flex h-8 items-center justify-center"><svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" fill="currentColor" viewBox="0 0 256 256"><path d="M224,115.55V208a16,16,0,0,1-16,16H168a16,16,0,0,1-16-16V168a8,8,0,0,0-8-8H112a8,8,0,0,0-8,8v40a16,16,0,0,1-16,16H48a16,16,0,0,1-16-16V115.55a16,16,0,0,1,5.17-11.78l80-75.48.11-.11a16,16,0,0,1,21.53,0,1.14,1.14,0,0,0,.11.11l80,75.48A16,16,0,0,1,224,115.55Z"></path></svg></div>
<p class="text-[#1c130d] text-xs font-medium leading-normal tracking-[0.015em]">Home</p>
</a>
<a class="flex flex-1 flex-col items-center justify-end gap-1 text-[#9c6c49]" href="#">
<div class="text-[#9c6c49] flex h-8 items-center justify-center"><svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" fill="currentColor" viewBox="0 0 256 256"><path d="M80,64a8,8,0,0,1,8-8H216a8,8,0,0,1,0,16H88A8,8,0,0,1,80,64Zm136,56H88a8,8,0,0,0,0,16H216a8,8,0,0,0,0-16Zm0,64H88a8,8,0,0,0,0,16H216a8,8,0,0,0,0-16ZM44,52A12,12,0,1,0,56,64,12,12,0,0,0,44,52Zm0,64a12,12,0,1,0,12,12A12,12,0,0,0,44,116Zm0,64a12,12,0,1,0,12,12A12,12,0,0,0,44,180Z"></path></svg></div>
<p class="text-[#9c6c49] text-xs font-medium leading-normal tracking-[0.015em]">Categories</p>
</a>
<a class="flex flex-1 flex-col items-center justify-end gap-1 text-[#9c6c49]" href="cart.html">
<div class="text-[#9c6c49] flex h-8 items-center justify-center"><svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" fill="currentColor" viewBox="0 0 256 256"><path d="M222.14,58.87A8,8,0,0,0,216,56H54.68L49.79,29.14A16,16,0,0,0,34.05,16H16a8,8,0,0,0,0,16h18L59.56,172.29a24,24,0,0,0,5.33,11.27,28,28,0,1,0,44.4,8.44h45.42A27.75,27.75,0,0,0,152,204a28,28,0,1,0,28-28H83.17a8,8,0,0,1-7.87-6.57L72.13,152h116a24,24,0,0,0,23.61-19.71l12.16-66.86A8,8,0,0,0,222.14,58.87ZM96,204a12,12,0,1,1-12-12A12,12,0,0,1,96,204Zm96,0a12,12,0,1,1-12-12A12,12,0,0,1,192,204Zm4-74.57A8,8,0,0,1,188.1,136H69.22L57.59,72H206.41Z"></path></svg></div>
<p class="text-[#9c6c49] text-xs font-medium leading-normal tracking-[0.015em]">Cart</p>
</a>
<a class="flex flex-1 flex-col items-center justify-end gap-1 text-[#9c6c49]" href="#">
<div class="text-[#9c6c49] flex h-8 items-center justify-center"><svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" fill="currentColor" viewBox="0 0 256 256"><path d="M230.92,212c-15.23-26.33-38.7-45.21-66.09-54.16a72,72,0,1,0-73.66,0C63.78,166.78,40.31,185.66,25.08,212a8,8,0,1,0,13.85,8c18.84-32.56,52.14-52,89.07-52s70.23,19.44,89.07,52a8,8,0,1,0,13.85-8ZM72,96a56,56,0,1,1,56,56A56.06,56.06,0,0,1,72,96Z"></path></svg></div>
<p class="text-[#9c6c49] text-xs font-medium leading-normal tracking-[0.015em]">Profile</p>
</a>
</div>
<div class="h-5 bg-[#fcfaf8]"></div>
</div>
</div>
<!-- Toast Notification -->
<div id="toast" class="hidden"></div>
<script src="script.js"></script>
</body>
</html>
product-detail.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Product Details</title>
<link rel="preconnect" href="https://fonts.gstatic.com/" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?display=swap&family=Noto+Sans:wght@400;500;700;900&family=Space+Grotesk:wght@400;500;700">
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
<style>
.cart-bubble {
position: absolute;
top: -5px;
right: -10px;
background-color: #f37a24;
color: white;
border-radius: 50%;
width: 20px;
height: 20px;
font-size: 12px;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
}
#toast {
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
background-color: #1c130d;
color: white;
padding: 10px 20px;
border-radius: 8px;
z-index: 1000;
transition: opacity 0.5s;
}
</style>
</head>
<body class="bg-[#fcfaf8]" style="font-family: 'Space Grotesk', 'Noto Sans', sans-serif;">
<div class="relative flex size-full min-h-screen flex-col justify-between group/design-root overflow-x-hidden">
<!-- Main Content -->
<div>
<!-- Header -->
<div class="flex items-center bg-[#fcfaf8] p-4 pb-2 justify-between">
<a href="index.html" class="text-[#1c130d] flex size-12 shrink-0 items-center">
<svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" fill="currentColor" viewBox="0 0 256 256"><path d="M224,128a8,8,0,0,1-8,8H59.31l58.35,58.34a8,8,0,0,1-11.32,11.32l-72-72a8,8,0,0,1,0-11.32l72-72a8,8,0,0,1,11.32,11.32L59.31,120H216A8,8,0,0,1,224,128Z"></path></svg>
</a>
<h1 class="text-[#1c130d] text-lg font-bold leading-tight tracking-[-0.015em] flex-1 text-center">Product Details</h1>
<div class="flex w-12 items-center justify-end">
<a href="cart.html" id="cart-icon" class="relative flex max-w-[480px] cursor-pointer items-center justify-center overflow-hidden rounded-lg h-12 bg-transparent text-[#1c130d] gap-2 text-base font-bold leading-normal tracking-[0.015em] min-w-0 p-0">
<div class="text-[#1c130d]">
<svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" fill="currentColor" viewBox="0 0 256 256"><path d="M222.14,58.87A8,8,0,0,0,216,56H54.68L49.79,29.14A16,16,0,0,0,34.05,16H16a8,8,0,0,0,0,16h18L59.56,172.29a24,24,0,0,0,5.33,11.27,28,28,0,1,0,44.4,8.44h45.42A27.75,27.75,0,0,0,152,204a28,28,0,1,0,28-28H83.17a8,8,0,0,1-7.87-6.57L72.13,152h116a24,24,0,0,0,23.61-19.71l12.16-66.86A8,8,0,0,0,222.14,58.87ZM96,204a12,12,0,1,1-12-12A12,12,0,0,1,96,204Zm96,0a12,12,0,1,1-12-12A12,12,0,0,1,192,204Zm4-74.57A8,8,0,0,1,188.1,136H69.22L57.59,72H206.41Z"></path></svg>
</div>
<span class="cart-bubble hidden">0</span>
</a>
</div>
</div>
<!-- Product Detail Container -->
<div id="product-detail-container" class="p-4">
<!-- Product details will be dynamically inserted here -->
</div>
</div>
</div>
<!-- Toast Notification -->
<div id="toast" class="hidden"></div>
<script src="script.js"></script>
</body>
</html>
cart.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Your Cart</title>
<link rel="preconnect" href="https://fonts.gstatic.com/" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?display=swap&family=Noto+Sans:wght@400;500;700;900&family=Space+Grotesk:wght@400;500;700">
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
<style>
/* Style for quantity buttons */
.quantity-btn {
background-color: #f4ece7;
color: #1c130d;
border-radius: 50%;
width: 24px;
height: 24px;
font-weight: bold;
border: 1px solid #e0d5cb;
}
</style>
</head>
<body class="bg-[#fcfaf8]" style="font-family: 'Space Grotesk', 'Noto Sans', sans-serif;">
<div class="relative flex size-full min-h-screen flex-col bg-[#fcfaf8] justify-between group/design-root overflow-x-hidden">
<!-- Main Content -->
<div>
<!-- Header -->
<div class="flex items-center bg-[#fcfaf8] p-4 pb-2 justify-between">
<a href="index.html" class="text-[#1c130d] flex size-12 shrink-0 items-center -ml-4">
<svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" fill="currentColor" viewBox="0 0 256 256"><path d="M224,128a8,8,0,0,1-8,8H59.31l58.35,58.34a8,8,0,0,1-11.32,11.32l-72-72a8,8,0,0,1,0-11.32l72-72a8,8,0,0,1,11.32,11.32L59.31,120H216A8,8,0,0,1,224,128Z"></path></svg>
</a>
<h1 class="text-[#1c130d] text-lg font-bold leading-tight tracking-[-0.015em] flex-1 text-center pr-8">Cart</h1>
</div>
<!-- Cart Items Container -->
<div id="cart-items-container">
<!-- Cart items will be dynamically inserted here -->
</div>
<!-- Totals Section -->
<div class="px-4 pt-4">
<div class="flex items-center gap-4 bg-[#fcfaf8] min-h-14 justify-between">
<p class="text-[#1c130d] text-base font-normal leading-normal flex-1 truncate">Subtotal</p>
<div class="shrink-0"><p id="subtotal-amount" class="text-[#1c130d] text-base font-normal leading-normal">$0.00</p></div>
</div>
<div class="flex items-center gap-4 bg-[#fcfaf8] min-h-14 justify-between">
<p class="text-[#1c130d] text-base font-normal leading-normal flex-1 truncate">Shipping</p>
<div class="shrink-0"><p id="shipping-amount" class="text-[#1c130d] text-base font-normal leading-normal">$0.00</p></div>
</div>
<div class="flex items-center gap-4 bg-[#fcfaf8] min-h-14 justify-between border-t border-[#f4ece7] pt-2">
<p class="text-[#1c130d] text-base font-bold leading-normal flex-1 truncate">Total</p>
<div class="shrink-0"><p id="total-amount" class="text-[#1c130d] text-base font-bold leading-normal">$0.00</p></div>
</div>
</div>
</div>
<!-- Checkout Button -->
<div class="p-4">
<a href="checkout.html" class="flex min-w-[84px] max-w-[480px] cursor-pointer items-center justify-center overflow-hidden rounded-lg h-12 px-5 flex-1 bg-[#f37a24] text-white text-base font-bold leading-normal tracking-[0.015em]">
<span class="truncate">Proceed to Checkout</span>
</a>
<div class="h-5 bg-[#fcfaf8]"></div>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
checkout.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Checkout</title>
<link rel="preconnect" href="https://fonts.gstatic.com/" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?display=swap&family=Noto+Sans:wght@400;500;700;900&family=Space+Grotesk:wght@400;500;700">
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
</head>
<body class="bg-[#fcfaf8]" style="font-family: 'Space Grotesk', 'Noto Sans', sans-serif;">
<div class="relative flex size-full min-h-screen flex-col bg-[#fcfaf8] justify-between group/design-root overflow-x-hidden">
<!-- Main Content -->
<div>
<!-- Header -->
<div class="flex items-center bg-[#fcfaf8] p-4 pb-2 justify-between">
<a href="cart.html" class="text-[#1c130d] flex size-12 shrink-0 items-center -ml-4">
<svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" fill="currentColor" viewBox="0 0 256 256"><path d="M224,128a8,8,0,0,1-8,8H59.31l58.35,58.34a8,8,0,0,1-11.32,11.32l-72-72a8,8,0,0,1,0-11.32l72-72a8,8,0,0,1,11.32,11.32L59.31,120H216A8,8,0,0,1,224,128Z"></path></svg>
</a>
<h1 class="text-[#1c130d] text-lg font-bold leading-tight tracking-[-0.015em] flex-1 text-center pr-8">Checkout</h1>
</div>
<!-- Order Summary -->
<h2 class="text-[#1c130d] text-lg font-bold leading-tight tracking-[-0.015em] px-4 pb-2 pt-4">Order Summary</h2>
<div id="checkout-summary-container">
<!-- Checkout summary will be dynamically inserted here -->
</div>
<!-- Delivery Details -->
<h2 class="text-[#1c130d] text-lg font-bold leading-tight tracking-[-0.015em] px-4 pb-2 pt-4">Delivery Details</h2>
<div class="px-4 space-y-4">
<label class="flex flex-col">
<p class="text-[#1c130d] text-base font-medium leading-normal pb-2">Name</p>
<input id="name" placeholder="Enter your full name" class="form-input flex w-full min-w-0 flex-1 resize-none overflow-hidden rounded-lg text-[#1c130d] focus:outline-0 focus:ring-2 focus:ring-[#f37a24] border-none bg-[#f4ece7] h-14 placeholder:text-[#9c6c49] p-4 text-base font-normal leading-normal">
</label>
<label class="flex flex-col">
<p class="text-[#1c130d] text-base font-medium leading-normal pb-2">Address</p>
<input id="address" placeholder="Enter your full address" class="form-input flex w-full min-w-0 flex-1 resize-none overflow-hidden rounded-lg text-[#1c130d] focus:outline-0 focus:ring-2 focus:ring-[#f37a24] border-none bg-[#f4ece7] h-14 placeholder:text-[#9c6c49] p-4 text-base font-normal leading-normal">
</label>
<label class="flex flex-col">
<p class="text-[#1c130d] text-base font-medium leading-normal pb-2">City</p>
<input id="city" placeholder="Enter your city" class="form-input flex w-full min-w-0 flex-1 resize-none overflow-hidden rounded-lg text-[#1c130d] focus:outline-0 focus:ring-2 focus:ring-[#f37a24] border-none bg-[#f4ece7] h-14 placeholder:text-[#9c6c49] p-4 text-base font-normal leading-normal">
</label>
<label class="flex flex-col">
<p class="text-[#1c130d] text-base font-medium leading-normal pb-2">Zip Code</p>
<input id="zip" type="tel" placeholder="Enter your zip code" class="form-input flex w-full min-w-0 flex-1 resize-none overflow-hidden rounded-lg text-[#1c130d] focus:outline-0 focus:ring-2 focus:ring-[#f37a24] border-none bg-[#f4ece7] h-14 placeholder:text-[#9c6c49] p-4 text-base font-normal leading-normal">
</label>
</div>
<!-- Totals Section -->
<h2 class="text-[#1c130d] text-lg font-bold leading-tight tracking-[-0.015em] px-4 pb-2 pt-4">Total</h2>
<div class="px-4">
<div class="flex items-center gap-4 bg-[#fcfaf8] min-h-14 justify-between">
<p class="text-[#1c130d] text-base font-normal leading-normal flex-1 truncate">Subtotal</p>
<div class="shrink-0"><p id="subtotal-amount" class="text-[#1c130d] text-base font-normal leading-normal">$0.00</p></div>
</div>
<div class="flex items-center gap-4 bg-[#fcfaf8] min-h-14 justify-between">
<p class="text-[#1c130d] text-base font-normal leading-normal flex-1 truncate">Shipping</p>
<div class="shrink-0"><p id="shipping-amount" class="text-[#1c130d] text-base font-normal leading-normal">$0.00</p></div>
</div>
<div class="flex items-center gap-4 bg-[#fcfaf8] min-h-14 justify-between border-t border-[#f4ece7] pt-2">
<p class="text-[#1c130d] text-base font-bold leading-normal flex-1 truncate">Total</p>
<div class="shrink-0"><p id="total-amount" class="text-[#1c130d] text-base font-bold leading-normal">$0.00</p></div>
</div>
</div>
</div>
<!-- Checkout Button -->
<div class="p-4">
<button id="whatsapp-checkout-btn" class="flex min-w-[84px] max-w-[480px] cursor-pointer items-center justify-center overflow-hidden rounded-lg h-12 px-5 flex-1 bg-[#25D366] text-white text-base font-bold leading-normal tracking-[0.015em]">
<span class="truncate">Checkout on WhatsApp</span>
</button>
<div class="h-5 bg-[#fcfaf8]"></div>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
script.js
// This script will be linked to all your HTML pages.
// It uses localStorage to remember the cart contents even if the user closes the browser.
document.addEventListener('DOMContentLoaded', () => {
// --- DATA ---
// Product data. In a real application, this would come from a database.
const products = [
{
id: 1,
name: 'Whole Chicken',
category: 'Fresh',
price: 5.99,
unit: 'kg',
image: 'https://lh3.googleusercontent.com/aida-public/AB6AXuAXVUcp24HVw4TEvMJ6lG2nECTa3_9a_rXHbo0vMss5R_V1o2q9AYyEM6kw81UjduMPE21TVZ1mLq3-G3SQTN_qNsUTAXQF297on6v4j1CJIJuJ-p9bCEHhiSIu-6B8poEOPVi2sOOVTXG81sI1IgWM0ZR2_WLKXpwHvNc-fMbAnjk6J6v2ifXIU2KVbJ5dEW30HPHOUJ6yrhqlnme1JCjaic0oq35XARf8a9uoApu8xTfoBuL4HvHmnKtI7VUdOvaT1MzwfIWYTCGu'
},
{
id: 2,
name: 'Chicken Breast',
category: 'Fresh',
price: 7.99,
unit: 'kg',
image: 'https://lh3.googleusercontent.com/aida-public/AB6AXuDFU-pZshccrj9ripa2XwD0xH0l3eQTPz36QWo3VxdGNzj-KIzMScJMl-wCA9ldlx_CrZSK170Vkt7YkzhjZgFWtLgT_qGo2Q6inYQjB2oNl7PhCGP1ZbQHbRdVZ6brRZ68zaPw04Ay9e8Zj6NI6BAEVpNN1BCltVKnnJ3VNw61IlShCkFvJGjZiYG-HQ9aVlTZDodb6k-d6olYNSDC5ReSHvl2jGdzyYudi7h2RyQyTDKIzwOHW8Dsx4-XTH5j8CvUm0NPqrFYhKZK'
},
{
id: 3,
name: 'Lemon Herb Chicken',
category: 'Marinated',
price: 6.49,
unit: 'kg',
image: 'https://lh3.googleusercontent.com/aida-public/AB6AXuCSDATvYXg_oSJIpKdGhfg0dHKbLDyPanT4kjigDMBDYihPl0A-oeahskOkhrsz_Pk9ovYLb9avh1e6kI5FvYKGFpFjSFMeW6xw4B0RiZF8QqRLoH6txqQSngpfvRuHzZOX4hbmy2F11DYvAeGhfwTpqUpm6bZQCSQ2AaaSZhHe_4OWsuzGXP3lEqN2AO_ISfi7E5C8NNZwAC66i1vPKTU9nUtJJdBdFlsJn0WD94T69YcvNXJfWeSihEoaECs5TBcJwSgPnfQ-ehEF'
},
{
id: 4,
name: 'Chicken Thighs',
category: 'Fresh',
price: 4.99,
unit: 'kg',
image: 'https://lh3.googleusercontent.com/aida-public/AB6AXuChSMYS1oMTW2pku_6Fra6QmNSRHFslLM3wAOhBsCinV3uwAlWDrqo8wnq8qqxTcptvA6QzKqyvVvqyQoHZxIKw7yfuC7CzFCDsjznOfeqh7mkuBYNJA-kNovRahyzSmlLHn0Cudh1HjOZ7WWCyEYF58InZDzcMZnA5n6ADqJRQt_3xM832DK0kph5aM6CKZr4lvPFuvwbRBqyhhd0g2lnH0BvlSjUt6HIYRbDbVgkuTYy93uQtoMyAE6M7Ogx7vm84cjG5CwFjyvVi'
},
{
id: 5,
name: 'Spicy Chicken Wings',
category: 'Marinated',
price: 5.49,
unit: 'kg',
image: 'https://lh3.googleusercontent.com/aida-public/AB6AXuB93QuJ-e6eWFCCfqcam4FHtYRu9wWheGf8lHhJrUA8bUE8_AMDRfuZOBkvhDglY2Vrp4UycC2MlqA0P5LXdUo1fEl7RCgFc5yTfN7Vb2THOVBZC5bNG73Z2pgDl3EQswz8BkrP_zocIctfvyHFowJ8CtJWGhyv1jrh2BO7WYlwvdVdFuN4v0xhb5uTWn7beBT84LT6U67QsuCitI1Pzv3j-FJR_H8oX4ZtXb6rNPaDBHyF2FKVSz376F8c7uuUU2_rjxU2s1zHK4gg'
},
{
id: 6,
name: 'Chicken Drumsticks',
category: 'Fresh',
price: 3.99,
unit: 'kg',
image: 'https://lh3.googleusercontent.com/aida-public/AB6AXuAt59suoZMhFd1fU1HI61nsdLG3Tjb5L4C57p8oCJlrwGoeWsXhBZ2utCx4YYEtDRBPDgxAbnI3MXT9E8BNOEwi_aSjzfXQrRb70rU3uR5Gn3FfmZFY5A0dzrMQ5TpYyQXbhMzsvZ4XCltLu-eMCHGg8CYqkiN0g_-VmOM2tm75go2NdAw9amiCuh4sA6QgX79Vf3LOK8AYV830dzy31b-eIKq7rB5SqN7b-yA_yfjFKz80JM64d2iGnPlVnpKpAG8XT1RA6Q8etm4F'
}
];
// --- CART LOGIC ---
// Function to get the cart from localStorage
const getCart = () => {
const cart = localStorage.getItem('chickenShopCart');
return cart ? JSON.parse(cart) : [];
};
// Function to save the cart to localStorage
const saveCart = (cart) => {
localStorage.setItem('chickenShopCart', JSON.stringify(cart));
updateCartIcon();
};
// Function to add an item to the cart
const addToCart = (productId) => {
const cart = getCart();
const product = products.find(p => p.id === productId);
if (!product) return;
const existingItem = cart.find(item => item.id === productId);
if (existingItem) {
existingItem.quantity++;
} else {
cart.push({ id: productId, quantity: 1 });
}
saveCart(cart);
// Show a confirmation message
const toast = document.getElementById('toast');
if (toast) {
toast.textContent = `${product.name} added to cart!`;
toast.classList.remove('hidden');
setTimeout(() => {
toast.classList.add('hidden');
}, 2000);
}
};
// Function to update item quantity in cart
const updateQuantity = (productId, newQuantity) => {
let cart = getCart();
if (newQuantity <= 0) {
cart = cart.filter(item => item.id !== productId);
} else {
const itemInCart = cart.find(item => item.id === productId);
if (itemInCart) {
itemInCart.quantity = newQuantity;
}
}
saveCart(cart);
// Re-render the page if we are on cart or checkout
if (document.getElementById('cart-items-container') || document.getElementById('checkout-summary-container')) {
location.reload();
}
};
// Function to get total item count for the cart icon
const getCartItemCount = () => {
return getCart().reduce((total, item) => total + item.quantity, 0);
};
// Function to update the cart icon bubble
const updateCartIcon = () => {
const cartIcon = document.getElementById('cart-icon');
if (cartIcon) {
const itemCount = getCartItemCount();
const bubble = cartIcon.querySelector('.cart-bubble');
if (bubble) {
if (itemCount > 0) {
bubble.textContent = itemCount;
bubble.classList.remove('hidden');
} else {
bubble.classList.add('hidden');
}
}
}
};
// --- PAGE-SPECIFIC RENDERING ---
// Render product list on index.html
const renderProducts = () => {
const container = document.getElementById('product-list-container');
if (!container) return;
container.innerHTML = ''; // Clear existing content
products.forEach(product => {
const productCard = document.createElement('div');
productCard.className = 'p-4';
productCard.innerHTML = `
<div class="flex items-stretch justify-between gap-4 rounded-lg cursor-pointer product-card" data-id="${product.id}">
<div class="flex flex-[2_2_0px] flex-col gap-4">
<div class="flex flex-col gap-1">
<p class="text-[#9c6c49] text-sm font-normal leading-normal">${product.category}</p>
<p class="text-[#1c130d] text-base font-bold leading-tight">${product.name}</p>
<p class="text-[#9c6c49] text-sm font-normal leading-normal">$${product.price.toFixed(2)} / ${product.unit}</p>
</div>
<button data-id="${product.id}" class="add-to-cart-btn flex min-w-[84px] max-w-[480px] cursor-pointer items-center justify-center overflow-hidden rounded-lg h-8 px-4 flex-row-reverse bg-[#f4ece7] text-[#1c130d] text-sm font-medium leading-normal w-fit">
<span class="truncate">Add to Cart</span>
</button>
</div>
<div class="w-full bg-center bg-no-repeat aspect-video bg-cover rounded-lg flex-1" style="background-image: url('${product.image}');"></div>
</div>
`;
container.appendChild(productCard);
});
// Add event listeners after rendering
document.querySelectorAll('.add-to-cart-btn').forEach(button => {
button.addEventListener('click', (e) => {
e.stopPropagation(); // Prevent card click when button is clicked
const productId = parseInt(e.currentTarget.dataset.id);
addToCart(productId);
});
});
document.querySelectorAll('.product-card').forEach(card => {
card.addEventListener('click', (e) => {
const productId = parseInt(e.currentTarget.dataset.id);
window.location.href = `product-detail.html?id=${productId}`;
});
});
};
// Render product details on product-detail.html
const renderProductDetails = () => {
const container = document.getElementById('product-detail-container');
if (!container) return;
const urlParams = new URLSearchParams(window.location.search);
const productId = parseInt(urlParams.get('id'));
const product = products.find(p => p.id === productId);
if (!product) {
container.innerHTML = '<p class="text-center text-[#1c130d]">Product not found.</p>';
return;
}
container.innerHTML = `
<div class="w-full h-64 bg-center bg-no-repeat bg-cover rounded-lg" style="background-image: url('${product.image}');"></div>
<div class="p-4">
<p class="text-[#9c6c49] text-sm font-normal leading-normal">${product.category}</p>
<h2 class="text-[#1c130d] text-2xl font-bold leading-tight mt-1">${product.name}</h2>
<p class="text-xl text-[#f37a24] font-bold mt-2">$${product.price.toFixed(2)} / ${product.unit}</p>
<p class="text-[#9c6c49] mt-4">This is a placeholder description for our high-quality, farm-fresh ${product.name}. Perfect for any meal, guaranteed to be delicious and tender.</p>
<button data-id="${product.id}" class="add-to-cart-btn flex w-full mt-6 min-w-[84px] max-w-[480px] cursor-pointer items-center justify-center overflow-hidden rounded-lg h-12 px-5 bg-[#f37a24] text-white text-base font-bold leading-normal tracking-[0.015em]">
<span class="truncate">Add to Cart</span>
</button>
</div>
`;
// Add event listener
document.querySelector('.add-to-cart-btn').addEventListener('click', (e) => {
const productId = parseInt(e.currentTarget.dataset.id);
addToCart(productId);
});
};
// Render items in cart.html and checkout.html
const renderCartItems = (containerId, isCheckout = false) => {
const container = document.getElementById(containerId);
if (!container) return;
const cart = getCart();
container.innerHTML = ''; // Clear
let subtotal = 0;
if (cart.length === 0) {
container.innerHTML = '<p class="text-center text-[#9c6c49] p-4">Your cart is empty.</p>';
} else {
cart.forEach(item => {
const product = products.find(p => p.id === item.id);
if (product) {
subtotal += product.price * item.quantity;
const itemElement = document.createElement('div');
itemElement.className = 'flex items-center gap-4 bg-[#fcfaf8] px-4 min-h-[72px] py-2 justify-between';
itemElement.innerHTML = `
<div class="flex items-center gap-4 flex-1">
${!isCheckout ? `<div class="bg-center bg-no-repeat aspect-square bg-cover rounded-lg size-14" style="background-image: url('${product.image}');"></div>` : ''}
<div class="flex flex-col justify-center">
<p class="text-[#1c130d] text-base font-medium leading-normal line-clamp-1">${product.name}</p>
${isCheckout
? `<p class="text-[#9c6c49] text-sm font-normal leading-normal line-clamp-2">${item.quantity} x $${product.price.toFixed(2)}</p>`
: `<div class="flex items-center gap-2 mt-1">
<button class="quantity-btn" data-id="${product.id}" data-change="-1">-</button>
<span class="text-[#1c130d]">${item.quantity}</span>
<button class="quantity-btn" data-id="${product.id}" data-change="1">+</button>
</div>`
}
</div>
</div>
<div class="shrink-0"><p class="text-[#1c130d] text-base font-normal leading-normal">$${(product.price * item.quantity).toFixed(2)}</p></div>
`;
container.appendChild(itemElement);
}
});
}
// Update totals
const shipping = cart.length > 0 ? 5.00 : 0.00;
const total = subtotal + shipping;
document.getElementById('subtotal-amount').textContent = `$${subtotal.toFixed(2)}`;
document.getElementById('shipping-amount').textContent = `$${shipping.toFixed(2)}`;
document.getElementById('total-amount').textContent = `$${total.toFixed(2)}`;
// Add event listeners for quantity buttons if on cart page
if (!isCheckout) {
document.querySelectorAll('.quantity-btn').forEach(button => {
button.addEventListener('click', e => {
const productId = parseInt(e.currentTarget.dataset.id);
const change = parseInt(e.currentTarget.dataset.change);
const cart = getCart();
const item = cart.find(i => i.id === productId);
if (item) {
updateQuantity(productId, item.quantity + change);
}
});
});
}
};
// --- WHATSAPP CHECKOUT ---
const handleWhatsAppCheckout = () => {
const checkoutButton = document.getElementById('whatsapp-checkout-btn');
if (!checkoutButton) return;
checkoutButton.addEventListener('click', () => {
const name = document.getElementById('name').value.trim();
const address = document.getElementById('address').value.trim();
const city = document.getElementById('city').value.trim();
const zip = document.getElementById('zip').value.trim();
if (!name || !address || !city || !zip) {
alert('Please fill in all delivery details.');
return;
}
const cart = getCart();
if (cart.length === 0) {
alert('Your cart is empty.');
return;
}
let message = "Hello! I'd like to place an order:\n\n";
let subtotal = 0;
cart.forEach(item => {
const product = products.find(p => p.id === item.id);
if (product) {
const itemTotal = product.price * item.quantity;
subtotal += itemTotal;
message += `*${product.name}*\n`;
message += ` - Quantity: ${item.quantity} ${product.unit}\n`;
message += ` - Price: $${itemTotal.toFixed(2)}\n\n`;
}
});
const shipping = 5.00;
const total = subtotal + shipping;
message += `*Subtotal:* $${subtotal.toFixed(2)}\n`;
message += `*Shipping:* $${shipping.toFixed(2)}\n`;
message += `*Total:* $${total.toFixed(2)}\n\n`;
message += "*Delivery Details:*\n";
message += `Name: ${name}\n`;
message += `Address: ${address}, ${city}, ${zip}\n\n`;
message += "Thank you!";
const phoneNumber = "917898004784"; // Country code + number
const whatsappUrl = `https://wa.me/${phoneNumber}?text=${encodeURIComponent(message)}`;
window.open(whatsappUrl, '_blank');
});
};
// --- INITIALIZATION ---
// Router to call the correct function based on the page
const page = window.location.pathname.split("/").pop();
if (page === 'index.html' || page === '') {
renderProducts();
}
if (page === 'product-detail.html') {
renderProductDetails();
}
if (page === 'cart.html') {
renderCartItems('cart-items-container', false);
}
if (page === 'checkout.html') {
renderCartItems('checkout-summary-container', true);
handleWhatsAppCheckout();
}
// Update cart icon on all pages
updateCartIcon();
});
Conclusion
Chicken Realtor is not just a project — it’s a template for how small meat sellers and butchers can modernize their business without relying on expensive platforms or third-party services. By blending eCommerce with WhatsApp, we unlocked instant communication and frictionless shopping.
I’m proud of how this turned out, and I hope more businesses adopt similar lightweight, powerful tools in the future.
Want to build something like this for your own niche? I’m available for freelance or hourly project work — rockzahmad@gmail.com . 🚀