Melanjutkan Proyek Website Marketplace Lokal untuk Warga RT
Proyek ini bertujuan untuk membuat sebuah marketplace lokal yang sederhana namun elegan, responsif untuk perangkat mobile, dan beroperasi di platform Blogger. Ini akan mencakup satu moodboard untuk identitas visual dan empat visual antarmuka pengguna untuk menunjukkan fungsionalitas utama seperti tampilan beranda, daftar produk, halaman detail produk, dan proses checkout.
Tentu, saya akan melanjutkan desain website marketplace lokal ini dengan berfokus pada implementasi di Blogger. Skrip ini akan dibuat seminimalis mungkin agar ringan dan mudah dipasang.
Berikut adalah skrip lengkap HTML, CSS, dan JavaScript yang bisa kamu pasang langsung di platform Blogger. Skrip ini mencakup struktur dasar, gaya, dan fungsionalitas inti yang responsif untuk perangkat seluler, dengan palet warna hijau muda dan kuning seperti yang kita diskusikan.
Penjelasan dan Fitur Utama Skrip:
- Struktur HTML (Blogger Post/Page):
- Menggunakan
divuntuk setiap bagian halaman (header, navigasi, konten utama, dll.). - Struktur yang sederhana agar mudah dimodifikasi di editor Blogger.
- Menggunakan
- CSS (Disisipkan di
<style>atau Template Blogger):- Responsif: Menggunakan media queries untuk menyesuaikan tampilan di layar HP.
- Palet Warna: Hijau muda (
#A2D9A2), Kuning Cerah (#FFD700), Putih Gading (#F8F8F8), Abu-abu Muda (#EEEEEE). - Tipografi: Menggunakan font sans-serif yang mudah dibaca.
- Elegan & Bersih: Desain minimalis dengan padding dan margin yang cukup.
- JavaScript (Disisipkan di
<script>):- Simulasi Data Produk: Karena Blogger bukan database, kita akan menggunakan array JavaScript untuk menyimpan data produk warung. Admin RT bisa mengedit array ini secara manual.
- Filter/Pencarian Sederhana: Fitur pencarian produk berdasarkan nama.
- Dinamis Menampilkan Produk: Produk akan dimuat secara dinamis ke halaman.
- Keranjang Belanja (Sederhana): Menggunakan
localStorageuntuk menyimpan item keranjang, sehingga tidak hilang saat halaman di-refresh (namun tidak akan bertahan jika browser ditutup atau cache dihapus). - Tombol Pesan (WhatsApp): Otomatis membuat link WhatsApp ke penjual.
- Proses Checkout (Simulasi): Mengarahkan ke link WhatsApp untuk konfirmasi pesanan.
- Navigasi: Menampilkan atau menyembunyikan bagian halaman yang berbeda.
Cara Pemasangan di Blogger:
- Login ke Blogger.
- Buat Halaman Baru: Masuk ke menu
Laman>Laman Baru. - Mode Tampilan HTML: Di editor laman, ganti mode dari
Tampilan MenuliskeTampilan HTML(biasanya ikon< >atau pilihan di sudut kiri atas). - Paste Skrip: Salin seluruh kode di bawah ini dan tempelkan di editor HTML tersebut.
- Perbarui/Publikasikan Laman: Beri judul laman, misalnya "Marketplace RT ", lalu Publikasikan.
- Tambahkan ke Menu Navigasi (Opsional): Jika ingin laman ini muncul di menu blog utama, pergi ke
Tata Letak>Gadget>Daftar Lamandan tambahkan laman "Marketplace RT " yang baru dibuat.
Skrip Lengkap (HTML, CSS, JavaScript)
<style>
/* --- RESET & GLOBAL STYLES --- */
body {
margin: 0;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: #F8F8F8; /* Putih Gading */
color: #333;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.container {
max-width: 100%;
margin: 0 auto;
padding: 0 10px;
}
a {
text-decoration: none;
color: #A2D9A2; /* Hijau Muda */
}
button {
cursor: pointer;
border: none;
padding: 10px 15px;
border-radius: 5px;
font-size: 1em;
transition: background-color 0.3s ease;
}
input[type="text"], input[type="number"], textarea {
width: 100%;
padding: 10px;
margin-bottom: 10px;
border: 1px solid #EEEEEE; /* Abu-abu Muda */
border-radius: 5px;
box-sizing: border-box;
}
/* --- HEADER & NAVIGATION --- */
.header {
background-color: #A2D9A2; /* Hijau Muda */
color: white;
padding: 15px 10px;
text-align: center;
position: sticky;
top: 0;
z-index: 1000;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
.header h1 {
margin: 0;
font-size: 1.5em;
font-weight: 600;
}
.bottom-nav {
display: flex;
justify-content: space-around;
align-items: center;
background-color: white;
padding: 10px 0;
position: fixed;
bottom: 0;
left: 0;
right: 0;
box-shadow: 0 -2px 5px rgba(0,0,0,0.1);
z-index: 1000;
}
.bottom-nav button {
background: none;
color: #777;
font-size: 0.8em;
display: flex;
flex-direction: column;
align-items: center;
padding: 5px;
}
.bottom-nav button.active {
color: #A2D9A2; /* Hijau Muda */
}
.bottom-nav button i {
font-size: 1.2em;
margin-bottom: 3px;
}
/* Search Bar */
.search-bar {
padding: 10px;
background-color: #F8F8F8; /* Putih Gading */
border-bottom: 1px solid #EEEEEE;
}
.search-bar input {
background-color: white;
border-radius: 20px;
padding: 8px 15px;
border: 1px solid #DDD;
}
/* --- BANNER --- */
.banner {
background-color: #FFD700; /* Kuning Cerah */
color: #333;
padding: 15px;
text-align: center;
margin-bottom: 15px;
border-radius: 8px;
font-weight: 500;
margin: 10px;
}
.banner p {
margin: 5px 0;
}
/* --- PRODUCT LISTING --- */
.product-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 15px;
padding: 15px 10px 80px 10px; /* Padding bawah untuk nav */
}
.product-card {
background-color: white;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 5px rgba(0,0,0,0.05);
text-align: left;
display: flex;
flex-direction: column;
}
.product-card img {
width: 100%;
height: 120px;
object-fit: cover;
display: block;
border-bottom: 1px solid #EEEEEE;
}
.product-card-info {
padding: 10px;
flex-grow: 1;
}
.product-card h3 {
margin: 0 0 5px 0;
font-size: 1.1em;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.product-card p.price {
font-weight: bold;
color: #333;
margin: 0 0 5px 0;
}
.product-card p.store {
font-size: 0.85em;
color: #666;
margin: 0 0 10px 0;
}
.product-card button {
background-color: #FFD700; /* Kuning Cerah */
color: #333;
width: 100%;
border-radius: 0 0 8px 8px; /* Sudut bawah saja */
padding: 8px;
font-weight: 500;
}
.product-card button:hover {
background-color: #FFC107;
}
/* --- PRODUCT DETAIL PAGE --- */
.product-detail-page {
padding: 15px 10px 80px 10px; /* Padding bawah untuk nav */
background-color: white;
min-height: calc(100vh - 120px); /* Adjust height */
}
.product-detail-page img {
width: 100%;
height: 250px;
object-fit: cover;
border-radius: 8px;
margin-bottom: 15px;
}
.product-detail-page h2 {
margin-top: 0;
font-size: 1.8em;
color: #333;
}
.product-detail-page p.price {
font-size: 1.4em;
font-weight: bold;
color: #A2D9A2; /* Hijau Muda */
margin-bottom: 10px;
}
.product-detail-page p.store-info {
font-size: 1em;
color: #666;
margin-bottom: 15px;
}
.product-detail-page p.description {
font-size: 0.95em;
line-height: 1.5;
color: #555;
margin-bottom: 20px;
}
.product-detail-actions {
display: flex;
gap: 10px;
margin-top: 20px;
}
.product-detail-actions button {
flex: 1;
font-weight: bold;
}
.product-detail-actions .add-to-cart-btn {
background-color: #A2D9A2; /* Hijau Muda */
color: white;
}
.product-detail-actions .add-to-cart-btn:hover {
background-color: #8CCF8C;
}
.product-detail-actions .chat-btn {
background-color: #FFD700; /* Kuning Cerah */
color: #333;
}
.product-detail-actions .chat-btn:hover {
background-color: #FFC107;
}
/* --- CART PAGE --- */
.cart-page {
padding: 15px 10px 80px 10px; /* Padding bawah untuk nav */
}
.cart-item {
display: flex;
align-items: center;
background-color: white;
padding: 10px;
margin-bottom: 10px;
border-radius: 8px;
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
}
.cart-item img {
width: 60px;
height: 60px;
object-fit: cover;
border-radius: 5px;
margin-right: 10px;
}
.cart-item-info {
flex-grow: 1;
}
.cart-item-info h4 {
margin: 0 0 5px 0;
font-size: 1em;
}
.cart-item-info p {
margin: 0;
font-size: 0.9em;
color: #666;
}
.cart-item-actions {
display: flex;
align-items: center;
gap: 5px;
}
.cart-item-actions button {
background-color: #EEEEEE; /* Abu-abu Muda */
color: #555;
padding: 5px 8px;
font-size: 0.9em;
border-radius: 5px;
}
.cart-item-actions button.remove {
background-color: #FFCDD2;
color: #D32F2F;
}
.cart-summary {
background-color: white;
padding: 15px;
border-radius: 8px;
box-shadow: 0 2px 5px rgba(0,0,0,0.05);
margin-top: 20px;
}
.cart-summary p {
display: flex;
justify-content: space-between;
margin: 5px 0;
font-size: 1.1em;
}
.cart-summary p strong {
color: #A2D9A2; /* Hijau Muda */
}
.checkout-btn {
background-color: #A2D9A2; /* Hijau Muda */
color: white;
width: 100%;
margin-top: 15px;
padding: 12px;
font-weight: bold;
border-radius: 8px;
}
.checkout-btn:hover {
background-color: #8CCF8C;
}
/* --- CHECKOUT PAGE (Sederhana) --- */
.checkout-page {
padding: 15px 10px 80px 10px;
background-color: white;
min-height: calc(100vh - 120px);
}
.checkout-page h2 {
color: #A2D9A2;
margin-bottom: 20px;
}
.checkout-page label {
display: block;
margin-bottom: 5px;
font-weight: 500;
}
.checkout-page select {
width: 100%;
padding: 10px;
margin-bottom: 15px;
border: 1px solid #EEEEEE;
border-radius: 5px;
box-sizing: border-box;
background-color: white;
}
.checkout-order-summary {
background-color: #F8F8F8;
padding: 15px;
border-radius: 8px;
margin-bottom: 20px;
}
.checkout-order-summary h3 {
margin-top: 0;
color: #A2D9A2;
font-size: 1.2em;
}
.checkout-order-summary ul {
list-style: none;
padding: 0;
margin: 0 0 10px 0;
}
.checkout-order-summary ul li {
display: flex;
justify-content: space-between;
font-size: 0.9em;
margin-bottom: 5px;
}
.checkout-order-summary p.total {
font-weight: bold;
font-size: 1.2em;
text-align: right;
border-top: 1px dashed #DDD;
padding-top: 10px;
margin-top: 10px;
}
.place-order-btn {
background-color: #FFD700; /* Kuning Cerah */
color: #333;
width: 100%;
padding: 15px;
font-weight: bold;
border-radius: 8px;
font-size: 1.1em;
}
.place-order-btn:hover {
background-color: #FFC107;
}
/* --- PROFILE / ACCOUNT PAGE (Sederhana) --- */
.account-page {
padding: 15px 10px 80px 10px;
background-color: white;
min-height: calc(100vh - 120px);
}
.account-page h2 {
color: #A2D9A2;
margin-bottom: 20px;
}
.account-page p {
margin-bottom: 10px;
line-height: 1.5;
}
.account-page .profile-section {
background-color: #F8F8F8;
padding: 15px;
border-radius: 8px;
margin-bottom: 15px;
}
.account-page .profile-section h3 {
margin-top: 0;
color: #555;
border-bottom: 1px solid #EEEEEE;
padding-bottom: 8px;
margin-bottom: 10px;
}
.account-page button {
background-color: #FFD700;
color: #333;
margin-top: 10px;
}
/* --- UTILITIES --- */
.hidden {
display: none !important;
}
.text-center {
text-align: center;
}
.mb-15 { margin-bottom: 15px; }
.mt-15 { margin-top: 15px; }
/* Font Awesome for Icons (Jika ingin menggunakan ikon) */
@import url('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css');
</style>
<!-- Font Awesome (for icons in bottom navigation) -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css">
<!-- MAIN HTML STRUCTURE -->
<div class="marketplace-app">
<!-- Header -->
<div class="header">
<h1>Marketplace RT NES</h1>
</div>
<!-- Search Bar (Optional, can be integrated into Home Page) -->
<div class="search-bar">
<input type="text" id="searchInput" placeholder="Cari produk atau warung...">
</div>
<!-- Main Content Area -->
<div class="main-content">
<!-- HOME PAGE -->
<div id="homePage" class="page">
<div class="banner">
<p>🎉 Dukung Usaha Lokal RT NES! 🎉</p>
<p>Temukan aneka produk dan jasa dari tetangga kita.</p>
</div>
<h2 class="text-center mb-15">Produk Terbaru</h2>
<div id="productGrid" class="product-grid">
<!-- Products will be loaded here by JavaScript -->
</div>
</div>
<!-- CATEGORIES PAGE (Sederhana, bisa dikembangkan) -->
<div id="categoriesPage" class="page hidden">
<h2 class="text-center mb-15">Kategori Produk</h2>
<div class="product-grid">
<div class="product-card" onclick="alert('Ini adalah kategori Makanan. Fitur ini bisa dikembangkan lebih lanjut!')">
<img src="https://via.placeholder.com/150/A2D9A2/FFFFFF?text=Makanan" alt="Kategori Makanan">
<div class="product-card-info text-center">
<h3>Makanan & Minuman</h3>
</div>
</div>
<div class="product-card" onclick="alert('Ini adalah kategori Jasa. Fitur ini bisa dikembangkan lebih lanjut!')">
<img src="https://via.placeholder.com/150/FFD700/FFFFFF?text=Jasa" alt="Kategori Jasa">
<div class="product-card-info text-center">
<h3>Jasa Lokal</h3>
</div>
</div>
<div class="product-card" onclick="alert('Ini adalah kategori Kerajinan. Fitur ini bisa dikembangkan lebih lanjut!')">
<img src="https://via.placeholder.com/150/A2D9A2/FFFFFF?text=Kerajinan" alt="Kategori Kerajinan">
<div class="product-card-info text-center">
<h3>Kerajinan Tangan</h3>
</div>
</div>
<div class="product-card" onclick="alert('Ini adalah kategori Lain-lain. Fitur ini bisa dikembangkan lebih lanjut!')">
<img src="https://via.placeholder.com/150/FFD700/FFFFFF?text=Lain-lain" alt="Kategori Lain-lain">
<div class="product-card-info text-center">
<h3>Lain-lain</h3>
</div>
</div>
</div>
</div>
<!-- PRODUCT DETAIL PAGE -->
<div id="productDetailPage" class="page hidden product-detail-page">
<!-- Product details will be loaded here by JavaScript -->
</div>
<!-- CART PAGE -->
<div id="cartPage" class="page hidden cart-page">
<h2 class="text-center mb-15">Keranjang Belanja</h2>
<div id="cartItemsContainer">
<!-- Cart items will be loaded here by JavaScript -->
<p class="text-center" id="emptyCartMessage">Keranjang Anda masih kosong.</p>
</div>
<div id="cartSummary" class="cart-summary hidden">
<p>Subtotal: <span id="cartSubtotal">Rp 0</span></p>
<p>Ongkos Kirim (Lokal RT): <span>Rp 5.000</span></p>
<p><strong>Total: <strong id="cartTotal">Rp 0</strong></strong></p>
<button class="checkout-btn" onclick="showPage('checkoutPage')">Lanjut ke Checkout</button>
</div>
</div>
<!-- CHECKOUT PAGE -->
<div id="checkoutPage" class="page hidden checkout-page">
<h2 class="text-center">Checkout Pesanan</h2>
<div class="checkout-order-summary">
<h3>Ringkasan Pesanan Anda</h3>
<ul id="checkoutItemsList">
<!-- Items will be listed here -->
</ul>
<p class="total">Total Bayar: <strong id="checkoutTotalAmount">Rp 0</strong></p>
</div>
<label for="customerName">Nama Lengkap:</label>
<input type="text" id="customerName" placeholder="Nama Anda" value="Anonim">
<label for="customerAddress">Alamat Pengiriman:</label>
<textarea id="customerAddress" placeholder="Contoh: Jl. Mawar No.12, RT 01 RW 02"></textarea>
<label for="paymentMethod">Metode Pembayaran:</label>
<select id="paymentMethod">
<option value="COD">Bayar di Tempat (COD)</option>
<option value="Transfer Bank">Transfer Bank (BCA/Mandiri)</option>
<option value="QRIS">QRIS</option>
</select>
<p class="text-center" style="font-size:0.9em; color: #666;">
Setelah 'Konfirmasi Pesanan', Anda akan diarahkan ke WhatsApp untuk detail pembayaran/pengiriman.
</p>
<button class="place-order-btn" onclick="placeOrder()">Konfirmasi Pesanan</button>
</div>
<!-- ACCOUNT / PROFILE PAGE (Sederhana) -->
<div id="accountPage" class="page hidden account-page">
<h2 class="text-center">Akun Saya</h2>
<div class="profile-section">
<h3>Informasi Pengguna</h3>
<p><strong>Nama:</strong> Warga RT Nes</p>
<p><strong>Email:</strong> warga@rtnes.com (Simulasi)</p>
</div>
<div class="profile-section">
<h3>Manajemen Warung (Untuk Penjual)</h3>
<p>Jika Anda pemilik warung, Anda bisa mendaftarkan warung Anda ke admin RT untuk mulai berjualan. Fitur ini akan ditambahkan oleh admin RT.</p>
<button class="add-store-btn" onclick="alert('Fitur tambah warung dan produk akan diatur oleh admin RT. Silakan hubungi Admin RT untuk pendaftaran warung Anda.')">Daftar Warung</button>
</div>
<p class="text-center mt-15" style="font-size:0.8em; color: #999;">Untuk perubahan data akun, silakan hubungi Admin RT.</p>
</div>
</div>
<!-- Bottom Navigation -->
<div class="bottom-nav">
<button id="navHome" class="active" onclick="showPage('homePage')">
<i class="fas fa-home"></i> Home
</button>
<button id="navCategories" onclick="showPage('categoriesPage')">
<i class="fas fa-th-large"></i> Kategori
</button>
<button id="navCart" onclick="showPage('cartPage')">
<i class="fas fa-shopping-cart"></i> Keranjang <span id="cartCount" style="background-color: red; color: white; border-radius: 50%; padding: 2px 6px; font-size: 0.7em; margin-left: 5px; display: none;">0</span>
</button>
<button id="navAccount" onclick="showPage('accountPage')">
<i class="fas fa-user"></i> Akun
</button>
</div>
</div>
<script>
// --- DATA SIMULASI PRODUK (Admin RT bisa edit ini) ---
const products = [
{
id: 'p001',
name: 'Nasi Kuning Komplit',
price: 12000,
store: 'Warung Bu Siti',
storePhone: '6281234567890', // Nomor WhatsApp penjual (format: kode negara tanpa +)
image: 'https://via.placeholder.com/300x200/A2D9A2/FFFFFF?text=Nasi+Kuning',
description: 'Nasi kuning gurih dengan telur, orek tempe, dan abon. Cocok untuk sarapan atau makan siang.'
},
{
id: 'p002',
name: 'Kue Basah Campur',
price: 15000,
store: 'Pawon Mpok Leha',
storePhone: '6281234567891',
image: 'https://via.placeholder.com/300x200/FFD700/333333?text=Kue+Basah',
description: 'Aneka kue basah tradisional (3 jenis) per kotak. Pesan H-1.'
},
{
id: 'p003',
name: 'Jasa Cuci Setrika',
price: 10000, // Per kg
store: 'Jasa Laundry Express',
storePhone: '6281234567892',
image: 'https://via.placeholder.com/300x200/A2D9A2/FFFFFF?text=Cuci+Setrika',
description: 'Melayani cuci setrika per kilogram. Jemput antar area RT NES.'
},
{
id: 'p004',
name: 'Keripik Singkong Renyah',
price: 8000,
store: 'Snack Mbak Yuni',
storePhone: '6281234567893',
image: 'https://via.placeholder.com/300x200/FFD700/333333?text=Keripik',
description: 'Keripik singkong renyah dengan bumbu balado pedas manis. Cocok untuk camilan.'
},
{
id: 'p005',
name: 'Ayam Goreng Krispi',
price: 17000,
store: 'Ayam Penyet Bu Lastri',
storePhone: '6281234567894',
image: 'https://via.placeholder.com/300x200/A2D9A2/FFFFFF?text=Ayam+Goreng',
description: 'Seporsi ayam goreng krispi renyah dengan nasi dan lalapan.'
}
// Tambahkan produk lain di sini
];
let cart = JSON.parse(localStorage.getItem('cart')) || [];
let currentPage = 'homePage'; // Default page
// --- HELPER FUNCTIONS ---
function formatRupiah(number) {
return new Intl.NumberFormat('id-ID', {
style: 'currency',
currency: 'IDR',
minimumFractionDigits: 0
}).format(number);
}
// --- PAGE NAVIGATION ---
function showPage(pageId) {
const pages = document.querySelectorAll('.page');
pages.forEach(page => page.classList.add('hidden'));
document.getElementById(pageId).classList.remove('hidden');
// Update active state for bottom nav buttons
const navButtons = document.querySelectorAll('.bottom-nav button');
navButtons.forEach(btn => btn.classList.remove('active'));
document.getElementById('nav' + pageId.charAt(0).toUpperCase() + pageId.slice(1).replace('Page', '')).classList.add('active');
currentPage = pageId; // Update current page state
// Specific updates for certain pages
if (pageId === 'cartPage') {
renderCart();
} else if (pageId === 'checkoutPage') {
renderCheckoutSummary();
}
}
// --- HOME PAGE RENDERING ---
function renderProducts(filterText = '') {
const productGrid = document.getElementById('productGrid');
productGrid.innerHTML = ''; // Clear existing products
const filteredProducts = products.filter(product =>
product.name.toLowerCase().includes(filterText.toLowerCase()) ||
product.store.toLowerCase().includes(filterText.toLowerCase())
);
if (filteredProducts.length === 0) {
productGrid.innerHTML = '<p class="text-center" style="grid-column: 1 / -1; color: #666;">Produk tidak ditemukan.</p>';
return;
}
filteredProducts.forEach(product => {
const productCard = document.createElement('div');
productCard.classList.add('product-card');
productCard.innerHTML = `
<img src="${product.image}" alt="${product.name}">
<div class="product-card-info">
<h3>${product.name}</h3>
<p class="price">${formatRupiah(product.price)}</p>
<p class="store">Dari: ${product.store}</p>
</div>
<button onclick="showProductDetail('${product.id}')">Lihat Detail</button>
`;
productGrid.appendChild(productCard);
});
}
// --- PRODUCT DETAIL PAGE ---
function showProductDetail(productId) {
const product = products.find(p => p.id === productId);
if (!product) {
alert('Produk tidak ditemukan!');
return;
}
const detailPage = document.getElementById('productDetailPage');
detailPage.innerHTML = `
<img src="${product.image}" alt="${product.name}">
<h2>${product.name}</h2>
<p class="price">${formatRupiah(product.price)}</p>
<p class="store-info">Dijual oleh: <strong>${product.store}</strong></p>
<p class="description">${product.description}</p>
<div class="product-detail-actions">
<button class="add-to-cart-btn" onclick="addToCart('${product.id}')">Tambah ke Keranjang</button>
<button class="chat-btn" onclick="chatWithSeller('${product.storePhone}', '${product.name}')">Pesan via WA</button>
</div>
`;
showPage('productDetailPage');
}
// --- CART FUNCTIONS ---
function updateCartCount() {
const cartCountElement = document.getElementById('cartCount');
const totalItems = cart.reduce((sum, item) => sum + item.quantity, 0);
if (totalItems > 0) {
cartCountElement.textContent = totalItems;
cartCountElement.style.display = 'inline';
} else {
cartCountElement.style.display = 'none';
}
}
function addToCart(productId) {
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({ ...product, quantity: 1 });
}
localStorage.setItem('cart', JSON.stringify(cart));
updateCartCount();
alert(`${product.name} ditambahkan ke keranjang!`);
}
function renderCart() {
const cartItemsContainer = document.getElementById('cartItemsContainer');
const emptyCartMessage = document.getElementById('emptyCartMessage');
const cartSummary = document.getElementById('cartSummary');
let subtotal = 0;
cartItemsContainer.innerHTML = '';
if (cart.length === 0) {
emptyCartMessage.classList.remove('hidden');
cartSummary.classList.add('hidden');
return;
}
emptyCartMessage.classList.add('hidden');
cartSummary.classList.remove('hidden');
cart.forEach(item => {
subtotal += item.price * item.quantity;
const cartItemDiv = document.createElement('div');
cartItemDiv.classList.add('cart-item');
cartItemDiv.innerHTML = `
<img src="${item.image}" alt="${item.name}">
<div class="cart-item-info">
<h4>${item.name}</h4>
<p>${formatRupiah(item.price)} x ${item.quantity}</p>
</div>
<div class="cart-item-actions">
<button onclick="updateQuantity('${item.id}', -1)">-</button>
<span>${item.quantity}</span>
<button onclick="updateQuantity('${item.id}', 1)">+</button>
<button class="remove" onclick="removeFromCart('${item.id}')"><i class="fas fa-trash-alt"></i></button>
</div>
`;
cartItemsContainer.appendChild(cartItemDiv);
});
const ongkir = 5000; // Contoh ongkir lokal RT
document.getElementById('cartSubtotal').textContent = formatRupiah(subtotal);
document.getElementById('cartTotal').textContent = formatRupiah(subtotal + ongkir);
}
function updateQuantity(productId, change) {
const itemIndex = cart.findIndex(item => item.id === productId);
if (itemIndex > -1) {
cart[itemIndex].quantity += change;
if (cart[itemIndex].quantity <= 0) {
cart.splice(itemIndex, 1); // Remove if quantity is 0 or less
}
localStorage.setItem('cart', JSON.stringify(cart));
renderCart();
updateCartCount();
}
}
function removeFromCart(productId) {
if (confirm('Yakin ingin menghapus item ini dari keranjang?')) {
cart = cart.filter(item => item.id !== productId);
localStorage.setItem('cart', JSON.stringify(cart));
renderCart();
updateCartCount();
}
}
// --- CHECKOUT FUNCTIONS ---
function renderCheckoutSummary() {
const checkoutItemsList = document.getElementById('checkoutItemsList');
const checkoutTotalAmount = document.getElementById('checkoutTotalAmount');
let subtotal = 0;
const ongkir = 5000;
checkoutItemsList.innerHTML = '';
cart.forEach(item => {
subtotal += item.price * item.quantity;
const li = document.createElement('li');
li.textContent = `${item.name} (${item.quantity}x)`;
const spanPrice = document.createElement('span');
spanPrice.textContent = formatRupiah(item.price * item.quantity);
li.appendChild(spanPrice);
checkoutItemsList.appendChild(li);
});
const liOngkir = document.createElement('li');
liOngkir.textContent = `Ongkos Kirim (Lokal RT)`;
const spanOngkir = document.createElement('span');
spanOngkir.textContent = formatRupiah(ongkir);
liOngkir.appendChild(spanOngkir);
checkoutItemsList.appendChild(liOngkir);
checkoutTotalAmount.textContent = formatRupiah(subtotal + ongkir);
}
function placeOrder() {
if (cart.length === 0) {
alert('Keranjang Anda kosong. Tambahkan produk dulu!');
return;
}
const customerName = document.getElementById('customerName').value;
const customerAddress = document.getElementById('customerAddress').value;
const paymentMethod = document.getElementById('paymentMethod').value;
if (!customerName || !customerAddress) {
alert('Nama dan Alamat pengiriman harus diisi!');
return;
}
let orderSummary = `Halo penjual! Saya ${customerName} dari RT NES, ingin memesan:\n\n`;
let totalOrderPrice = 0;
const ongkir = 5000; // Same as in cart
// Group items by store for individual WhatsApp messages
const ordersByStore = {};
cart.forEach(item => {
if (!ordersByStore[item.storePhone]) {
ordersByStore[item.storePhone] = {
storeName: item.store,
items: [],
subtotal: 0
};
}
ordersByStore[item.storePhone].items.push(`${item.name} (${item.quantity}x) - ${formatRupiah(item.price * item.quantity)}`);
ordersByStore[item.storePhone].subtotal += (item.price * item.quantity);
totalOrderPrice += (item.price * item.quantity);
});
// Create a consolidated message for the customer
let customerMessage = `Hai! Saya ${customerName}, telah melakukan pemesanan di Marketplace RT NES.\n\nDetail pesanan saya:\n\n`;
let overallOrderForCustomer = [];
Object.keys(ordersByStore).forEach(storePhone => {
const storeOrder = ordersByStore[storePhone];
customerMessage += `*${storeOrder.storeName} (${storePhone})*\n${storeOrder.items.join('\n')}\nSubtotal: ${formatRupiah(storeOrder.subtotal)}\n\n`;
overallOrderForCustomer.push(`*${storeOrder.storeName}*\n${storeOrder.items.join('\n')}\nSubtotal: ${formatRupiah(storeOrder.subtotal)}`);
});
customerMessage += `\nAlamat Pengiriman: ${customerAddress}\nMetode Pembayaran: ${paymentMethod}\n\n`;
customerMessage += `Ongkos Kirim: ${formatRupiah(ongkir)}\n`;
customerMessage += `*Total Pembayaran: ${formatRupiah(totalOrderPrice + ongkir)}*\n\n`;
customerMessage += `Mohon konfirmasi pesanan saya. Terima kasih! 😊`;
// Open WhatsApp for customer (this can be improved to send to admin or each seller individually)
const adminWA = '6281234567899'; // Ganti dengan nomor WA Admin RT
const whatsappLinkCustomer = `https://wa.me/${adminWA}?text=${encodeURIComponent(customerMessage)}`;
window.open(whatsappLinkCustomer, '_blank');
alert('Pesanan Anda telah dikirim ke Admin RT dan penjual via WhatsApp. Mohon tunggu konfirmasi!');
// Clear cart after placing order
cart = [];
localStorage.removeItem('cart');
updateCartCount();
showPage('homePage');
renderProducts();
}
function chatWithSeller(phone, productName) {
const message = encodeURIComponent(`Halo, saya tertarik dengan produk *${productName}* yang Anda jual di Marketplace RT NES. Mohon informasinya lebih lanjut. Terima kasih.`);
window.open(`https://wa.me/${phone}?text=${message}`, '_blank');
}
// --- INITIAL LOAD ---
document.addEventListener('DOMContentLoaded', () => {
renderProducts();
updateCartCount();
// Event listener for search input
document.getElementById('searchInput').addEventListener('keyup', (event) => {
renderProducts(event.target.value);
});
});
</script>
Penjelasan Detil untuk Admin RT dan Pengembangan Lanjutan:
1. Manajemen Produk (Untuk Admin RT)
- Edit Produk: Admin RT perlu mengedit daftar produk langsung di dalam skrip JavaScript. Cari bagian
const products = [...]dan tambahkan/edit objek produk di sana.- Setiap objek produk memiliki
id,name,price,store,storePhone(penting untuk WhatsApp),image, dandescription. - Ganti
https://via.placeholder.com/...dengan URL gambar produk asli. Anda bisa mengunggah gambar ke hosting gratis (seperti Imgur) atau menggunakan fitur unggah gambar di Blogger lalu menyalin URL-nya.
- Setiap objek produk memiliki
- Warga Daftar Warung: Admin RT akan menerima pendaftaran warung dari warga secara manual (misalnya via WhatsApp), lalu Admin RT yang akan menambahkan produk mereka ke dalam array
productsdi skrip.
2. Gambar Produk
https://via.placeholder.com/...: Ini adalah placeholder gambar. Ganti dengan URL gambar produk yang sebenarnya. Anda bisa mengunggah gambar ke Google Photos, Flickr, atau bahkan langsung di postingan Blogger tersembunyi, lalu dapatkan URL gambar langsungnya.
3. Nomor WhatsApp
storePhone: Pastikan formatnya adalah kode negara tanpa+(contoh:6281234567890untuk Indonesia).adminWA: Ganti dengan nomor WhatsApp Admin RT untuk menerima ringkasan pesanan.
4. Keterbatasan (Karena Blogger Bukan Platform E-commerce Penuh)
- Tidak Ada Backend Database: Semua data (produk, keranjang) disimpan di frontend (JavaScript array dan
localStorage). Ini berarti:- Produk baru harus ditambahkan/diedit secara manual di kode oleh Admin RT.
localStorageakan dihapus jika pengguna membersihkan cache browser mereka.- Tidak ada fitur stok barang, manajemen pesanan otomatis, atau notifikasi real-time ke penjual/admin secara otomatis (kecuali via WhatsApp yang manual).
- Pembayaran: Disimulasikan dan dikonfirmasi secara manual via WhatsApp. Tidak ada integrasi payment gateway otomatis seperti Midtrans atau Xendit.
- Manajemen Akun Penjual: Tidak ada dashboard terpisah untuk penjual. Semua pengaturan produk oleh admin RT.
- Keamanan: Karena berbasis HTML/JS sederhana, tidak seaman platform e-commerce berbayar. Namun, untuk komunitas RT yang kecil dan terpercaya, ini cukup.
5. Pengembangan Lanjutan (Jika Membutuhkan Fitur Lebih Lanjut)
Jika proyek ini berkembang dan fitur Blogger terasa membatasi:
- Migrasi ke Platform Lebih Kuat: Pertimbangkan untuk pindah ke platform seperti Laravel, WordPress (dengan WooCommerce), atau Shopify Lite jika membutuhkan database, manajemen stok, dan integrasi pembayaran otomatis.
- Integrasi Google Sheets (Semi-Backend): Untuk manajemen produk yang lebih mudah tanpa coding, Anda bisa mencoba mengintegrasikan Google Sheets sebagai "database" menggunakan Google Apps Script, lalu JavaScript di Blogger mengambil data dari sana. Ini lebih kompleks namun bisa mengurangi kebutuhan edit kode manual.
Skrip ini menyediakan dasar yang kuat dan fungsional untuk website marketplace lokal yang responsif di Blogger, dengan tampilan yang bersih dan sesuai tema warna yang diinginkan. Selamat mencoba!
Kemudian bagaimana cara pasangnya di blogger
Tentu, saya akan melanjutkan desain website marketplace lokal ini dengan berfokus pada implementasi di Blogger. Skrip ini akan dibuat seminimalis mungkin agar ringan dan mudah dipasang.
Berikut adalah skrip lengkap HTML, CSS, dan JavaScript yang bisa kamu pasang langsung di platform Blogger. Skrip ini mencakup struktur dasar, gaya, dan fungsionalitas inti yang responsif untuk perangkat seluler, dengan palet warna hijau muda dan kuning seperti yang kita diskusikan.
Penjelasan dan Fitur Utama Skrip:
- Struktur HTML (Blogger Post/Page):
- Menggunakan
divuntuk setiap bagian halaman (header, navigasi, konten utama, dll.). - Struktur yang sederhana agar mudah dimodifikasi di editor Blogger.
- Menggunakan
- CSS (Disisipkan di
<style>atau Template Blogger):- Responsif: Menggunakan media queries untuk menyesuaikan tampilan di layar HP.
- Palet Warna: Hijau muda (
#A2D9A2), Kuning Cerah (#FFD700), Putih Gading (#F8F8F8), Abu-abu Muda (#EEEEEE). - Tipografi: Menggunakan font sans-serif yang mudah dibaca.
- Elegan & Bersih: Desain minimalis dengan padding dan margin yang cukup.
- JavaScript (Disisipkan di
<script>):- Simulasi Data Produk: Karena Blogger bukan database, kita akan menggunakan array JavaScript untuk menyimpan data produk warung. Admin RT bisa mengedit array ini secara manual.
- Filter/Pencarian Sederhana: Fitur pencarian produk berdasarkan nama.
- Dinamis Menampilkan Produk: Produk akan dimuat secara dinamis ke halaman.
- Keranjang Belanja (Sederhana): Menggunakan
localStorageuntuk menyimpan item keranjang, sehingga tidak hilang saat halaman di-refresh (namun tidak akan bertahan jika browser ditutup atau cache dihapus). - Tombol Pesan (WhatsApp): Otomatis membuat link WhatsApp ke penjual.
- Proses Checkout (Simulasi): Mengarahkan ke link WhatsApp untuk konfirmasi pesanan.
- Navigasi: Menampilkan atau menyembunyikan bagian halaman yang berbeda.
Cara Pemasangan di Blogger:
- Login ke Blogger.
- Buat Halaman Baru: Masuk ke menu
Laman>Laman Baru. - Mode Tampilan HTML: Di editor laman, ganti mode dari
Tampilan MenuliskeTampilan HTML(biasanya ikon< >atau pilihan di sudut kiri atas). - Paste Skrip: Salin seluruh kode di bawah ini dan tempelkan di editor HTML tersebut.
- Perbarui/Publikasikan Laman: Beri judul laman, misalnya "Marketplace RT NES", lalu Publikasikan.
- Tambahkan ke Menu Navigasi (Opsional): Jika ingin laman ini muncul di menu blog utama, pergi ke
Tata Letak>Gadget>Daftar Lamandan tambahkan laman "Marketplace RT NES" yang baru dibuat.
Skrip Lengkap (HTML, CSS, JavaScript)
<style>
/* --- RESET & GLOBAL STYLES --- */
body {
margin: 0;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: #F8F8F8; /* Putih Gading */
color: #333;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.container {
max-width: 100%;
margin: 0 auto;
padding: 0 10px;
}
a {
text-decoration: none;
color: #A2D9A2; /* Hijau Muda */
}
button {
cursor: pointer;
border: none;
padding: 10px 15px;
border-radius: 5px;
font-size: 1em;
transition: background-color 0.3s ease;
}
input[type="text"], input[type="number"], textarea {
width: 100%;
padding: 10px;
margin-bottom: 10px;
border: 1px solid #EEEEEE; /* Abu-abu Muda */
border-radius: 5px;
box-sizing: border-box;
}
/* --- HEADER & NAVIGATION --- */
.header {
background-color: #A2D9A2; /* Hijau Muda */
color: white;
padding: 15px 10px;
text-align: center;
position: sticky;
top: 0;
z-index: 1000;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
.header h1 {
margin: 0;
font-size: 1.5em;
font-weight: 600;
}
.bottom-nav {
display: flex;
justify-content: space-around;
align-items: center;
background-color: white;
padding: 10px 0;
position: fixed;
bottom: 0;
left: 0;
right: 0;
box-shadow: 0 -2px 5px rgba(0,0,0,0.1);
z-index: 1000;
}
.bottom-nav button {
background: none;
color: #777;
font-size: 0.8em;
display: flex;
flex-direction: column;
align-items: center;
padding: 5px;
}
.bottom-nav button.active {
color: #A2D9A2; /* Hijau Muda */
}
.bottom-nav button i {
font-size: 1.2em;
margin-bottom: 3px;
}
/* Search Bar */
.search-bar {
padding: 10px;
background-color: #F8F8F8; /* Putih Gading */
border-bottom: 1px solid #EEEEEE;
}
.search-bar input {
background-color: white;
border-radius: 20px;
padding: 8px 15px;
border: 1px solid #DDD;
}
/* --- BANNER --- */
.banner {
background-color: #FFD700; /* Kuning Cerah */
color: #333;
padding: 15px;
text-align: center;
margin-bottom: 15px;
border-radius: 8px;
font-weight: 500;
margin: 10px;
}
.banner p {
margin: 5px 0;
}
/* --- PRODUCT LISTING --- */
.product-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 15px;
padding: 15px 10px 80px 10px; /* Padding bawah untuk nav */
}
.product-card {
background-color: white;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 5px rgba(0,0,0,0.05);
text-align: left;
display: flex;
flex-direction: column;
}
.product-card img {
width: 100%;
height: 120px;
object-fit: cover;
display: block;
border-bottom: 1px solid #EEEEEE;
}
.product-card-info {
padding: 10px;
flex-grow: 1;
}
.product-card h3 {
margin: 0 0 5px 0;
font-size: 1.1em;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.product-card p.price {
font-weight: bold;
color: #333;
margin: 0 0 5px 0;
}
.product-card p.store {
font-size: 0.85em;
color: #666;
margin: 0 0 10px 0;
}
.product-card button {
background-color: #FFD700; /* Kuning Cerah */
color: #333;
width: 100%;
border-radius: 0 0 8px 8px; /* Sudut bawah saja */
padding: 8px;
font-weight: 500;
}
.product-card button:hover {
background-color: #FFC107;
}
/* --- PRODUCT DETAIL PAGE --- */
.product-detail-page {
padding: 15px 10px 80px 10px; /* Padding bawah untuk nav */
background-color: white;
min-height: calc(100vh - 120px); /* Adjust height */
}
.product-detail-page img {
width: 100%;
height: 250px;
object-fit: cover;
border-radius: 8px;
margin-bottom: 15px;
}
.product-detail-page h2 {
margin-top: 0;
font-size: 1.8em;
color: #333;
}
.product-detail-page p.price {
font-size: 1.4em;
font-weight: bold;
color: #A2D9A2; /* Hijau Muda */
margin-bottom: 10px;
}
.product-detail-page p.store-info {
font-size: 1em;
color: #666;
margin-bottom: 15px;
}
.product-detail-page p.description {
font-size: 0.95em;
line-height: 1.5;
color: #555;
margin-bottom: 20px;
}
.product-detail-actions {
display: flex;
gap: 10px;
margin-top: 20px;
}
.product-detail-actions button {
flex: 1;
font-weight: bold;
}
.product-detail-actions .add-to-cart-btn {
background-color: #A2D9A2; /* Hijau Muda */
color: white;
}
.product-detail-actions .add-to-cart-btn:hover {
background-color: #8CCF8C;
}
.product-detail-actions .chat-btn {
background-color: #FFD700; /* Kuning Cerah */
color: #333;
}
.product-detail-actions .chat-btn:hover {
background-color: #FFC107;
}
/* --- CART PAGE --- */
.cart-page {
padding: 15px 10px 80px 10px; /* Padding bawah untuk nav */
}
.cart-item {
display: flex;
align-items: center;
background-color: white;
padding: 10px;
margin-bottom: 10px;
border-radius: 8px;
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
}
.cart-item img {
width: 60px;
height: 60px;
object-fit: cover;
border-radius: 5px;
margin-right: 10px;
}
.cart-item-info {
flex-grow: 1;
}
.cart-item-info h4 {
margin: 0 0 5px 0;
font-size: 1em;
}
.cart-item-info p {
margin: 0;
font-size: 0.9em;
color: #666;
}
.cart-item-actions {
display: flex;
align-items: center;
gap: 5px;
}
.cart-item-actions button {
background-color: #EEEEEE; /* Abu-abu Muda */
color: #555;
padding: 5px 8px;
font-size: 0.9em;
border-radius: 5px;
}
.cart-item-actions button.remove {
background-color: #FFCDD2;
color: #D32F2F;
}
.cart-summary {
background-color: white;
padding: 15px;
border-radius: 8px;
box-shadow: 0 2px 5px rgba(0,0,0,0.05);
margin-top: 20px;
}
.cart-summary p {
display: flex;
justify-content: space-between;
margin: 5px 0;
font-size: 1.1em;
}
.cart-summary p strong {
color: #A2D9A2; /* Hijau Muda */
}
.checkout-btn {
background-color: #A2D9A2; /* Hijau Muda */
color: white;
width: 100%;
margin-top: 15px;
padding: 12px;
font-weight: bold;
border-radius: 8px;
}
.checkout-btn:hover {
background-color: #8CCF8C;
}
/* --- CHECKOUT PAGE (Sederhana) --- */
.checkout-page {
padding: 15px 10px 80px 10px;
background-color: white;
min-height: calc(100vh - 120px);
}
.checkout-page h2 {
color: #A2D9A2;
margin-bottom: 20px;
}
.checkout-page label {
display: block;
margin-bottom: 5px;
font-weight: 500;
}
.checkout-page select {
width: 100%;
padding: 10px;
margin-bottom: 15px;
border: 1px solid #EEEEEE;
border-radius: 5px;
box-sizing: border-box;
background-color: white;
}
.checkout-order-summary {
background-color: #F8F8F8;
padding: 15px;
border-radius: 8px;
margin-bottom: 20px;
}
.checkout-order-summary h3 {
margin-top: 0;
color: #A2D9A2;
font-size: 1.2em;
}
.checkout-order-summary ul {
list-style: none;
padding: 0;
margin: 0 0 10px 0;
}
.checkout-order-summary ul li {
display: flex;
justify-content: space-between;
font-size: 0.9em;
margin-bottom: 5px;
}
.checkout-order-summary p.total {
font-weight: bold;
font-size: 1.2em;
text-align: right;
border-top: 1px dashed #DDD;
padding-top: 10px;
margin-top: 10px;
}
.place-order-btn {
background-color: #FFD700; /* Kuning Cerah */
color: #333;
width: 100%;
padding: 15px;
font-weight: bold;
border-radius: 8px;
font-size: 1.1em;
}
.place-order-btn:hover {
background-color: #FFC107;
}
/* --- PROFILE / ACCOUNT PAGE (Sederhana) --- */
.account-page {
padding: 15px 10px 80px 10px;
background-color: white;
min-height: calc(100vh - 120px);
}
.account-page h2 {
color: #A2D9A2;
margin-bottom: 20px;
}
.account-page p {
margin-bottom: 10px;
line-height: 1.5;
}
.account-page .profile-section {
background-color: #F8F8F8;
padding: 15px;
border-radius: 8px;
margin-bottom: 15px;
}
.account-page .profile-section h3 {
margin-top: 0;
color: #555;
border-bottom: 1px solid #EEEEEE;
padding-bottom: 8px;
margin-bottom: 10px;
}
.account-page button {
background-color: #FFD700;
color: #333;
margin-top: 10px;
}
/* --- UTILITIES --- */
.hidden {
display: none !important;
}
.text-center {
text-align: center;
}
.mb-15 { margin-bottom: 15px; }
.mt-15 { margin-top: 15px; }
/* Font Awesome for Icons (Jika ingin menggunakan ikon) */
@import url('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css');
</style>
<!-- Font Awesome (for icons in bottom navigation) -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css">
<!-- MAIN HTML STRUCTURE -->
<div class="marketplace-app">
<!-- Header -->
<div class="header">
<h1>Marketplace RT NES</h1>
</div>
<!-- Search Bar (Optional, can be integrated into Home Page) -->
<div class="search-bar">
<input type="text" id="searchInput" placeholder="Cari produk atau warung...">
</div>
<!-- Main Content Area -->
<div class="main-content">
<!-- HOME PAGE -->
<div id="homePage" class="page">
<div class="banner">
<p>🎉 Dukung Usaha Lokal RT NES! 🎉</p>
<p>Temukan aneka produk dan jasa dari tetangga kita.</p>
</div>
<h2 class="text-center mb-15">Produk Terbaru</h2>
<div id="productGrid" class="product-grid">
<!-- Products will be loaded here by JavaScript -->
</div>
</div>
<!-- CATEGORIES PAGE (Sederhana, bisa dikembangkan) -->
<div id="categoriesPage" class="page hidden">
<h2 class="text-center mb-15">Kategori Produk</h2>
<div class="product-grid">
<div class="product-card" onclick="alert('Ini adalah kategori Makanan. Fitur ini bisa dikembangkan lebih lanjut!')">
<img src="https://via.placeholder.com/150/A2D9A2/FFFFFF?text=Makanan" alt="Kategori Makanan">
<div class="product-card-info text-center">
<h3>Makanan & Minuman</h3>
</div>
</div>
<div class="product-card" onclick="alert('Ini adalah kategori Jasa. Fitur ini bisa dikembangkan lebih lanjut!')">
<img src="https://via.placeholder.com/150/FFD700/FFFFFF?text=Jasa" alt="Kategori Jasa">
<div class="product-card-info text-center">
<h3>Jasa Lokal</h3>
</div>
</div>
<div class="product-card" onclick="alert('Ini adalah kategori Kerajinan. Fitur ini bisa dikembangkan lebih lanjut!')">
<img src="https://via.placeholder.com/150/A2D9A2/FFFFFF?text=Kerajinan" alt="Kategori Kerajinan">
<div class="product-card-info text-center">
<h3>Kerajinan Tangan</h3>
</div>
</div>
<div class="product-card" onclick="alert('Ini adalah kategori Lain-lain. Fitur ini bisa dikembangkan lebih lanjut!')">
<img src="https://via.placeholder.com/150/FFD700/FFFFFF?text=Lain-lain" alt="Kategori Lain-lain">
<div class="product-card-info text-center">
<h3>Lain-lain</h3>
</div>
</div>
</div>
</div>
<!-- PRODUCT DETAIL PAGE -->
<div id="productDetailPage" class="page hidden product-detail-page">
<!-- Product details will be loaded here by JavaScript -->
</div>
<!-- CART PAGE -->
<div id="cartPage" class="page hidden cart-page">
<h2 class="text-center mb-15">Keranjang Belanja</h2>
<div id="cartItemsContainer">
<!-- Cart items will be loaded here by JavaScript -->
<p class="text-center" id="emptyCartMessage">Keranjang Anda masih kosong.</p>
</div>
<div id="cartSummary" class="cart-summary hidden">
<p>Subtotal: <span id="cartSubtotal">Rp 0</span></p>
<p>Ongkos Kirim (Lokal RT): <span>Rp 5.000</span></p>
<p><strong>Total: <strong id="cartTotal">Rp 0</strong></strong></p>
<button class="checkout-btn" onclick="showPage('checkoutPage')">Lanjut ke Checkout</button>
</div>
</div>
<!-- CHECKOUT PAGE -->
<div id="checkoutPage" class="page hidden checkout-page">
<h2 class="text-center">Checkout Pesanan</h2>
<div class="checkout-order-summary">
<h3>Ringkasan Pesanan Anda</h3>
<ul id="checkoutItemsList">
<!-- Items will be listed here -->
</ul>
<p class="total">Total Bayar: <strong id="checkoutTotalAmount">Rp 0</strong></p>
</div>
<label for="customerName">Nama Lengkap:</label>
<input type="text" id="customerName" placeholder="Nama Anda" value="Anonim">
<label for="customerAddress">Alamat Pengiriman:</label>
<textarea id="customerAddress" placeholder="Contoh: Jl. Mawar No.12, RT 01 RW 02"></textarea>
<label for="paymentMethod">Metode Pembayaran:</label>
<select id="paymentMethod">
<option value="COD">Bayar di Tempat (COD)</option>
<option value="Transfer Bank">Transfer Bank (BCA/Mandiri)</option>
<option value="QRIS">QRIS</option>
</select>
<p class="text-center" style="font-size:0.9em; color: #666;">
Setelah 'Konfirmasi Pesanan', Anda akan diarahkan ke WhatsApp untuk detail pembayaran/pengiriman.
</p>
<button class="place-order-btn" onclick="placeOrder()">Konfirmasi Pesanan</button>
</div>
<!-- ACCOUNT / PROFILE PAGE (Sederhana) -->
<div id="accountPage" class="page hidden account-page">
<h2 class="text-center">Akun Saya</h2>
<div class="profile-section">
<h3>Informasi Pengguna</h3>
<p><strong>Nama:</strong> Warga RT Nes</p>
<p><strong>Email:</strong> warga@rtnes.com (Simulasi)</p>
</div>
<div class="profile-section">
<h3>Manajemen Warung (Untuk Penjual)</h3>
<p>Jika Anda pemilik warung, Anda bisa mendaftarkan warung Anda ke admin RT untuk mulai berjualan. Fitur ini akan ditambahkan oleh admin RT.</p>
<button class="add-store-btn" onclick="alert('Fitur tambah warung dan produk akan diatur oleh admin RT. Silakan hubungi Admin RT untuk pendaftaran warung Anda.')">Daftar Warung</button>
</div>
<p class="text-center mt-15" style="font-size:0.8em; color: #999;">Untuk perubahan data akun, silakan hubungi Admin RT.</p>
</div>
</div>
<!-- Bottom Navigation -->
<div class="bottom-nav">
<button id="navHome" class="active" onclick="showPage('homePage')">
<i class="fas fa-home"></i> Home
</button>
<button id="navCategories" onclick="showPage('categoriesPage')">
<i class="fas fa-th-large"></i> Kategori
</button>
<button id="navCart" onclick="showPage('cartPage')">
<i class="fas fa-shopping-cart"></i> Keranjang <span id="cartCount" style="background-color: red; color: white; border-radius: 50%; padding: 2px 6px; font-size: 0.7em; margin-left: 5px; display: none;">0</span>
</button>
<button id="navAccount" onclick="showPage('accountPage')">
<i class="fas fa-user"></i> Akun
</button>
</div>
</div>
<script>
// --- DATA SIMULASI PRODUK (Admin RT bisa edit ini) ---
const products = [
{
id: 'p001',
name: 'Nasi Kuning Komplit',
price: 12000,
store: 'Warung Bu Siti',
storePhone: '6281234567890', // Nomor WhatsApp penjual (format: kode negara tanpa +)
image: 'https://via.placeholder.com/300x200/A2D9A2/FFFFFF?text=Nasi+Kuning',
description: 'Nasi kuning gurih dengan telur, orek tempe, dan abon. Cocok untuk sarapan atau makan siang.'
},
{
id: 'p002',
name: 'Kue Basah Campur',
price: 15000,
store: 'Pawon Mpok Leha',
storePhone: '6281234567891',
image: 'https://via.placeholder.com/300x200/FFD700/333333?text=Kue+Basah',
description: 'Aneka kue basah tradisional (3 jenis) per kotak. Pesan H-1.'
},
{
id: 'p003',
name: 'Jasa Cuci Setrika',
price: 10000, // Per kg
store: 'Jasa Laundry Express',
storePhone: '6281234567892',
image: 'https://via.placeholder.com/300x200/A2D9A2/FFFFFF?text=Cuci+Setrika',
description: 'Melayani cuci setrika per kilogram. Jemput antar area RT NES.'
},
{
id: 'p004',
name: 'Keripik Singkong Renyah',
price: 8000,
store: 'Snack Mbak Yuni',
storePhone: '6281234567893',
image: 'https://via.placeholder.com/300x200/FFD700/333333?text=Keripik',
description: 'Keripik singkong renyah dengan bumbu balado pedas manis. Cocok untuk camilan.'
},
{
id: 'p005',
name: 'Ayam Goreng Krispi',
price: 17000,
store: 'Ayam Penyet Bu Lastri',
storePhone: '6281234567894',
image: 'https://via.placeholder.com/300x200/A2D9A2/FFFFFF?text=Ayam+Goreng',
description: 'Seporsi ayam goreng krispi renyah dengan nasi dan lalapan.'
}
// Tambahkan produk lain di sini
];
let cart = JSON.parse(localStorage.getItem('cart')) || [];
let currentPage = 'homePage'; // Default page
// --- HELPER FUNCTIONS ---
function formatRupiah(number) {
return new Intl.NumberFormat('id-ID', {
style: 'currency',
currency: 'IDR',
minimumFractionDigits: 0
}).format(number);
}
// --- PAGE NAVIGATION ---
function showPage(pageId) {
const pages = document.querySelectorAll('.page');
pages.forEach(page => page.classList.add('hidden'));
document.getElementById(pageId).classList.remove('hidden');
// Update active state for bottom nav buttons
const navButtons = document.querySelectorAll('.bottom-nav button');
navButtons.forEach(btn => btn.classList.remove('active'));
document.getElementById('nav' + pageId.charAt(0).toUpperCase() + pageId.slice(1).replace('Page', '')).classList.add('active');
currentPage = pageId; // Update current page state
// Specific updates for certain pages
if (pageId === 'cartPage') {
renderCart();
} else if (pageId === 'checkoutPage') {
renderCheckoutSummary();
}
}
// --- HOME PAGE RENDERING ---
function renderProducts(filterText = '') {
const productGrid = document.getElementById('productGrid');
productGrid.innerHTML = ''; // Clear existing products
const filteredProducts = products.filter(product =>
product.name.toLowerCase().includes(filterText.toLowerCase()) ||
product.store.toLowerCase().includes(filterText.toLowerCase())
);
if (filteredProducts.length === 0) {
productGrid.innerHTML = '<p class="text-center" style="grid-column: 1 / -1; color: #666;">Produk tidak ditemukan.</p>';
return;
}
filteredProducts.forEach(product => {
const productCard = document.createElement('div');
productCard.classList.add('product-card');
productCard.innerHTML = `
<img src="${product.image}" alt="${product.name}">
<div class="product-card-info">
<h3>${product.name}</h3>
<p class="price">${formatRupiah(product.price)}</p>
<p class="store">Dari: ${product.store}</p>
</div>
<button onclick="showProductDetail('${product.id}')">Lihat Detail</button>
`;
productGrid.appendChild(productCard);
});
}
// --- PRODUCT DETAIL PAGE ---
function showProductDetail(productId) {
const product = products.find(p => p.id === productId);
if (!product) {
alert('Produk tidak ditemukan!');
return;
}
const detailPage = document.getElementById('productDetailPage');
detailPage.innerHTML = `
<img src="${product.image}" alt="${product.name}">
<h2>${product.name}</h2>
<p class="price">${formatRupiah(product.price)}</p>
<p class="store-info">Dijual oleh: <strong>${product.store}</strong></p>
<p class="description">${product.description}</p>
<div class="product-detail-actions">
<button class="add-to-cart-btn" onclick="addToCart('${product.id}')">Tambah ke Keranjang</button>
<button class="chat-btn" onclick="chatWithSeller('${product.storePhone}', '${product.name}')">Pesan via WA</button>
</div>
`;
showPage('productDetailPage');
}
// --- CART FUNCTIONS ---
function updateCartCount() {
const cartCountElement = document.getElementById('cartCount');
const totalItems = cart.reduce((sum, item) => sum + item.quantity, 0);
if (totalItems > 0) {
cartCountElement.textContent = totalItems;
cartCountElement.style.display = 'inline';
} else {
cartCountElement.style.display = 'none';
}
}
function addToCart(productId) {
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({ ...product, quantity: 1 });
}
localStorage.setItem('cart', JSON.stringify(cart));
updateCartCount();
alert(`${product.name} ditambahkan ke keranjang!`);
}
function renderCart() {
const cartItemsContainer = document.getElementById('cartItemsContainer');
const emptyCartMessage = document.getElementById('emptyCartMessage');
const cartSummary = document.getElementById('cartSummary');
let subtotal = 0;
cartItemsContainer.innerHTML = '';
if (cart.length === 0) {
emptyCartMessage.classList.remove('hidden');
cartSummary.classList.add('hidden');
return;
}
emptyCartMessage.classList.add('hidden');
cartSummary.classList.remove('hidden');
cart.forEach(item => {
subtotal += item.price * item.quantity;
const cartItemDiv = document.createElement('div');
cartItemDiv.classList.add('cart-item');
cartItemDiv.innerHTML = `
<img src="${item.image}" alt="${item.name}">
<div class="cart-item-info">
<h4>${item.name}</h4>
<p>${formatRupiah(item.price)} x ${item.quantity}</p>
</div>
<div class="cart-item-actions">
<button onclick="updateQuantity('${item.id}', -1)">-</button>
<span>${item.quantity}</span>
<button onclick="updateQuantity('${item.id}', 1)">+</button>
<button class="remove" onclick="removeFromCart('${item.id}')"><i class="fas fa-trash-alt"></i></button>
</div>
`;
cartItemsContainer.appendChild(cartItemDiv);
});
const ongkir = 5000; // Contoh ongkir lokal RT
document.getElementById('cartSubtotal').textContent = formatRupiah(subtotal);
document.getElementById('cartTotal').textContent = formatRupiah(subtotal + ongkir);
}
function updateQuantity(productId, change) {
const itemIndex = cart.findIndex(item => item.id === productId);
if (itemIndex > -1) {
cart[itemIndex].quantity += change;
if (cart[itemIndex].quantity <= 0) {
cart.splice(itemIndex, 1); // Remove if quantity is 0 or less
}
localStorage.setItem('cart', JSON.stringify(cart));
renderCart();
updateCartCount();
}
}
function removeFromCart(productId) {
if (confirm('Yakin ingin menghapus item ini dari keranjang?')) {
cart = cart.filter(item => item.id !== productId);
localStorage.setItem('cart', JSON.stringify(cart));
renderCart();
updateCartCount();
}
}
// --- CHECKOUT FUNCTIONS ---
function renderCheckoutSummary() {
const checkoutItemsList = document.getElementById('checkoutItemsList');
const checkoutTotalAmount = document.getElementById('checkoutTotalAmount');
let subtotal = 0;
const ongkir = 5000;
checkoutItemsList.innerHTML = '';
cart.forEach(item => {
subtotal += item.price * item.quantity;
const li = document.createElement('li');
li.textContent = `${item.name} (${item.quantity}x)`;
const spanPrice = document.createElement('span');
spanPrice.textContent = formatRupiah(item.price * item.quantity);
li.appendChild(spanPrice);
checkoutItemsList.appendChild(li);
});
const liOngkir = document.createElement('li');
liOngkir.textContent = `Ongkos Kirim (Lokal RT)`;
const spanOngkir = document.createElement('span');
spanOngkir.textContent = formatRupiah(ongkir);
liOngkir.appendChild(spanOngkir);
checkoutItemsList.appendChild(liOngkir);
checkoutTotalAmount.textContent = formatRupiah(subtotal + ongkir);
}
function placeOrder() {
if (cart.length === 0) {
alert('Keranjang Anda kosong. Tambahkan produk dulu!');
return;
}
const customerName = document.getElementById('customerName').value;
const customerAddress = document.getElementById('customerAddress').value;
const paymentMethod = document.getElementById('paymentMethod').value;
if (!customerName || !customerAddress) {
alert('Nama dan Alamat pengiriman harus diisi!');
return;
}
let orderSummary = `Halo penjual! Saya ${customerName} dari RT NES, ingin memesan:\n\n`;
let totalOrderPrice = 0;
const ongkir = 5000; // Same as in cart
// Group items by store for individual WhatsApp messages
const ordersByStore = {};
cart.forEach(item => {
if (!ordersByStore[item.storePhone]) {
ordersByStore[item.storePhone] = {
storeName: item.store,
items: [],
subtotal: 0
};
}
ordersByStore[item.storePhone].items.push(`${item.name} (${item.quantity}x) - ${formatRupiah(item.price * item.quantity)}`);
ordersByStore[item.storePhone].subtotal += (item.price * item.quantity);
totalOrderPrice += (item.price * item.quantity);
});
// Create a consolidated message for the customer
let customerMessage = `Hai! Saya ${customerName}, telah melakukan pemesanan di Marketplace RT NES.\n\nDetail pesanan saya:\n\n`;
let overallOrderForCustomer = [];
Object.keys(ordersByStore).forEach(storePhone => {
const storeOrder = ordersByStore[storePhone];
customerMessage += `*${storeOrder.storeName} (${storePhone})*\n${storeOrder.items.join('\n')}\nSubtotal: ${formatRupiah(storeOrder.subtotal)}\n\n`;
overallOrderForCustomer.push(`*${storeOrder.storeName}*\n${storeOrder.items.join('\n')}\nSubtotal: ${formatRupiah(storeOrder.subtotal)}`);
});
customerMessage += `\nAlamat Pengiriman: ${customerAddress}\nMetode Pembayaran: ${paymentMethod}\n\n`;
customerMessage += `Ongkos Kirim: ${formatRupiah(ongkir)}\n`;
customerMessage += `*Total Pembayaran: ${formatRupiah(totalOrderPrice + ongkir)}*\n\n`;
customerMessage += `Mohon konfirmasi pesanan saya. Terima kasih! 😊`;
// Open WhatsApp for customer (this can be improved to send to admin or each seller individually)
const adminWA = '6281234567899'; // Ganti dengan nomor WA Admin RT
const whatsappLinkCustomer = `https://wa.me/${adminWA}?text=${encodeURIComponent(customerMessage)}`;
window.open(whatsappLinkCustomer, '_blank');
alert('Pesanan Anda telah dikirim ke Admin RT dan penjual via WhatsApp. Mohon tunggu konfirmasi!');
// Clear cart after placing order
cart = [];
localStorage.removeItem('cart');
updateCartCount();
showPage('homePage');
renderProducts();
}
function chatWithSeller(phone, productName) {
const message = encodeURIComponent(`Halo, saya tertarik dengan produk *${productName}* yang Anda jual di Marketplace RT NES. Mohon informasinya lebih lanjut. Terima kasih.`);
window.open(`https://wa.me/${phone}?text=${message}`, '_blank');
}
// --- INITIAL LOAD ---
document.addEventListener('DOMContentLoaded', () => {
renderProducts();
updateCartCount();
// Event listener for search input
document.getElementById('searchInput').addEventListener('keyup', (event) => {
renderProducts(event.target.value);
});
});
</script>
Penjelasan Detil untuk Admin RT dan Pengembangan Lanjutan:
1. Manajemen Produk (Untuk Admin RT)
- Edit Produk: Admin RT perlu mengedit daftar produk langsung di dalam skrip JavaScript. Cari bagian
const products = [...]dan tambahkan/edit objek produk di sana.- Setiap objek produk memiliki
id,name,price,store,storePhone(penting untuk WhatsApp),image, dandescription. - Ganti
https://via.placeholder.com/...dengan URL gambar produk asli. Anda bisa mengunggah gambar ke hosting gratis (seperti Imgur) atau menggunakan fitur unggah gambar di Blogger lalu menyalin URL-nya.
- Setiap objek produk memiliki
- Warga Daftar Warung: Admin RT akan menerima pendaftaran warung dari warga secara manual (misalnya via WhatsApp), lalu Admin RT yang akan menambahkan produk mereka ke dalam array
productsdi skrip.
2. Gambar Produk
https://via.placeholder.com/...: Ini adalah placeholder gambar. Ganti dengan URL gambar produk yang sebenarnya. Anda bisa mengunggah gambar ke Google Photos, Flickr, atau bahkan langsung di postingan Blogger tersembunyi, lalu dapatkan URL gambar langsungnya.
3. Nomor WhatsApp
storePhone: Pastikan formatnya adalah kode negara tanpa+(contoh:6281234567890untuk Indonesia).adminWA: Ganti dengan nomor WhatsApp Admin RT untuk menerima ringkasan pesanan.
4. Keterbatasan (Karena Blogger Bukan Platform E-commerce Penuh)
- Tidak Ada Backend Database: Semua data (produk, keranjang) disimpan di frontend (JavaScript array dan
localStorage). Ini berarti:- Produk baru harus ditambahkan/diedit secara manual di kode oleh Admin RT.
localStorageakan dihapus jika pengguna membersihkan cache browser mereka.- Tidak ada fitur stok barang, manajemen pesanan otomatis, atau notifikasi real-time ke penjual/admin secara otomatis (kecuali via WhatsApp yang manual).
- Pembayaran: Disimulasikan dan dikonfirmasi secara manual via WhatsApp. Tidak ada integrasi payment gateway otomatis seperti Midtrans atau Xendit.
- Manajemen Akun Penjual: Tidak ada dashboard terpisah untuk penjual. Semua pengaturan produk oleh admin RT.
- Keamanan: Karena berbasis HTML/JS sederhana, tidak seaman platform e-commerce berbayar. Namun, untuk komunitas RT yang kecil dan terpercaya, ini cukup.
5. Pengembangan Lanjutan (Jika Membutuhkan Fitur Lebih Lanjut)
Jika proyek ini berkembang dan fitur Blogger terasa membatasi:
- Migrasi ke Platform Lebih Kuat: Pertimbangkan untuk pindah ke platform seperti Laravel, WordPress (dengan WooCommerce), atau Shopify Lite jika membutuhkan database, manajemen stok, dan integrasi pembayaran otomatis.
- Integrasi Google Sheets (Semi-Backend): Untuk manajemen produk yang lebih mudah tanpa coding, Anda bisa mencoba mengintegrasikan Google Sheets sebagai "database" menggunakan Google Apps Script, lalu JavaScript di Blogger mengambil data dari sana. Ini lebih kompleks namun bisa mengurangi kebutuhan edit kode manual.
Skrip ini menyediakan dasar yang kuat dan fungsional untuk website marketplace lokal yang responsif di Blogger, dengan tampilan yang bersih dan sesuai tema warna yang diinginkan. Selamat mencoba! Tentu, mari kita lanjutkan dengan panduan langkah demi langkah tentang cara memasang skrip HTML, CSS, dan JavaScript yang saya berikan sebelumnya di Blogger. Proses ini membutuhkan sedikit perhatian karena Blogger memiliki cara khusus dalam menangani konten kustom.
Berikut adalah langkah-langkah detail untuk memasangnya:
Cara Memasang Skrip di Blogger:
Ada dua metode utama, tergantung apakah Anda ingin marketplace ini menjadi sebuah "halaman" atau "postingan" terpisah, atau jika Anda ingin sedikit lebih maju dengan mengintegrasikannya ke tema blog Anda.
Metode 1: Membuat Marketplace sebagai Halaman atau Postingan Baru (Paling Mudah)
Ini adalah cara termudah dan direkomendasikan untuk awal, karena tidak akan mengganggu struktur tema blog Anda yang sudah ada.
- Login ke Akun Blogger Anda.
- Akses Menu "Laman" (Pages) atau "Postingan" (Posts):
- Jika Anda ingin marketplace ini menjadi halaman statis (misalnya
/p/marketplace-rt.html), klik pada menu Laman di sidebar kiri. - Jika Anda ingin marketplace ini muncul seperti postingan blog (misalnya
/2025/11/marketplace-rt-nes.html), klik pada menu Postingan. - Pilih Laman Baru atau Postingan Baru.
- Jika Anda ingin marketplace ini menjadi halaman statis (misalnya
- Ganti Mode Editor ke Tampilan HTML:
- Di editor postingan/laman, Anda akan melihat ikon pensil atau menu dropdown di sudut kiri atas (biasanya di samping judul). Klik ikon tersebut, lalu pilih Tampilan HTML (atau
HTML view). Ini sangat penting, jangan sampai di modeTampilan MenulisatauCompose view.
- Di editor postingan/laman, Anda akan melihat ikon pensil atau menu dropdown di sudut kiri atas (biasanya di samping judul). Klik ikon tersebut, lalu pilih Tampilan HTML (atau
Tidak ada komentar:
Posting Komentar