<script src="https://www.gstatic.com/firebasejs/10.7.0/firebase-app-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/10.7.0/firebase-firestore-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/10.7.0/firebase-auth-compat.js"></script>
<style>
body { font-family: sans-serif; padding:10px; }
input, button {
width:100%;
padding:8px;
margin:5px 0;
}
.grid {
display:grid;
grid-template-columns:repeat(7,1fr);
gap:5px;
}
.day {
height:45px;
display:flex;
align-items:center;
justify-content:center;
border-radius:6px;
cursor:pointer;
}
.FREE { background:#ddd; }
.HOLD { background:orange; }
.BOOKED { background:red; color:white; }
.box {
border:1px solid #ccc;
padding:10px;
margin:5px 0;
}
</style>
Đăng nhập
Đăng nhập
<script>
// CONFIG
const firebaseConfig = {
apiKey: "AIzaSyDs66yXaVeVSyq7hGENDQbbC-uBHLinH8E",
authDomain: "villa-537c8.firebaseapp.com",
projectId: "villa-537c8"
};
firebase.initializeApp(firebaseConfig);
const db = firebase.firestore();
const auth = firebase.auth();
let mode = "sale";
let villa_id = null;
// LOGIN
async function login(){
let email = emailInput.value;
let password = passwordInput.value;
try{
await auth.signInWithEmailAndPassword(email,password);
let snap = await db.collection("users")
.where("email","==",email).get();
snap.forEach(doc=>{
mode = doc.data().role;
});
loginBox.style.display="none";
app.style.display="block";
init();
}catch(e){
alert("Sai tài khoản");
}
}
// INIT
function init(){
if(mode==="owner") ownerUI();
else saleUI();
}
// OWNER UI
function ownerUI(){
app.innerHTML = `
Thêm villa
Lưu
Danh sách
Lịch
`;
loadOwner();
}
function addVilla(){
db.collection("villas").add({
name: name.value,
district: district.value,
bedrooms: parseInt(bedrooms.value),
price: parseInt(price.value)
});
alert("Đã thêm");
loadOwner();
}
function loadOwner(){
db.collection("villas").get().then(snap=>{
let html="";
snap.forEach(doc=>{
let v=doc.data();
html += `
${v.name} - ${v.price}
`;
});
list.innerHTML = html;
});
}
// SALE UI
function saleUI(){
app.innerHTML = `
Villa
Lịch
`;
loadOwner();
}
// CHỌN VILLA
function selectVilla(id){
villa_id = id;
listenCal();
}
// LISTEN
function listenCal(){
db.collection("availability")
.where("villa_id","==",villa_id)
.onSnapshot(snap=>{
let map={};
snap.forEach(doc=>{
let d=doc.data();
map[d.date]=d;
});
render(map);
});
}
// RENDER
function render(data){
cal.innerHTML="";
for(let i=1;i<=31;i++){
let date = `2026-04-${String(i).padStart(2,"0")}`;
let d = data[date] || {status:"FREE"};
let div=document.createElement("div");
div.className="day "+d.status;
div.innerText=i;
div.onclick=()=>hold(date);
cal.appendChild(div);
}
}
// HOLD
async function hold(date){
let ref = db.collection("availability").doc(villa_id+"_"+date);
await db.runTransaction(async (tx)=>{
let doc = await tx.get(ref);
if(!doc.exists || doc.data().status==="FREE"){
tx.set(ref,{
villa_id,
date,
status:"HOLD",
expire_time: Date.now()+15*60*1000
});
} else {
alert("Đã có người giữ");
}
});
}
</script>
Đăng nhập
Đăng nhậpThêm villa
LưuDanh sách
Lịch
`; loadOwner(); } function addVilla(){ db.collection("villas").add({ name: name.value, district: district.value, bedrooms: parseInt(bedrooms.value), price: parseInt(price.value) }); alert("Đã thêm"); loadOwner(); } function loadOwner(){ db.collection("villas").get().then(snap=>{ let html=""; snap.forEach(doc=>{ let v=doc.data(); html += `Villa
Lịch
`; loadOwner(); } // CHỌN VILLA function selectVilla(id){ villa_id = id; listenCal(); } // LISTEN function listenCal(){ db.collection("availability") .where("villa_id","==",villa_id) .onSnapshot(snap=>{ let map={}; snap.forEach(doc=>{ let d=doc.data(); map[d.date]=d; }); render(map); }); } // RENDER function render(data){ cal.innerHTML=""; for(let i=1;i<=31;i++){ let date = `2026-04-${String(i).padStart(2,"0")}`; let d = data[date] || {status:"FREE"}; let div=document.createElement("div"); div.className="day "+d.status; div.innerText=i; div.onclick=()=>hold(date); cal.appendChild(div); } } // HOLD async function hold(date){ let ref = db.collection("availability").doc(villa_id+"_"+date); await db.runTransaction(async (tx)=>{ let doc = await tx.get(ref); if(!doc.exists || doc.data().status==="FREE"){ tx.set(ref,{ villa_id, date, status:"HOLD", expire_time: Date.now()+15*60*1000 }); } else { alert("Đã có người giữ"); } }); } </script>