update footer

This commit is contained in:
flems 2026-05-22 18:57:32 +07:00
parent d3a336b5a0
commit 5cf07e2f8e
8 changed files with 2 additions and 1347 deletions

View File

@ -1,301 +0,0 @@
# 🚀 Deploy Web Javaherbal ke Vercel
## ✅ Persiapan Selesai!
File-file yang sudah disiapkan:
- ✅ `.gitignore` - Exclude node_modules, dist, .env
- ✅ `vercel.json` - Konfigurasi Vercel
- ✅ `package.json` - Script build sudah ada
---
## 📋 LANGKAH-LANGKAH DEPLOY
### 1️⃣ Push ke GitHub
#### A. Buat Repository Baru di GitHub
1. Buka https://github.com
2. Klik tombol **"New"** (repository baru)
3. Isi:
- Repository name: `frondend-web`
- Description: `Web dashboard untuk sistem pengeringan cabai jawa`
- Visibility: **Public** atau **Private**
4. **JANGAN** centang "Add a README file"
5. Klik **"Create repository"**
#### B. Push Code ke GitHub
```bash
cd javaherbal-v2/javaherbal2
# Initialize git
git init
# Add all files
git add .
# Commit
git commit -m "Initial commit - Web Javaherbal"
# Add remote
git remote add origin https://github.com/flemss/frondend-web.git
# Push
git branch -M main
git push -u origin main
```
---
### 2️⃣ Deploy ke Vercel
#### A. Buka Vercel
1. Buka https://vercel.com
2. Klik **"Sign Up"** atau **"Login"**
3. Login dengan **GitHub**
#### B. Import Project
1. Klik **"Add New..."** → **"Project"**
2. Pilih **"Import Git Repository"**
3. Cari repository **"frondend-web"**
4. Klik **"Import"**
#### C. Configure Project
1. **Project Name:** `frondend-web` (atau nama lain)
2. **Framework Preset:** Vercel akan auto-detect **Vite**
3. **Root Directory:** `./` (default)
4. **Build Command:** `npm run build` (auto-filled)
5. **Output Directory:** `dist` (auto-filled)
6. **Install Command:** `npm install` (auto-filled)
#### D. Environment Variables (Opsional)
Jika ada environment variables, tambahkan di sini.
Untuk saat ini, tidak perlu karena API_URL sudah hardcoded.
#### E. Deploy!
1. Klik **"Deploy"**
2. Tunggu 1-2 menit
3. **Selesai!** 🎉
---
## 🌐 URL VERCEL
Setelah deploy selesai, Vercel akan memberikan URL seperti:
```
https://frondend-web.vercel.app
```
atau
```
https://frondend-web-flemss.vercel.app
```
---
## 🧪 TESTING
### 1. Buka URL Vercel
```
https://frondend-web.vercel.app
```
### 2. Test Register
1. Klik "Daftar di sini"
2. Isi form registrasi
3. Klik "Daftar"
4. **Expected:** Alert "Registrasi berhasil!" → Redirect ke login
### 3. Test Login
1. Isi form login
2. Klik "Masuk"
3. **Expected:** Redirect ke beranda
4. **Expected:** Floating stat suhu muncul
### 4. Test Control Panel
1. Klik menu "Control"
2. **Expected:** Panel kontrol muncul
3. **Expected:** Data suhu real-time
4. **Expected:** Toggle heater berfungsi
---
## 🔄 UPDATE WEB
Setiap kali ada perubahan code:
```bash
cd javaherbal-v2/javaherbal2
# Add changes
git add .
# Commit
git commit -m "Update: deskripsi perubahan"
# Push
git push origin main
```
**Vercel akan otomatis:**
- Detect perubahan di GitHub
- Build ulang
- Deploy versi baru
- Zero downtime!
---
## ⚙️ CUSTOM DOMAIN (Opsional)
Jika ingin pakai domain sendiri (contoh: `javaherbal.com`):
### 1. Beli Domain
- Namecheap, GoDaddy, Niagahoster, dll
### 2. Tambah Domain di Vercel
1. Buka project di Vercel dashboard
2. Klik tab **"Settings"**
3. Klik **"Domains"**
4. Klik **"Add"**
5. Masukkan domain Anda
6. Follow instruksi untuk update DNS
### 3. Update DNS
Di provider domain Anda, tambahkan record:
```
Type: CNAME
Name: www
Value: cname.vercel-dns.com
```
Tunggu 5-60 menit untuk propagasi DNS.
---
## 🔐 ENVIRONMENT VARIABLES (Jika Diperlukan)
Jika ingin API_URL bisa diubah tanpa rebuild:
### 1. Buat file `.env.production`
```bash
VITE_API_URL=https://web-production-32384.up.railway.app/api
```
### 2. Update code untuk pakai env variable
```typescript
// Sebelum
const API_URL = 'https://web-production-32384.up.railway.app/api'
// Sesudah
const API_URL = import.meta.env.VITE_API_URL || 'https://web-production-32384.up.railway.app/api'
```
### 3. Set di Vercel Dashboard
1. Buka project di Vercel
2. Klik tab **"Settings"**
3. Klik **"Environment Variables"**
4. Tambah:
- Key: `VITE_API_URL`
- Value: `https://web-production-32384.up.railway.app/api`
5. Save
### 4. Redeploy
Vercel akan auto redeploy dengan env variable baru.
---
## 📊 MONITORING
### Vercel Dashboard
https://vercel.com/dashboard
**Fitur:**
- ✅ Deployment history
- ✅ Build logs
- ✅ Analytics (traffic, performance)
- ✅ Error tracking
- ✅ Custom domains
- ✅ Environment variables
---
## 🔍 TROUBLESHOOTING
### Problem: Build Failed
**Solusi:**
1. Cek build logs di Vercel dashboard
2. Test build lokal:
```bash
npm run build
```
3. Fix error yang muncul
4. Push lagi ke GitHub
### Problem: 404 Not Found
**Solusi:**
1. Pastikan `vercel.json` ada dan benar
2. Pastikan rewrites sudah diset untuk SPA routing
3. Redeploy
### Problem: API Not Working
**Solusi:**
1. Cek backend Railway masih online
2. Cek CORS di backend
3. Cek API_URL di code
4. Cek browser console untuk error
---
## ✅ CHECKLIST
### Sebelum Deploy:
- [x] `.gitignore` sudah dibuat
- [x] `vercel.json` sudah dibuat
- [x] `package.json` script build ada
- [x] API_URL sudah diset ke Railway
- [ ] Test build lokal (`npm run build`)
- [ ] Push ke GitHub
### Setelah Deploy:
- [ ] URL Vercel bisa diakses
- [ ] Register berfungsi
- [ ] Login berfungsi
- [ ] Control panel berfungsi
- [ ] Data real-time muncul
---
## 🎉 SELESAI!
Web Javaherbal sekarang online di Vercel!
**Keuntungan:**
- ✅ Gratis unlimited
- ✅ Auto deploy dari GitHub
- ✅ HTTPS otomatis
- ✅ CDN global (cepat)
- ✅ Zero downtime deployment
- ✅ Custom domain support
**Selamat! Web Anda sekarang production-ready!** 🚀
---
## 📞 SUPPORT
### Vercel Documentation
https://vercel.com/docs
### Vite Documentation
https://vitejs.dev/guide/
### React Router Documentation
https://reactrouter.com/
---
**Created:** May 21, 2026
**Status:** ✅ Ready to Deploy

