import React, { useState, useEffect } from 'react';
import {
Search, Menu, Phone, Mail, ChevronRight,
LogIn, Users, FileText, FileCheck, Upload,
Home, CheckCircle, Building, MapPin, AlertCircle,
ChevronLeft, ArrowRight, X, Calendar, Globe, Image as ImageIcon,
Loader, Plus, Trash2, Edit, Save, LayoutDashboard, LogOut,
Bell, BarChart3, HelpCircle, Key, Settings, UserPlus, Lock, ShieldAlert,
Info, Briefcase, ArrowUp, MessageCircle, List
} from 'lucide-react';
// --- CONSTANTS & DATA ---
// FIXED: Renamed to match state initialization
const INITIAL_SEARCH_OPTIONS = {
version: ["Versi 2.0", "Versi 3.0"],
category: ["Merit", "Terbuka", "Terus", "Bebas"],
type: ["Rumah Selangorku", "Komersial Mampu Milik", "Kedai / Industri Mampu Milik"],
district: ["Gombak", "Hulu Langat", "Hulu Selangor", "Klang", "Kuala Langat", "Kuala Selangor", "Petaling", "Sabak Bernam", "Sepang"]
};
const SEARCH_FIELDS = [
{ key: 'version', label: 'Versi Projek' },
{ key: 'category', label: 'Kategori' },
{ key: 'type', label: 'Jenis Projek' },
{ key: 'district', label: 'Daerah' }
];
const PROCESS_STEPS = [
{ id: 1, title: "Daftar", icon: Users, desc: "Daftar akaun pengguna" },
{ id: 2, title: "Mohon", icon: FileText, desc: "Pilih projek & mohon" },
{ id: 3, title: "Semakan", icon: FileCheck, desc: "Tapisan kelayakan LPHS" },
{ id: 4, title: "Dokumen", icon: Upload, desc: "Muat naik dokumen" },
{ id: 5, title: "Tawaran", icon: Mail, desc: "Terima surat tawaran" },
{ id: 6, title: "Miliki", icon: Home, desc: "Serahan kunci rumah" }
];
const STATISTICS = [
{ label: "Permohonan", value: "145,203", icon: FileText },
{ label: "Projek Lulus", value: "428", icon: CheckCircle },
{ label: "Unit Ditawar", value: "32,450", icon: Building },
{ label: "Pemilik", value: "28,900", icon: Key }
];
const FAQS = [
{ q: "Siapakah yang layak memohon Rumah Selangorku?", a: "Warganegara Malaysia berumur 18 tahun ke atas, pendapatan isi rumah tidak melebihi RM14,500, dan belum memiliki rumah di Selangor." },
{ q: "Berapa lama tempoh sah laku permohonan?", a: "Tempoh sah laku permohonan adalah selama 2 tahun. Pemohon perlu mengemaskini maklumat sekiranya terdapat perubahan." },
{ q: "Adakah saya boleh memilih lokasi rumah?", a: "Ya, pemohon boleh memilih daerah dan mukim yang dikehendaki semasa membuat permohonan dalam sistem." },
{ q: "Bagaimanakah cara untuk menyemak status permohonan?", a: "Status permohonan boleh disemak dengan log masuk ke akaun anda di portal ini dan melihat pada menu 'Semakan'." },
{ q: "Adakah saya perlu membayar sebarang yuran pendaftaran?", a: "Tiada sebarang yuran pendaftaran dikenakan oleh LPHS. Sila berhati-hati dengan pihak ketiga yang meminta bayaran." }
];
const INITIAL_AGENCIES = [
{ id: 1, name: "LPHS", logo: null },
{ id: 2, name: "MBSJ", logo: null },
{ id: 3, name: "MBSA", logo: null },
{ id: 4, name: "MPKj", logo: null },
{ id: 5, name: "MPSp", logo: null }
];
const INITIAL_PROJECTS = [
{
id: 1,
title: "RUMAH SELANGORKU IDAMAN SARI",
developer: "Permodalan Negeri Selangor Bhd",
location: "Puchong, Petaling",
full_address: "PT 12345, Jalan Puchong Utama, 47100 Puchong, Selangor.",
price: "RM 250,000.00",
type: "Rumah Selangorku",
status: "Buka",
details: {
pbt: "MBSJ", lease: "Leasehold", startDate: "2023-01-01", endDate: "2025-12-31",
developer_contact: "03-5510 2477", developer_email: "sales@pnsb.com.my", developer_pic: "En. Azlan"
},
gallery: [
"https://images.unsplash.com/photo-1580587771525-78b9dba3b91d?auto=format&fit=crop&q=80&w=600",
"https://images.unsplash.com/photo-1613490493576-7fde63acd811?auto=format&fit=crop&q=80&w=600",
"https://images.unsplash.com/photo-1512917774080-9991f1c4c750?auto=format&fit=crop&q=80&w=600"
]
},
{
id: 2,
title: "PANGSAPURI SERI KENANGA (JENIS C)",
developer: "Tetuan Hartanah Jaya Sdn Bhd",
location: "Serendah, Hulu Selangor",
full_address: "Lot 455, Mukim Serendah, Daerah Hulu Selangor.",
price: "RM 150,000.00",
type: "Rumah Selangorku",
status: "Terhad",
details: {
pbt: "MPHS", lease: "Freehold", startDate: "2022-03-15", endDate: "2025-03-15",
developer_contact: "03-6021 8888", developer_email: "enquiry@hartanahjaya.com", developer_pic: "Cik Sarah"
},
gallery: [
"https://images.unsplash.com/photo-1570129477492-45c003edd2be?auto=format&fit=crop&q=80&w=600",
"https://images.unsplash.com/photo-1560448204-e02f11c3d0e2?auto=format&fit=crop&q=80&w=600",
"https://images.unsplash.com/photo-1484154218962-a1c002085d2f?auto=format&fit=crop&q=80&w=600"
]
},
{
id: 3,
title: "RESIDENSI HARAPAN MULIA",
developer: "Cyberview Sdn Bhd",
location: "Cyberjaya, Sepang",
full_address: "Persiaran Apec, Cyber 8, 63000 Cyberjaya.",
price: "RM 200,000.00",
type: "Rumah Selangorku",
status: "Buka",
details: {
pbt: "MPSp", lease: "Freehold", startDate: "2023-06-10", endDate: "2026-06-10",
developer_contact: "03-8315 6111", developer_email: "sales@cyberview.com.my", developer_pic: "Mr. Tan"
},
gallery: [
"https://images.unsplash.com/photo-1564013799919-ab600027ffc6?auto=format&fit=crop&q=80&w=600",
"https://images.unsplash.com/photo-1574362848149-11496d93a7c7?auto=format&fit=crop&q=80&w=600",
"https://images.unsplash.com/photo-1592595896551-12b371d546d5?auto=format&fit=crop&q=80&w=600"
]
},
{
id: 4,
title: "VISTA PERDANA",
developer: "Gamuda Land",
location: "Kuala Langat",
full_address: "Bandar Rimbayu, 42500 Telok Panglima Garang.",
price: "RM 180,000.00",
type: "Rumah Selangorku",
status: "Buka",
details: {
pbt: "MPKL", lease: "Leasehold", startDate: "2023-10-10", endDate: "2026-10-10",
developer_contact: "03-5112 3333", developer_email: "rimbayu@gamudaland.com.my", developer_pic: "En. Hakim"
},
gallery: [
"https://images.unsplash.com/photo-1568605114967-8130f3a36994?auto=format&fit=crop&q=80&w=600",
"https://images.unsplash.com/photo-1570129477492-45c003edd2be?auto=format&fit=crop&q=80&w=600",
"https://images.unsplash.com/photo-1512915922686-57c11dde9b6b?auto=format&fit=crop&q=80&w=600"
]
},
{
id: 5,
title: "IDAMAN ABADI",
developer: "Tropicana Corp",
location: "Kajang 2",
full_address: "Persiaran Tropicana Heights, 43000 Kajang.",
price: "RM 250,000.00",
type: "Rumah Idaman",
status: "Terhad",
details: {
pbt: "MPKj", lease: "Freehold", startDate: "2022-06-05", endDate: "2025-06-05",
developer_contact: "03-8733 8888", developer_email: "enquiry@tropicanacorp.com.my", developer_pic: "Mr. Lee"
},
gallery: [
"https://images.unsplash.com/photo-1600596542815-60c37c663045?auto=format&fit=crop&q=80&w=600",
"https://images.unsplash.com/photo-1513584685908-95c9e2d01361?auto=format&fit=crop&q=80&w=600"
]
},
{
id: 6,
title: "SELANGORKU MAKMUR",
developer: "MBI Selangor",
location: "Klang",
full_address: "Jalan Meru, 41050 Klang.",
price: "RM 42,000.00",
type: "Rumah Selangorku",
status: "Buka",
details: {
pbt: "MBDK", lease: "Leasehold", startDate: "2024-03-01", endDate: "2027-03-01",
developer_contact: "03-3371 1111", developer_email: "sales@mbiselangor.com.my", developer_pic: "Cik Nurul"
},
gallery: ["https://images.unsplash.com/photo-1582268611958-ebfd161ef9cf?auto=format&fit=crop&q=80&w=600",
"https://images.unsplash.com/photo-1584622050111-993a426fbf0a?auto=format&fit=crop&q=80&w=600"]
},
{
id: 7,
title: "PANGSAPURI MAWAR",
developer: "Eco World",
location: "Semenyih, Hulu Langat",
full_address: "Eco Majestic, 43500 Semenyih, Selangor.",
price: "RM 100,000.00",
type: "Rumah Selangorku",
status: "Buka",
details: {
pbt: "MPKj", lease: "Freehold", startDate: "2023-09-15", endDate: "2026-09-15",
developer_contact: "03-8723 2255", developer_email: "eco.majestic@ecoworld.my", developer_pic: "Mr. Chan"
},
gallery: [
"https://images.unsplash.com/photo-1560185007-cde436f6a4d0?auto=format&fit=crop&q=80&w=600",
"https://images.unsplash.com/photo-1560185893-a55cbc8c5768?auto=format&fit=crop&q=80&w=600"
]
},
{
id: 8,
title: "RESIDENSI BAYU",
developer: "Sime Darby Property",
location: "Sg Besar",
full_address: "Jalan Bernam, 45300 Sungai Besar, Selangor.",
price: "RM 150,000.00",
type: "Rumah Selangorku",
status: "Buka",
details: {
pbt: "MDSB", lease: "Leasehold", startDate: "2023-11-20", endDate: "2026-11-20",
developer_contact: "03-3224 2222", developer_email: "enquiry@simedarby.com", developer_pic: "En. Hafiz"
},
gallery: [
"https://images.unsplash.com/photo-1568605114967-8130f3a36994?auto=format&fit=crop&q=80&w=600",
"https://images.unsplash.com/photo-1570129477492-45c003edd2be?auto=format&fit=crop&q=80&w=600"
]
}
];
// --- COMPONENTS ---
const ConditionsModal = ({ onClose }) => (
Syarat Kelayakan Penuh
1. Syarat Umum
Warganegara Malaysia.
Berumur 18 tahun ke atas.
Pemohon dan pasangan tidak memiliki sebarang jenis rumah di Negeri Selangor.
Pemohon bujang yang mempunyai tanggungan keluarga layak memohon.
2. Had Pendapatan Isi Rumah (Bulanan)
Rumah Selangorku Jenis A
Tidak melebihi RM3,000.00
Rumah Selangorku Jenis B, C, D, E
Tidak melebihi RM14,500.00
Dokumen sokongan seperti penyata gaji, penyata KWSP, dan salinan kad pengenalan wajib dimuat naik semasa permohonan dibuat.
Tutup
);
const AdminDashboard = ({
projects, setProjects,
users, setUsers,
config, setConfig,
agencies, setAgencies,
searchOptions, setSearchOptions,
onLogout
}) => {
const [activeTab, setActiveTab] = useState('projects');
const [isEditing, setIsEditing] = useState(false);
const [currentProject, setCurrentProject] = useState(null);
const [previewImages, setPreviewImages] = useState([]);
const [newUser, setNewUser] = useState({ username: '', password: '' });
const [selectedField, setSelectedField] = useState('district');
const [newValue, setNewValue] = useState('');
// --- PROJECT HANDLERS ---
const handleAddNew = () => {
setCurrentProject({
id: Date.now(),
title: "", developer: "", location: "", full_address: "", price: "RM ", type: "Rumah Selangorku", status: "Buka",
details: { pbt: "", lease: "Leasehold", startDate: "", endDate: "", developer_contact: "", developer_email: "", developer_pic: "" },
gallery: []
});
setPreviewImages([]);
setIsEditing(true);
};
const handleEdit = (project) => {
setCurrentProject({ ...project });
setPreviewImages(project.gallery || []);
setIsEditing(true);
};
const handleDelete = (id) => {
if (window.confirm("Adakah anda pasti mahu memadam projek ini?")) setProjects(prev => prev.filter(p => p.id !== id));
};
const handleSave = (e) => {
e.preventDefault();
const projectToSave = { ...currentProject, gallery: previewImages };
setProjects(prev => {
const exists = prev.find(p => p.id === projectToSave.id);
return exists ? prev.map(p => p.id === projectToSave.id ? projectToSave : p) : [...prev, projectToSave];
});
setIsEditing(false);
};
const handleImageUpload = (e) => {
if (e.target.files) {
const files = Array.from(e.target.files);
const newImages = files.map(file => URL.createObjectURL(file));
setPreviewImages(prev => [...prev, ...newImages]);
}
};
// --- USER HANDLERS ---
const handleAddUser = () => {
if(newUser.username && newUser.password) {
setUsers([...users, { id: Date.now(), ...newUser }]);
setNewUser({ username: '', password: '' });
alert("Pengguna ditambah!");
}
};
const handleDeleteUser = (id) => {
if(window.confirm("Padam pengguna?")) setUsers(users.filter(u => u.id !== id));
};
// --- AGENCY HANDLERS ---
const handleAgencyUpload = (e) => {
if (e.target.files[0]) {
const newAgency = {
id: Date.now(),
name: "Agensi Baru",
logo: URL.createObjectURL(e.target.files[0])
};
setAgencies([...agencies, newAgency]);
}
};
const handleDeleteAgency = (id) => {
if(window.confirm("Padam agensi ini?")) setAgencies(agencies.filter(a => a.id !== id));
};
// --- SEARCH OPTIONS HANDLERS ---
const handleAddSearchOption = () => {
if (newValue.trim()) {
setSearchOptions(prev => ({
...prev,
[selectedField]: [...prev[selectedField], newValue]
}));
setNewValue('');
}
};
const handleDeleteSearchOption = (valToDelete) => {
if(window.confirm("Padam pilihan ini?")) {
setSearchOptions(prev => ({
...prev,
[selectedField]: prev[selectedField].filter(val => val !== valToDelete)
}));
}
};
// --- SETTING HANDLERS ---
const handleLogoUpload = (e) => {
if(e.target.files[0]) setConfig({...config, logo: URL.createObjectURL(e.target.files[0])});
};
const handleHeroUpload = (e) => {
if(e.target.files[0]) setConfig({...config, heroImage: URL.createObjectURL(e.target.files[0])});
};
if (isEditing) {
return (
{currentProject.title ? "Kemaskini Projek" : "Tambah Projek Baru"}
setIsEditing(false)} className="text-gray-400 hover:text-white">
);
}
return (
LPHS Admin Sistem Pengurusan
setActiveTab('projects')} className={`w-full flex items-center gap-3 px-4 py-3 rounded text-sm font-bold ${activeTab==='projects'?'bg-[#d00000]':'hover:bg-gray-700'}`}> Projek
setActiveTab('search')} className={`w-full flex items-center gap-3 px-4 py-3 rounded text-sm font-bold ${activeTab==='search'?'bg-[#d00000]':'hover:bg-gray-700'}`}>
Carian
setActiveTab('users')} className={`w-full flex items-center gap-3 px-4 py-3 rounded text-sm font-bold ${activeTab==='users'?'bg-[#d00000]':'hover:bg-gray-700'}`}> Pengguna
setActiveTab('agencies')} className={`w-full flex items-center gap-3 px-4 py-3 rounded text-sm font-bold ${activeTab==='agencies'?'bg-[#d00000]':'hover:bg-gray-700'}`}> Agensi
setActiveTab('settings')} className={`w-full flex items-center gap-3 px-4 py-3 rounded text-sm font-bold ${activeTab==='settings'?'bg-[#d00000]':'hover:bg-gray-700'}`}> Tetapan
Log Keluar
{/* PROJECTS TAB */}
{activeTab === 'projects' && (
<>
Senarai Projek Hartanah Tambah Projek
ID Projek Lokasi Status Tindakan
{projects.map((project) => (
#{project.id.toString().slice(-4)}
{project.title}
{project.location}
{project.status}
handleEdit(project)} className="p-2 text-blue-600 hover:bg-blue-50 rounded"> handleDelete(project.id)} className="p-2 text-red-600 hover:bg-red-50 rounded">
))}
>
)}
{/* CARIAN TAB (NEW) */}
{activeTab === 'search' && (
<>
Pengurusan Carian
{/* Selector */}
Pilih Kategori untuk Disunting
{SEARCH_FIELDS.map(field => (
setSelectedField(field.key)}
className={`px-4 py-2 rounded-full text-sm font-bold whitespace-nowrap transition-colors ${selectedField === field.key ? 'bg-[#d00000] text-white' : 'bg-gray-100 text-gray-600 hover:bg-gray-200'}`}
>
{field.label}
))}
{/* Add New */}
{/* List */}
{searchOptions[selectedField]?.map((option, index) => (
{option}
handleDeleteSearchOption(option)} className="text-gray-400 hover:text-red-600 opacity-0 group-hover:opacity-100 transition-opacity">
))}
>
)}
{/* USERS TAB */}
{activeTab === 'users' && (
<>
Pengurusan Admin
ID Kata Laluan Tindakan
{users.map(u => ({u.username} {u.password} handleDeleteUser(u.id)} className="text-red-600 hover:bg-red-50 px-3 py-1 rounded text-xs font-bold border border-red-200">Padam ))}
>
)}
{/* AGENCIES TAB */}
{activeTab === 'agencies' && (
<>
Agensi Kerjasama
{agencies.map(agency => (
handleDeleteAgency(agency.id)} className="absolute top-2 right-2 bg-red-600 text-white p-1 rounded-full opacity-0 group-hover:opacity-100 transition-opacity">
{agency.logo ?
:
{agency.name}
}
{agency.name}
))}
>
)}
{/* SETTINGS TAB */}
{activeTab === 'settings' && (
<>
Tetapan Sistem
>
)}
);
};
// --- PUBLIC COMPONENTS ---
const Header = ({ config, onLoginRequest }) => (
Portal Rasmi Kerajaan Negeri Selangor | +603-5510 2177
{config.name}
Lembaga Perumahan dan Hartanah Selangor
{["Laman Utama", "Maklumat", "Manual", "Muat Turun", "Hubungi Kami"].map(link =>
{link} )}
);
const HeroSection = ({ config }) => (
Terkini
Pemberitahuan: Sistem akan mengalami penyelenggaraan berjadual pada 12 Disember 2024.
);
const SearchWidget = ({ whatsappNumber, searchOptions }) => {
const [criteria, setCriteria] = useState({ version: '', category: '', type: '', district: '' });
const handleSearch = () => {
if (!criteria.version || !criteria.category || !criteria.type || !criteria.district) {
alert("Sila pilih sekurang-kurangnya satu kriteria carian.");
return;
}
const message =
`Salam, saya berminat untuk membuat semakan projek hartanah dengan kriteria berikut:%0a%0a` +
`📌 *Versi Projek:* ${criteria.version || 'Semua'}%0a` +
`📌 *Kategori:* ${criteria.category || 'Semua'}%0a` +
`📌 *Jenis Projek:* ${criteria.type || 'Semua'}%0a` +
`📌 *Daerah:* ${criteria.district || 'Semua'}%0a%0a` +
`Mohon bantuan pihak tuan/puan untuk semakan lanjut. Terima kasih.`;
window.open(`https://wa.me/${whatsappNumber}?text=${message}`, '_blank');
};
const handleReset = () => {
setCriteria({ version: '', category: '', type: '', district: '' });
};
return (
Carian Projek Hartanah
{SEARCH_FIELDS.map((field) => (
{field.label}
setCriteria({...criteria, [field.key]: e.target.value})}
className="w-full border p-2.5 text-sm rounded focus:ring-1 focus:ring-[#d00000] outline-none"
>
Pilih
{searchOptions[field.key]?.map(o=>{o} )}
))}
Set Semula
Hantar WhatsApp
);
};
const FAQSection = () => {
const [showAll, setShowAll] = useState(false);
const visibleFaqs = showAll ? FAQS : FAQS.slice(0, 3);
const allFaqs = [
...FAQS,
{ q: "Bagaimanakah cara untuk menyemak status permohonan?", a: "Status permohonan boleh disemak dengan log masuk ke akaun anda di portal ini dan melihat pada menu 'Semakan'." },
{ q: "Adakah saya perlu membayar sebarang yuran pendaftaran?", a: "Tiada sebarang yuran pendaftaran dikenakan oleh LPHS. Sila berhati-hati dengan pihak ketiga yang meminta bayaran." },
{ q: "Bolehkah saya memohon jika saya bekerja sendiri?", a: "Boleh. Anda perlu menyertakan dokumen sokongan pendapatan seperti penyata bank 6 bulan terkini dan pendaftaran perniagaan (SSM) jika ada." }
];
const displayFaqs = showAll ? allFaqs : allFaqs.slice(0, 3);
return (
Soalan Lazim
{displayFaqs.map((faq, i) => (
))}
setShowAll(!showAll)} className="text-[#d00000] font-bold text-sm border-b border-[#d00000] pb-1 hover:text-red-800 transition-colors">
{showAll ? "Tutup Soalan Lazim" : "Lihat Lagi Soalan Lazim"}
);
};
const AgenciesSection = ({ agencies }) => (
Agensi Kerjasama
{agencies?.map(agency => (
agency.logo ?
:
{agency.name}
))}
);
const ProjectModal = ({ project, onClose }) => {
if (!project) return null;
const images = project.gallery && project.gallery.length > 0 ? project.gallery : ["https://images.unsplash.com/photo-1580587771525-78b9dba3b91d?auto=format&fit=crop&q=80&w=600"];
const details = project.details || {};
const handleWhatsApp = () => {
const phone = "60186609796";
const message = `Salam, saya berminat untuk mengetahui lebih lanjut mengenai projek *${project.title}* oleh *${project.developer}*.`;
window.open(`https://wa.me/${phone}?text=${encodeURIComponent(message)}`, '_blank');
};
return (
{project.title} {project.full_address}
Maklumat Projek
Harga Bermula
{project.price}
Jenis Projek
{project.type}
Pegangan
{details.lease || '-'}
Jangka Mula
{details.startDate || '-'}
Jangka Siap
{details.endDate || '-'}
Galeri Projek
{images.map((img, index) => (
))}
Maklumat Pemaju
Nama Pemaju
{project.developer}
No. Telefon
{details.developer_contact || '-'}
Emel
{details.developer_email || '-'}
Hubungi via WhatsApp
);
}
const ProjectCard = ({ project, onSelect }) => {
const imageSrc = project.gallery && project.gallery.length > 0 ? project.gallery[0] : "https://images.unsplash.com/photo-1580587771525-78b9dba3b91d?auto=format&fit=crop&q=80&w=600";
return (
{project.status}
{project.type}
onSelect(project)} className="text-gray-900 font-bold text-sm mb-3 line-clamp-2 leading-snug group-hover:text-[#d00000] transition-colors cursor-pointer">{project.title}
{project.developer}
{project.location}
Harga Mula
{project.price}
onSelect(project)} className="text-white text-xs font-bold bg-gray-900 px-4 py-2 rounded hover:bg-[#d00000] transition-colors">Lihat
);
};
// --- FLOATING CONTROLS ---
const FloatingControls = ({ whatsappNumber }) => {
const [showScrollTop, setShowScrollTop] = useState(false);
useEffect(() => {
const checkScroll = () => {
if (window.scrollY > 300) setShowScrollTop(true);
else setShowScrollTop(false);
};
window.addEventListener('scroll', checkScroll);
return () => window.removeEventListener('scroll', checkScroll);
}, []);
const scrollToTop = () => {
window.scrollTo({ top: 0, behavior: 'smooth' });
};
return (
);
};
// --- MAIN APP COMPONENT ---
export default function App() {
const [view, setView] = useState('public');
const [projects, setProjects] = useState(INITIAL_PROJECTS);
const [selectedProject, setSelectedProject] = useState(null);
const [visibleCount, setVisibleCount] = useState(6);
const [showConditions, setShowConditions] = useState(false);
const [adminUser, setAdminUser] = useState('');
const [adminPass, setAdminPass] = useState('');
const [isLockedOut, setIsLockedOut] = useState(false);
const [loginAttempts, setLoginAttempts] = useState(0);
const [captcha, setCaptcha] = useState({ q: "5 + 3", a: 8 });
const [captchaInput, setCaptchaInput] = useState('');
// Admin State Management
const [users, setUsers] = useState([{id: 1, username: 'admin', password: 'admin'}]);
const [agencies, setAgencies] = useState(INITIAL_AGENCIES);
const [searchOptions, setSearchOptions] = useState(INITIAL_SEARCH_OPTIONS); // NEW: Search Options State
const [config, setConfig] = useState({
name: "SISTEM PERMOHONAN HARTANAH \nNEGERI SELANGOR",
logo: "https://upload.wikimedia.org/wikipedia/commons/e/ee/Coat_of_arms_of_Selangor.svg",
heroImage: "https://images.unsplash.com/photo-1486406146926-c627a92ad1ab?auto=format&fit=crop&q=80&w=2000",
whatsapp: "60186609796"
});
useEffect(() => {
generateCaptcha();
}, []);
const generateCaptcha = () => {
const a = Math.floor(Math.random() * 10);
const b = Math.floor(Math.random() * 10);
setCaptcha({ q: `${a} + ${b}`, a: a + b });
setCaptchaInput('');
};
const handleAdminLogin = (e) => {
e.preventDefault();
if (isLockedOut) return;
if (parseInt(captchaInput) !== captcha.a) {
alert("Captcha salah! Sila cuba lagi.");
generateCaptcha();
return;
}
const user = users.find(u => u.username === adminUser && u.password === adminPass);
if (user) {
setView('admin');
setLoginAttempts(0);
} else {
const newAttempts = loginAttempts + 1;
setLoginAttempts(newAttempts);
alert(`ID atau Kata Laluan salah! Percubaan ${newAttempts}/3`);
if (newAttempts >= 3) {
setIsLockedOut(true);
alert("Akaun dikunci selama 30 saat kerana terlalu banyak percubaan gagal.");
setTimeout(() => {
setIsLockedOut(false);
setLoginAttempts(0);
}, 30000);
}
}
};
const handleAdminLogout = () => {
setView('public');
setAdminUser('');
setAdminPass('');
};
if (view === 'admin') {
return (
);
}
if (view === 'login') return (
setView('public')} className="absolute top-4 right-4 text-gray-400 hover:text-black">
Log Masuk Admin
Sistem Pengurusan LPHS
{isLockedOut ? (
Akaun Dikunci
Sila tunggu 30 saat.
) : (
)}
);
return (
setView('login')} />
{selectedProject && setSelectedProject(null)} />}
{showConditions && setShowConditions(false)} />}
{/* Floating Controls */}
Proses Permohonan
Panduan langkah demi langkah untuk memiliki kediaman anda
{PROCESS_STEPS.map(step => {
const Icon = step.icon;
return (
);
})}
Syarat Kelayakan
{[{t:"Warganegara", d:"Malaysia"}, {t:"Umur", d:"18 Tahun Ke Atas"}, {t:"Pendapatan", d:"Tidak Lebih RM14,500"}].map((c, i) => (
{c.t} {c.d}
))}
setShowConditions(true)}
className="text-[#d00000] font-bold text-xs uppercase border border-[#d00000] px-4 py-2 rounded hover:bg-[#d00000] hover:text-white w-full transition-colors"
>
Baca Syarat Penuh
Senarai Projek Terkini
{projects.slice(0, visibleCount).map((project) => (
))}
{visibleCount < projects.length && (
setVisibleCount(prev => prev + 6)}
className="bg-white border border-gray-300 hover:border-[#d00000] text-gray-700 hover:text-[#d00000] px-8 py-3 rounded-full font-bold text-sm shadow-sm flex items-center justify-center gap-2 transition-all active:scale-95 w-full sm:w-auto"
>
Muat Lebih Banyak
)}
);
}