View File

@ -1,397 +0,0 @@
# 📚 Penjelasan Sistem Login Web Javaherbal
## 🔐 Sistem Penyimpanan Akun
Web Javaherbal menggunakan **localStorage** browser untuk menyimpan data akun dan status login.
---
## 📦 Apa itu localStorage?
**localStorage** adalah fitur browser yang memungkinkan website menyimpan data di komputer user secara permanen (tidak hilang saat browser ditutup).
### Karakteristik localStorage:
- ✅ Data disimpan di **browser user** (bukan di server)
- ✅ Data **tidak hilang** saat browser ditutup
- ✅ Data **tetap ada** sampai dihapus manual
- ✅ Kapasitas: ~5-10 MB per domain
- ✅ Format: Key-Value (string)
- ❌ **TIDAK AMAN** untuk data sensitif (password terlihat plain text)
---
## 🔄 Alur Sistem Login
### 1️⃣ REGISTRASI (Register)
**File:** `src/pages/Register.tsx`
#### Langkah-langkah:
1. User mengisi form:
- Nama lengkap
- Email
- Password (minimal 6 karakter)
- Konfirmasi password
2. Validasi:
```typescript
// Cek password cocok
if (password !== confirmPassword) {
setError('Password tidak cocok')
return
}
// Cek panjang password
if (password.length < 6) {
setError('Password minimal 6 karakter')
return
}
// Cek email sudah terdaftar
const users = JSON.parse(localStorage.getItem('users') || '[]')
if (users.find((u: any) => u.email === email)) {
setError('Email sudah terdaftar')
return
}
```
3. Simpan ke localStorage:
```typescript
// Buat user baru
const newUser = { name, email, password }
// Ambil array users yang sudah ada
const users = JSON.parse(localStorage.getItem('users') || '[]')
// Tambahkan user baru
users.push(newUser)
// Simpan kembali ke localStorage
localStorage.setItem('users', JSON.stringify(users))
```
4. Redirect ke halaman login
#### Contoh Data di localStorage:
```json
{
"users": [
{
"name": "John Doe",
"email": "john@example.com",
"password": "123456"
},
{
"name": "Jane Smith",
"email": "jane@example.com",
"password": "password123"
}
]
}
```
---
### 2️⃣ LOGIN
**File:** `src/pages/Login.tsx`
#### Langkah-langkah:
1. User mengisi form:
- Email
- Password
2. Validasi:
```typescript
// Ambil semua users dari localStorage
const users = JSON.parse(localStorage.getItem('users') || '[]')
// Cari user dengan email dan password yang cocok
const user = users.find((u: any) =>
u.email === email && u.password === password
)
if (user) {
// Login berhasil
localStorage.setItem('isAuthenticated', 'true')
localStorage.setItem('currentUser', JSON.stringify(user))
navigate('/')
} else {
// Login gagal
setError('Email atau password salah')
}
```
3. Jika berhasil:
- Set `isAuthenticated` = `'true'`
- Simpan data user ke `currentUser`
- Redirect ke halaman beranda
#### Data di localStorage Setelah Login:
```json
{
"users": [...],
"isAuthenticated": "true",
"currentUser": {
"name": "John Doe",
"email": "john@example.com",
"password": "123456"
}
}
```
---
### 3️⃣ CEK STATUS LOGIN
**File:** `src/components/ProtectedRoute.tsx`
#### Cara Kerja:
```typescript
const isAuthenticated = localStorage.getItem('isAuthenticated') === 'true'
if (!isAuthenticated) {
// Redirect ke login
return <Navigate to="/login" replace />
}
// Tampilkan halaman yang dilindungi
return <>{children}</>
```
#### Penggunaan:
```tsx
// Halaman yang perlu login
<Route
path="/control"
element={
<ProtectedRoute>
<Control />
</ProtectedRoute>
}
/>
```
---
### 4️⃣ LOGOUT
**File:** `src/components/Navbar.tsx` (kemungkinan)
#### Cara Kerja:
```typescript
function handleLogout() {
// Hapus status login
localStorage.removeItem('isAuthenticated')
localStorage.removeItem('currentUser')
// Redirect ke login
navigate('/login')
}
```
---
## 📊 Struktur Data di localStorage
### Key-Value Pairs:
| Key | Value | Deskripsi |
|-----|-------|-----------|
| `users` | `[{name, email, password}, ...]` | Array semua user yang terdaftar |
| `isAuthenticated` | `'true'` atau `'false'` | Status login user saat ini |
| `currentUser` | `{name, email, password}` | Data user yang sedang login |
### Contoh Lengkap:
```json
{
"users": [
{
"name": "Admin",
"email": "admin@javaherbal.com",
"password": "admin123"
},
{
"name": "User Test",
"email": "test@example.com",
"password": "test123"
}
],
"isAuthenticated": "true",
"currentUser": {
"name": "Admin",
"email": "admin@javaherbal.com",
"password": "admin123"
}
}
```
---
## 🔍 Cara Lihat Data di Browser
### Chrome / Edge:
1. Buka web di browser
2. Tekan **F12** (Developer Tools)
3. Klik tab **Application**
4. Di sidebar kiri, klik **Local Storage**
5. Pilih domain web (contoh: `http://localhost:5173`)
6. Lihat semua key-value yang tersimpan
### Firefox:
1. Buka web di browser
2. Tekan **F12** (Developer Tools)
3. Klik tab **Storage**
4. Di sidebar kiri, klik **Local Storage**
5. Pilih domain web
6. Lihat semua key-value yang tersimpan
---
## ⚠️ KELEMAHAN SISTEM INI
### 1. **Password Tidak Terenkripsi**
```json
{
"password": "123456" // ❌ Plain text, bisa dilihat siapa saja!
}
```
**Solusi:**
- Gunakan hashing (bcrypt, SHA-256)
- Simpan password di backend, bukan localStorage
### 2. **Data Bisa Dihapus User**
User bisa hapus localStorage via Developer Tools → semua akun hilang!
**Solusi:**
- Simpan data di backend (database)
- localStorage hanya untuk token/session
### 3. **Tidak Aman untuk Production**
localStorage bisa diakses oleh JavaScript → rentan XSS attack
**Solusi:**
- Gunakan backend API untuk autentikasi
- Simpan token di httpOnly cookie
- Implementasi JWT (JSON Web Token)
### 4. **Data Lokal per Browser**
Akun di Chrome tidak bisa diakses di Firefox (data terpisah)
**Solusi:**
- Gunakan backend database (MongoDB, PostgreSQL)
- Sinkronisasi data via API
---
## 🚀 REKOMENDASI UNTUK PRODUCTION
### Sistem Login yang Aman:
#### 1. **Backend API**
```
Frontend (React) → Backend API (Express) → Database (MongoDB)
```
#### 2. **Registrasi:**
```typescript
// Frontend
const response = await fetch('/api/auth/register', {
method: 'POST',
body: JSON.stringify({ name, email, password })
})
// Backend
const hashedPassword = await bcrypt.hash(password, 10)
await User.create({ name, email, password: hashedPassword })
```
#### 3. **Login:**
```typescript
// Frontend
const response = await fetch('/api/auth/login', {
method: 'POST',
body: JSON.stringify({ email, password })
})
const { token } = await response.json()
localStorage.setItem('token', token)
// Backend
const user = await User.findOne({ email })
const isValid = await bcrypt.compare(password, user.password)
if (isValid) {
const token = jwt.sign({ userId: user._id }, SECRET_KEY)
return { token }
}
```
#### 4. **Protected Routes:**
```typescript
// Frontend
const token = localStorage.getItem('token')
const response = await fetch('/api/protected', {
headers: { 'Authorization': `Bearer ${token}` }
})
// Backend
const token = req.headers.authorization?.split(' ')[1]
const decoded = jwt.verify(token, SECRET_KEY)
const user = await User.findById(decoded.userId)
```
---
## 📝 KESIMPULAN
### Sistem Saat Ini (localStorage):
- ✅ **Kelebihan:**
- Mudah implementasi
- Tidak perlu backend
- Cocok untuk prototype/demo
- Cepat
- ❌ **Kekurangan:**
- Tidak aman (password plain text)
- Data lokal (tidak sinkron antar device)
- Bisa dihapus user
- Tidak cocok untuk production
### Untuk Production:
- ✅ Gunakan backend API (Express + MongoDB)
- ✅ Hash password (bcrypt)
- ✅ Gunakan JWT untuk token
- ✅ Simpan token di httpOnly cookie
- ✅ Implementasi refresh token
- ✅ Rate limiting untuk prevent brute force
- ✅ HTTPS untuk enkripsi data
---
## 🎯 NEXT STEPS
Jika ingin upgrade ke sistem yang lebih aman:
1. **Buat Backend API untuk Auth**
- Endpoint: `/api/auth/register`
- Endpoint: `/api/auth/login`
- Endpoint: `/api/auth/logout`
- Endpoint: `/api/auth/me` (get current user)
2. **Gunakan MongoDB untuk Simpan User**
- Collection: `users`
- Schema: `{ name, email, password (hashed), createdAt }`
3. **Implementasi JWT**
- Generate token saat login
- Verify token di protected routes
- Refresh token untuk extend session
4. **Update Frontend**
- Ganti localStorage dengan API calls
- Simpan hanya token (bukan password)
- Handle token expiration
---
**Untuk saat ini, sistem localStorage sudah cukup untuk development/testing, tapi TIDAK AMAN untuk production!** 🔒

View File

@ -1,69 +0,0 @@
# 🚀 Push Web Javaherbal ke GitHub
## 📋 COMMAND SIAP PAKAI
Copy-paste command ini satu per satu:
### 1. Masuk ke Folder Web
```bash
cd javaherbal-v2/javaherbal2
```
### 2. Initialize Git
```bash
git init
```
### 3. Add All Files
```bash
git add .
```
### 4. Commit
```bash
git commit -m "Initial commit - Web Javaherbal dengan auth backend"
```
### 5. Add Remote (Repository: frondend-web)
```bash
git remote add origin https://github.com/flemss/frondend-web.git
```
### 6. Set Branch ke Main
```bash
git branch -M main
```
### 7. Push ke GitHub
```bash
git push -u origin main
```
---
## ✅ SELESAI!
Repository: https://github.com/flemss/frondend-web
**Next:** Deploy ke Vercel!
---
## 🔄 UPDATE SETELAH PUSH PERTAMA
Jika ada perubahan code:
```bash
cd javaherbal-v2/javaherbal2
# Add changes
git add .
# Commit
git commit -m "Update: deskripsi perubahan"
# Push
git push origin main
```
Vercel akan auto deploy! 🚀

View File

@ -1,31 +0,0 @@
# JavaHerbal 🌿
Website herbal modern dengan React + TypeScript + Vite.
## Cara Menjalankan
```bash
# 1. Install dependencies
npm install
# 2. Jalankan dev server
npm run dev
# → buka http://localhost:5173
# 3. Build production
npm run build
```
## Fitur
- Hero section dengan animasi
- Panel Kontrol: gauge SVG, toggle power, slider suhu, chart 24 jam (Recharts)
- Grid 6 produk dengan hover effects & keranjang belanja
- Footer lengkap dengan navigasi
- TypeScript strict-free (tidak ada error)
## Stack
- React 18 + TypeScript
- Vite 5
- Recharts
- Lucide React
- Google Fonts (Playfair Display + Plus Jakarta Sans)

View File

@ -1,245 +0,0 @@
# ✅ Update Web Javaherbal - Connected to Railway Backend
## 🎉 Yang Sudah Diupdate:
### 1. API Connection
- **Backend URL:** `https://web-production-32384.up.railway.app/api`
- **File:** `src/components/ControlPanel.tsx`
### 2. Fitur Baru:
#### ✅ Real-time Data
- Suhu update otomatis setiap 5 detik
- Data dari ESP32 via backend Railway
- Grafik menampilkan history 24 jam terakhir
#### ✅ Kontrol Manual Heater
- Toggle HEATER: ON/OFF
- Kirim kontrol ke backend → MQTT → ESP32
- Status heater real-time
#### ✅ Target Suhu (Setpoint)
- Slider untuk set target suhu (30-80°C)
- Kirim setpoint ke backend
- Update otomatis
### 3. Tampilan
- **TIDAK DIUBAH** - Tampilan tetap sama seperti sebelumnya
- Hanya fungsi backend yang ditambahkan
---
## 🚀 Cara Menjalankan
### 1. Install Dependencies (jika belum)
```bash
cd javaherbal-v2/javaherbal2
npm install
```
### 2. Jalankan Development Server
```bash
npm run dev
```
### 3. Buka Browser
```
http://localhost:5173
```
### 4. Login & Akses Control Panel
- Login dengan akun yang sudah terdaftar
- Klik menu "Control" atau akses `/control`
---
## 🎯 Fitur Control Panel
### Gauge Suhu
- Menampilkan suhu real-time dari ESP32
- Update setiap 5 detik
- Range: 0-100°C
### Toggle HEATER
- **ON:** Heater aktif (hijau)
- **OFF:** Heater nonaktif (abu-abu)
- Klik untuk toggle ON/OFF
- Kirim kontrol ke ESP32 via backend
### Slider Target Suhu
- Set target suhu: 30-80°C
- Drag slider untuk ubah setpoint
- Otomatis kirim ke backend
### Grafik Riwayat
- Menampilkan data 24 jam terakhir
- Update setiap 5 detik
- Hover untuk lihat detail
---
## 🔄 Data Flow
```
ESP32 (Publish MQTT)
↓
MQTT Broker (broker.hivemq.com)
↓
Backend Railway (Subscribe & Save)
↓
MongoDB Atlas (Store data)
↓
API Endpoint (/api/sensor/latest)
↓
Web Javaherbal (Fetch & Display)
```
### Kontrol Flow
```
Web Javaherbal (Toggle Heater)
↓
POST /api/sensor/control
↓
Backend Railway (Publish MQTT)
↓
MQTT Broker
↓
ESP32 (Receive & Execute)
```
---
## 🧪 Testing
### Test 1: Data Real-time
1. Buka web di browser
2. Login dan akses Control Panel
3. Lihat gauge suhu
4. **Expected:** Suhu muncul dan update setiap 5 detik
### Test 2: Kontrol Heater
1. Klik toggle HEATER
2. Lihat perubahan warna (hijau = ON, abu = OFF)
3. Cek di aplikasi mobile atau ESP32
4. **Expected:** Heater ON/OFF sesuai toggle
### Test 3: Set Target Suhu
1. Drag slider target suhu
2. Lihat angka berubah
3. **Expected:** Setpoint terkirim ke backend
### Test 4: Grafik History
1. Lihat grafik di panel kanan
2. Hover untuk lihat detail
3. **Expected:** Grafik menampilkan data 24 jam
---
## 🔍 Troubleshooting
### Problem: "Memuat data..." terus menerus
**Solusi:**
1. Cek backend Railway masih online:
```bash
curl https://web-production-32384.up.railway.app/api/sensor/latest
```
2. Cek browser console (F12) untuk error
3. Pastikan CORS enabled di backend
### Problem: Toggle heater tidak berfungsi
**Solusi:**
1. Cek network tab di browser (F12)
2. Lihat response dari POST /api/sensor/control
3. Cek backend logs di Railway
### Problem: Grafik kosong
**Solusi:**
1. Tunggu beberapa menit untuk data terkumpul
2. Cek ESP32 masih publish data
3. Cek MongoDB ada data
---
## 📊 API Endpoints yang Digunakan
### GET /api/sensor/latest
Fetch data sensor terbaru
```typescript
Response: {
success: true,
data: {
device: "esp32_cabai_01",
suhu: 27.8,
heater: true,
setpoint: 60
}
}
```
### GET /api/sensor/esp32_cabai_01?limit=24
Fetch history 24 data terakhir
```typescript
Response: {
success: true,
data: [
{
suhu: 27.8,
createdAt: "2026-05-19T14:45:58.139Z"
}
]
}
```
### POST /api/sensor/control
Kirim kontrol heater
```typescript
Body: {
mode: "MANUAL",
heater: true
}
Response: {
success: true,
message: "Kontrol relay berhasil dikirim"
}
```
### POST /api/sensor/setpoint
Set target suhu
```typescript
Body: {
setpoint: 60
}
Response: {
success: true,
message: "Setpoint berhasil diatur"
}
```
---
## ✅ Checklist
- [x] Connect ke backend Railway
- [x] Fetch data real-time
- [x] Display suhu di gauge
- [x] Toggle heater ON/OFF
- [x] Set target suhu
- [x] Display grafik history
- [x] Auto refresh setiap 5 detik
- [x] Error handling
- [x] Loading state
- [x] Tampilan tidak berubah
---
## 🎉 Selesai!
Web Javaherbal sekarang sudah terhubung dengan backend Railway dan bisa kontrol heater secara manual!
**Selamat menggunakan!** 🌶️

View File

@ -1,88 +0,0 @@
# ✅ Update Hero - Sembunyikan Status Suhu Jika Belum Login
## 🎯 Perubahan
### File yang Diubah:
- **`src/components/Hero.tsx`**
### Apa yang Diubah:
Floating stat "SUHU OPTIMAL 50°C – 70°C" di hero section sekarang **hanya tampil jika user sudah login**.
---
## 🔒 Logika
### Sebelum:
```tsx
{/* Floating stat */}
<div style={{ ... }}>
🌡️ SUHU OPTIMAL 50°C – 70°C
</div>
```
**Masalah:** Floating stat selalu tampil, bahkan jika user belum login.
### Sesudah:
```tsx
{/* Floating stat - Hanya tampil jika sudah login */}
{isAuthenticated && (
<div style={{ ... }}>
🌡️ SUHU OPTIMAL 50°C – 70°C
</div>
)}
```
**Solusi:** Floating stat hanya tampil jika `isAuthenticated === true`.
---
## 🧪 Testing
### Test 1: User Belum Login
1. Buka web di browser
2. Akses halaman beranda (/)
3. **Expected:** Floating stat suhu **TIDAK TAMPIL**
4. Hero section tetap tampil normal tanpa floating stat
### Test 2: User Sudah Login
1. Login dengan akun yang valid
2. Kembali ke halaman beranda (/)
3. **Expected:** Floating stat suhu **TAMPIL**
4. Menampilkan "SUHU OPTIMAL 50°C – 70°C"
### Test 3: Logout
1. Sudah login dan floating stat tampil
2. Logout dari aplikasi
3. Kembali ke halaman beranda
4. **Expected:** Floating stat suhu **TIDAK TAMPIL**
---
## 🔄 Cara Kerja
### Autentikasi
Web menggunakan `localStorage` untuk menyimpan status login:
```typescript
const isAuthenticated = localStorage.getItem('isAuthenticated') === 'true'
```
### Conditional Rendering
React akan render floating stat hanya jika `isAuthenticated === true`:
```tsx
{isAuthenticated && <FloatingStat />}
```
---
## 📊 Status
- ✅ Floating stat disembunyikan jika belum login
- ✅ Floating stat tampil jika sudah login
- ✅ Tampilan hero section tidak berubah
- ✅ Tidak ada perubahan pada halaman lain
---
## 🎉 Selesai!
Floating stat suhu sekarang hanya tampil untuk user yang sudah login!

View File

@ -1,186 +0,0 @@
# ✅ Update Responsive - Web Javaherbal
## 🎯 Perubahan
Web javaherbal sekarang sudah **responsive** dan tidak terpotong di HP!
---
## 📱 Yang Sudah Diupdate
### 1. **index.css**
- ✅ Prevent horizontal scroll
- ✅ Prevent text size adjustment di mobile
- ✅ Max-width 100% untuk semua elemen
- ✅ Responsive images
- ✅ Font size adjustment untuk mobile
- ✅ Prevent zoom on input focus (font-size 16px)
### 2. **Navbar.tsx**
- ✅ Responsive height: 64px → 56px (mobile)
- ✅ Responsive padding: 2rem → 1rem (mobile)
- ✅ **Hamburger menu di mobile** (icon Menu/X dari lucide-react)
- ✅ Mobile menu dropdown dengan semua navigation links
- ✅ Show user info di mobile menu
- ✅ Full-width login/logout button di mobile menu
- ✅ Auto-close menu saat route berubah
- ✅ Auto-close menu saat resize ke desktop
- ✅ Smooth transitions dan hover effects
- ✅ Active link highlighting di mobile menu
### 3. **Footer.tsx**
- ✅ Grid responsive: 4 kolom → 1 kolom (mobile)
- ✅ Padding responsive: 4rem 2rem → 3rem 1rem (mobile)
- ✅ Bottom bar: row → column (mobile)
- ✅ Smaller gaps di mobile
### 4. **Hero.tsx**
- ✅ Grid responsive: 2 kolom → 1 kolom (mobile)
- ✅ Padding responsive: 2rem → 1rem
### 5. **Dashboard.tsx**
- ✅ Section padding responsive: 5rem 2rem → 3rem 1rem (mobile)
- ✅ Grid auto-fit untuk cards
### 6. **ControlPanel.tsx**
- ✅ Grid responsive: 2 kolom → 1 kolom (mobile)
- ✅ Section padding responsive: 5rem 2rem → 3rem 1rem (mobile)
### 7. **Login.tsx & Register.tsx**
- ✅ Container padding responsive: 3rem → 2rem 1.5rem (mobile)
- ✅ Border radius responsive: 24px → 16px (mobile)
- ✅ Wrapper padding responsive: 2rem → 1rem (mobile)
### 8. **Products.tsx**
- ✅ Hero padding responsive: 4rem 2rem → 3rem 1rem (mobile)
- ✅ Section padding responsive: 4rem 2rem → 3rem 1rem (mobile)
- ✅ Filter layout: row → column (mobile)
- ✅ Grid responsive: auto-fill → 1 kolom (mobile)
- ✅ PaddingTop adjust dengan navbar mobile (56px)
### 9. **About.tsx**
- ✅ All section padding responsive: 5rem 2rem → 3rem 1rem (mobile)
- ✅ Timeline layout: 3 kolom → horizontal (mobile)
- ✅ Hide timeline line di mobile
- ✅ PaddingTop adjust dengan navbar mobile (56px)
---
## 📊 Breakpoints
### Desktop (> 768px)
- Navbar: 64px height
- Grid: 2-4 kolom
- Padding: 4-5rem 2rem
- Font size: Normal
- Show all navigation links
### Mobile (≤ 768px)
- Navbar: 56px height
- **Hamburger menu icon** (Menu/X toggle)
- **Mobile dropdown menu** dengan semua navigation links
- Grid: 1 kolom
- Padding: 3rem 1rem
- Font size: Smaller
- Input font: 16px (prevent zoom)
- Compact buttons
---
## 🔧 Implementasi
Semua komponen menggunakan:
```typescript
const [isMobile, setIsMobile] = useState(window.innerWidth <= 768)
React.useEffect(() => {
const handleResize = () => setIsMobile(window.innerWidth <= 768)
window.addEventListener('resize', handleResize)
return () => window.removeEventListener('resize', handleResize)
}, [])
```
Kemudian conditional rendering:
```typescript
style={{
padding: isMobile ? '1rem' : '2rem',
gridTemplateColumns: isMobile ? '1fr' : '1fr 1fr'
}}
```
---
## 🧪 Testing
### Desktop
1. Buka web di browser
2. Resize window
3. **Expected:** Layout adjust smoothly
### Tablet
1. Buka web di tablet atau resize browser ke 768px
2. **Expected:** Grid jadi 1 kolom
3. **Expected:** Padding lebih kecil
### Mobile
1. Buka web di HP
2. **Expected:** Hamburger menu icon (☰) muncul di kanan atas
3. **Expected:** Klik hamburger, dropdown menu muncul dengan semua links
4. **Expected:** Klik link, menu auto-close dan navigate
5. **Expected:** Tidak ada horizontal scroll
6. **Expected:** UI tidak terpotong
7. **Expected:** Text readable
8. **Expected:** Input tidak zoom saat focus
---
## ✅ Checklist
- [x] Prevent horizontal scroll
- [x] Responsive navbar (hide links, compact buttons)
- [x] **Hamburger menu untuk mobile navigation**
- [x] Mobile menu dropdown dengan semua links
- [x] Auto-close menu on route change
- [x] Responsive footer (4 col → 1 col)
- [x] Responsive grid (2-4 col → 1 col)
- [x] Responsive padding (all pages)
- [x] Responsive font size
- [x] Prevent zoom on input
- [x] Max-width 100% semua elemen
- [x] Responsive images
- [x] Responsive timeline (About page)
- [x] Responsive filter (Products page)
- [x] Responsive login/register forms
---
## 🎉 Selesai!
Web sekarang **fully responsive** dan mobile-friendly! 📱
Semua halaman sudah disesuaikan:
- ✅ Home (Hero, Dashboard)
- ✅ Products
- ✅ About
- ✅ Control Panel (gauge tidak terpotong)
- ✅ Login
- ✅ Register
- ✅ **Navbar dengan Hamburger Menu** 🍔
- ✅ Footer
## 🍔 Fitur Hamburger Menu
Di mobile (≤ 768px):
1. **Icon hamburger** (☰) muncul di kanan atas navbar
2. **Klik icon** → Dropdown menu muncul dari atas
3. **Menu berisi:**
- User info (jika login)
- Semua navigation links (Beranda, Produk, Tentang Kami)
- Control Panel link (jika login)
- Button Login/Logout
4. **Auto-close** saat:
- Klik link (navigate ke halaman lain)
- Resize window ke desktop
- Klik icon X
5. **Smooth animations** dan hover effects
6. **Active link highlighting** (warna hijau untuk halaman aktif)

View File

@ -1,5 +1,5 @@
import React, { useState } from 'react'
import { Leaf, Mail, Phone, MapPin, Instagram, Facebook, Youtube, LucideProps } from 'lucide-react'
import { Leaf, Mail, Phone, MapPin, LucideProps } from 'lucide-react'
// ── types ────────────────────────────────────────────────────────────────────
type IconComponent = React.FC<LucideProps>
@ -8,10 +8,8 @@ interface LinkColData { title: string; links: string[] }
interface ContactData { Icon: IconComponent; text: string }
// ── data ─────────────────────────────────────────────────────────────────────
const SOCIAL_ICONS: IconComponent[] = [Instagram, Facebook, Youtube]
const LINK_COLS: LinkColData[] = [
{ title: 'Produk', links: ['Rempah Kering','Jamu Tradisional', 'Paket Bundle'] },
{ title: 'Produk', links: ['Rempah Kering','Jamu Tradisional'] },
]
const CONTACT_ITEMS: ContactData[] = [
@ -46,27 +44,6 @@ function HoverLink({ children, dimColor = 'rgba(255,255,255,0.6)', size = '0.85r
)
}
function SocialBtn({ Icon }: { Icon: IconComponent }) {
const [hovered, setHovered] = useState(false)
return (
<button
style={{
width: '36px', height: '36px',
borderRadius: '8px',
background: hovered ? 'rgba(122,182,72,0.28)' : 'rgba(255,255,255,0.1)',
border: '1px solid rgba(255,255,255,0.15)',
display: 'flex', alignItems: 'center', justifyContent: 'center',
color: hovered ? '#7ab648' : 'rgba(255,255,255,0.7)',
cursor: 'pointer', transition: 'all 0.2s',
}}
onMouseEnter={() => setHovered(true)}
onMouseLeave={() => setHovered(false)}
>
<Icon size={16} />
</button>
)
}
function LinkCol({ title, links }: LinkColData) {
return (
<div>
@ -152,11 +129,6 @@ export default function Footer() {
>
Teknologi pengeringan untuk menjaga khasiat alami rempah Nusantara.
</p>
<div style={{ display: 'flex', gap: '10px' }}>
{SOCIAL_ICONS.map((Icon, i) => (
<SocialBtn key={i} Icon={Icon} />
))}
</div>
</div>
{/* Link columns */}