2
HAPPENHAUS
Every Occasion, Perfectly Crafted
Hyderabad · Est. 2012
🔧 We are performing scheduled maintenance. The site will be back shortly. Thank you for your patience.
Services Gallery Reviews Book Now
✦ Hyderabad's Premier Celebration Studio

Where Every
Moment Becomes
Extraordinary

Bespoke decor, world-class catering, immersive lighting & photography — all under one roof for your perfect celebration.

What We Do

Curated Services
For Every Occasion

Request a Quote →
How It Works

Simple Steps to Your Dream Event

01
Enquire
Fill out our booking form with your event details and vision.
02
Consult
Our specialist calls within 24 hours to craft your perfect plan.
03
Design
We create mood boards, timelines & a bespoke customised proposal.
04
Celebrate
We execute flawlessly while you enjoy every magical moment.
Get In Touch

Let's Create
Something Beautiful

Ready to turn your vision into reality? Sign in or create an account. Our HAPPENHAUS specialists reach out within 24 hours.

What We Offer
🌸 Luxury Decor 📷 Photography 🎵 Live Music ✨ Lighting Design 🎊 Full Event Management 💍 Wedding Planning 🎂 Birthday & Celebrations 🏢 Corporate Events
📍
Jubilee Hills, Hyderabad, Telangana
📞
+91 7386030321
✉️
happenhaus.in@gmail.com
🕐
Mon–Sat: 10 AM – 7 PM
🔐
Sign In to Book

Create a free account or sign in to submit your booking request and track it in real time.

why sign in?
📋 Track bookings live 🔔 Get status updates ✏️ Modify requests 💰 See final pricing
⚠️ You already have a pending or confirmed booking for this service. Please modify your existing booking or contact us.
Client Stories

Reviews & Ratings

Loading reviews…
Loading reviews…
Gallery
2 HAPPENHAUS
Welcome
Sign in or create a free account to book your event

Profile Settings

?

Modify Booking

Update your booking details. Changes will be reviewed by our team.

🎊 Event Completed

Share Your Experience

Your story inspires families across Hyderabad. Tell us how we did — it only takes a minute.

Chat on WhatsApp
Call Us Now
in . For GitHub Pages / static hosting: use a CI secret to generate config.js at build time (GitHub Actions example): echo "window.__HH_CFG__={apiKey:'${{ secrets.FB_API_KEY }}',...}" > config.js NEVER hardcode real values below. ───────────────────────────────────────────────────────────── */ const firebaseConfig = (window.__HH_CFG__) || { /* FALLBACK — replace with real values via config.js above */ apiKey: "REPLACE_WITH_ENV_VAR", authDomain: "REPLACE_WITH_ENV_VAR", projectId: "REPLACE_WITH_ENV_VAR", storageBucket: "REPLACE_WITH_ENV_VAR", messagingSenderId: "REPLACE_WITH_ENV_VAR", appId: "REPLACE_WITH_ENV_VAR" }; const app = initializeApp(firebaseConfig); const auth = getAuth(app); const db = getFirestore(app); window._db = db; window._auth = auth; let currentUser = null; let myBookings = []; // ── AUTH STATE ── onAuthStateChanged(auth, async user => { currentUser = user; if (user) { document.getElementById('guestNav').classList.add('hidden'); document.getElementById('userNav').classList.remove('hidden'); document.getElementById('userNav').style.display='flex'; document.getElementById('mobGuest').classList.add('hidden'); document.getElementById('mobUser').classList.remove('hidden'); document.getElementById('myBookings').classList.remove('hidden'); const initial = (user.displayName || user.email || '?')[0].toUpperCase(); document.getElementById('uAvBtn').textContent = initial; document.getElementById('profAvLg').textContent = initial; document.getElementById('profEmailDisp').textContent = user.email; document.getElementById('profEmail').value = user.email; document.getElementById('profNameDisp').textContent = user.displayName || 'No name set'; document.getElementById('profName').value = user.displayName || ''; // Load phone from users collection try { const snap = await getDocs(query(collection(db,'users'),where('uid','==',user.uid))); if(!snap.empty){ const d=snap.docs[0].data(); document.getElementById('profPhone').value=d.phone||''; } } catch(e){} showForm(true, false); await loadMyBookings(user.uid); loadCustomerNotifications(user.uid); loadFirestoreGallery(); checkMaintenanceMode(); loadReviews(); // Check for confirmed booking to show review form // Review available only on completed bookings — handled via booking card button } else { currentUser = null; myBookings = []; document.getElementById('guestNav').classList.remove('hidden'); document.getElementById('userNav').classList.add('hidden'); document.getElementById('mobGuest').classList.remove('hidden'); document.getElementById('mobUser').classList.add('hidden'); document.getElementById('myBookings').classList.add('hidden'); if(!window._guestMode) showForm(false, false); loadFirestoreGallery(); checkMaintenanceMode(); loadReviews(); } }); // ── SIGN IN ── window.doLogin = async () => { const st = document.getElementById('authSt'); st.innerHTML='Signing in…'; try { await signInWithEmailAndPassword(auth, document.getElementById('lEmail').value.trim(), document.getElementById('lPwd').value); closeAuth(); showToast('Welcome back! 🎉'); } catch(e){ st.innerHTML=`${fe(e.code)}`; } }; // ── REGISTER ── window.doRegister = async () => { const st = document.getElementById('authSt2'); st.innerHTML='Creating account…'; try { const c = await createUserWithEmailAndPassword(auth, document.getElementById('rEmail').value.trim(), document.getElementById('rPwd').value); const fname = document.getElementById('rFirst').value.trim(); const lname = document.getElementById('rLast').value.trim(); await updateProfile(c.user, {displayName: fname+' '+lname}); await addDoc(collection(db,'users'),{uid:c.user.uid,firstName:fname,lastName:lname,email:c.user.email,phone:document.getElementById('rPhone').value.trim(),role:'customer',createdAt:serverTimestamp()}); closeAuth(); showToast('Account created! Welcome 🌟'); } catch(e){ st.innerHTML=`${fe(e.code)}`; } }; // ── FORGOT PASSWORD ── window.doForgotPwd = async () => { const st = document.getElementById('authSt3'); const email = document.getElementById('fpEmail').value.trim(); if(!email){ st.innerHTML='Please enter your email.'; return; } st.innerHTML='Sending reset link…'; try { await sendPasswordResetEmail(auth, email); st.innerHTML='✓ Reset link sent! Check your inbox.'; showToast('Password reset email sent 📧'); } catch(e){ st.innerHTML=`${fe(e.code)}`; } }; // ── SIGN OUT ── window.doSignOut = async () => { if(_bookingsUnsubscribe){ _bookingsUnsubscribe(); _bookingsUnsubscribe=null; } await signOut(auth); window._guestMode = false; showForm(false, false); showToast('Signed out.'); }; // ── PROFILE SAVE ── window.saveProfile = async () => { const st = document.getElementById('profSt'); const name = document.getElementById('profName').value.trim(); const phone = document.getElementById('profPhone').value.trim(); if(!name){ st.innerHTML='Name is required.'; return; } st.innerHTML='Saving…'; try { await updateProfile(auth.currentUser, {displayName: name}); // Update in users collection const snap = await getDocs(query(collection(db,'users'),where('uid','==',currentUser.uid))); if(!snap.empty){ await updateDoc(doc(db,'users',snap.docs[0].id),{firstName:name.split(' ')[0],lastName:name.split(' ').slice(1).join(' ')||'',phone}); } document.getElementById('profNameDisp').textContent = name; document.getElementById('uAvBtn').textContent = name[0].toUpperCase(); document.getElementById('profAvLg').textContent = name[0].toUpperCase(); st.innerHTML='✓ Profile updated!'; showToast('Profile saved ✓'); } catch(e){ st.innerHTML=`${e.message}`; } }; // ── MAINTENANCE MODE CHECK ── async function checkMaintenanceMode(){ try { const snap = await getDocs(collection(db,'settings')); if(!snap.empty){ const s = snap.docs[0].data(); const banner = document.getElementById('maintenanceBanner'); const body = document.body; if(s.maintenance){ banner.textContent = s.maintenanceMsg || '🔧 We are performing scheduled maintenance. Back shortly!'; banner.classList.add('show'); body.classList.add('has-banner'); } else { banner.classList.remove('show'); body.classList.remove('has-banner'); } } } catch(e){} } // ── CHECK DUPLICATE BOOKING ── window.checkDuplicate = async () => { if(!currentUser) return; const svc = document.getElementById('bkService').value; if(!svc) return; const warn = document.getElementById('dupWarn'); const sub = document.getElementById('subBtn'); const existing = myBookings.filter(b=>b.service===svc && (b.status==='pending'||b.status==='confirmed')); if(existing.length > 0){ warn.style.display='block'; sub.disabled=true; } else { warn.style.display='none'; sub.disabled=false; } }; // ── SUBMIT BOOKING ── window.submitBooking = async (ev) => { ev.preventDefault(); const user = auth.currentUser; const btn = document.getElementById('subBtn'); const st = document.getElementById('bkSt'); // Block guest users — must be signed in if(!user){ st.innerHTML='⚠️ Please sign in or create an account to submit a booking.'; setTimeout(()=>openAuth('register'),600); return; } // Final duplicate check const svc = document.getElementById('bkService').value; if(user){ const existing = myBookings.filter(b=>b.service===svc&&(b.status==='pending'||b.status==='confirmed')); if(existing.length>0){ st.innerHTML='You already have an active booking for this service.'; return; } } btn.disabled=true; btn.textContent='Sending…'; const bSel=document.getElementById('bkBudget').value; const finalBudget=bSel==='custom'?'₹'+Number(document.getElementById('bkCustomAmt').value||0).toLocaleString('en-IN'):bSel; try { // ── Generate Meaningful Booking ID: [EVENT_CODE]-[MON]-[NNNN] ── // Format: e.g. WED-MAR-0042 | BDY-DEC-0007 | CRP-JAN-0115 const _eventCodeMap = { 'Wedding':'WED', 'Reception':'REC', 'Engagement':'ENG', 'Sangeet':'SGT', 'Mehendi':'MEH', 'Birthday Party':'BDY', 'Corporate Event':'CRP', 'Anniversary':'ANV', 'Baby Shower':'BSH', 'Housewarming':'HWM', 'Naming Ceremony':'NAM', 'Farewell':'FWL', 'Other':'EVT' }; const _svcCodeMap = { 'Luxury Decor & Styling':'DCR', 'Professional Photography':'PHT', 'Live Music & Entertainment':'MUS', 'Premium Lighting Design':'LGT', 'Complete Event Management':'MGT', 'Multiple Services':'MUL' }; const _months = ['JAN','FEB','MAR','APR','MAY','JUN','JUL','AUG','SEP','OCT','NOV','DEC']; const _now = new Date(); const _mon = _months[_now.getMonth()]; // Event type takes priority for the prefix; fall back to service code const _evtType = document.getElementById('bkEventType').value; const _evtCode = _eventCodeMap[_evtType] || _svcCodeMap[svc] || 'EVT'; // Fetch current counter for this prefix from Firestore to get incremental number let _seq = 1; try { const _cSnap = await getDocs(query(collection(db,'bookings'), where('bookingId','>=',_evtCode+'-'), where('bookingId','<',_evtCode+'.'))); _seq = _cSnap.size + 1; } catch(_e){ _seq = Math.floor(Math.random()*900)+100; } const bookingId = _evtCode + '-' + _mon + '-' + String(_seq).padStart(4,'0'); await addDoc(collection(db,'bookings'),{ bookingId, userId:user?user.uid:'guest', userEmail:user?user.email:document.getElementById('bkEmail').value, name:document.getElementById('bkName').value, phone:document.getElementById('bkPhone').value, email:document.getElementById('bkEmail').value, service:svc, eventType:document.getElementById('bkEventType').value, eventDate:document.getElementById('bkDate').value, budget:finalBudget, venue:document.getElementById('bkVenue').value, message:document.getElementById('bkMsg').value, isGuest:!user, status:'pending', pipeline:'New Enquiry', createdAt:serverTimestamp() }); st.innerHTML='✓ Booking submitted! Your ID: '+bookingId+'. We\'ll contact you within 24 hours.'; document.getElementById('bkForm').reset(); document.getElementById('budgetCustom').style.display='none'; document.getElementById('dupWarn').style.display='none'; if(user) await loadMyBookings(user.uid); showToast('Booking submitted! 🎊'); // WhatsApp confirmation const waMsgEnc = encodeURIComponent(`Hi HAPPENHAUS! My booking for *${svc}* on ${document.getElementById('bkDate').value||'TBD'} has been submitted. Please confirm at your earliest.`); // Pre-fill WA suggestion with booking details window._lastBookingMsg = `Hi HAPPENHAUS! My booking for *${svc}* on ${document.getElementById('bkDate').value||'TBD'} has been submitted. Please confirm at your earliest. Name: ${document.getElementById('bkName').value}`; } catch(err){ st.innerHTML=`Error: ${err.message}`; } btn.disabled=false; btn.textContent='Send Booking Request →'; }; // ── LOAD MY BOOKINGS (real-time onSnapshot) ── let _bookingsUnsubscribe = null; function renderBookingsList(docs) { const list = document.getElementById('bkList'); if(!list) return; myBookings = docs.map(d=>({id:d.id,...d.data()})); myBookings.sort((a,b)=>(b.createdAt?.seconds||0)-(a.createdAt?.seconds||0)); if(!myBookings.length){ list.innerHTML='
No bookings yet. Make your first request →
'; return; } const icons={'Luxury Decor & Styling':'🌸','Professional Photography':'📷','Live Music & Entertainment':'🎵','Premium Lighting Design':'✨','Gourmet Catering':'🍽️','Complete Event Management':'🎊','Multiple Services':'🎉'}; // Status pipeline labels — covers ALL admin pipeline stages const statusMap={ 'New Enquiry':'🔔 New Enquiry','pending':'🔔 New Enquiry', 'consultation':'📞 Consultation Scheduled','Consultation Scheduled':'📞 Consultation Scheduled', 'proposal':'📋 Proposal Sent','Proposal Sent':'📋 Proposal Sent', 'confirmed':'✅ Confirmed','Confirmed':'✅ Confirmed', 'declined':'✕ Declined','Declined':'✕ Declined', 'completed':'🎊 Completed','Completed':'🎊 Completed' }; // Status badge css class map const scMap = { 'confirmed':'bk-confirmed','Confirmed':'bk-confirmed', 'completed':'bk-confirmed','Completed':'bk-confirmed', 'declined':'bk-declined','Declined':'bk-declined', 'consultation':'bk-consultation','Consultation Scheduled':'bk-consultation', 'proposal':'bk-proposal','Proposal Sent':'bk-proposal', }; list.innerHTML = myBookings.map(b=>{ // Use pipeline for display when set by admin; else fall back to status const displayStatus = b.pipeline && b.pipeline !== 'New Enquiry' ? b.pipeline : (b.status || 'pending'); const sc = scMap[b.status] || scMap[b.pipeline] || 'bk-pending'; const sl = statusMap[b.pipeline] || statusMap[b.status] || '🔔 New Enquiry'; const dt = b.eventDate?new Date(b.eventDate).toLocaleDateString('en-IN',{day:'numeric',month:'long',year:'numeric'}):'Date TBD'; const canModify = b.status==='pending' || b.status==='New Enquiry'; const priceHtml = b.finalPrice?`
💰 Final Price: ${b.finalPrice}
`:''; // "Share Your Experience" button — only for completed bookings const reviewBtn = (b.status==='completed' || b.pipeline==='Completed') ? `` : ''; return `
${icons[b.service]||'🎊'}
${b.service||'Event Service'}
${b.bookingId?`
🎫 ${b.bookingId}
`:''}
${b.eventType||'Event'} · ${dt} · ${b.budget||''}
📍 ${b.venue||'Venue TBD'}
${priceHtml}
${canModify?``:''} ${reviewBtn}
${sl}
`; }).join(''); // Check for completed bookings to allow reviews const hasCompleted = myBookings.some(b=>b.status==='completed'||b.pipeline==='Completed'); const hasConfirmed = myBookings.some(b=>b.status==='confirmed'||b.pipeline==='Confirmed'); // Review buttons appear inline on completed booking cards } async function loadMyBookings(uid) { const list = document.getElementById('bkList'); list.innerHTML='
Loading…
'; // Unsubscribe previous listener if any if(_bookingsUnsubscribe) { _bookingsUnsubscribe(); _bookingsUnsubscribe=null; } try { const q = query(collection(db,'bookings'),where('userId','==',uid)); // onSnapshot gives real-time updates — status changes from admin reflect instantly _bookingsUnsubscribe = onSnapshot(q, (snap) => { renderBookingsList(snap.docs); }, (err) => { console.error('Bookings snapshot error:', err); list.innerHTML='
Could not load bookings.
'+err.message+'
'; if(err.message && (err.message.includes('permission')||err.message.includes('insufficient'))){ const notice=document.getElementById('firestoreNotice'); if(notice) notice.style.display='block'; } }); } catch(err){ console.error('Bookings load error:', err); list.innerHTML='
Could not load bookings.
'; } } window._loadMyBookings = loadMyBookings; // ── MODIFY BOOKING ── window.openModify = async (id) => { const bk = myBookings.find(b=>b.id===id); if(!bk) return; document.getElementById('modifyBkId').value=id; document.getElementById('modName').value=bk.name||''; document.getElementById('modPhone').value=bk.phone||''; document.getElementById('modDate').value=bk.eventDate||''; document.getElementById('modVenue').value=bk.venue||''; document.getElementById('modMsg').value=bk.message||''; document.getElementById('modSt').innerHTML=''; document.getElementById('modifyModal').classList.add('open'); document.body.style.overflow='hidden'; }; window.closeModify=()=>{document.getElementById('modifyModal').classList.remove('open');document.body.style.overflow='';}; window.saveModify = async () => { const id=document.getElementById('modifyBkId').value; const st=document.getElementById('modSt'); st.innerHTML='Saving…'; try{ await updateDoc(doc(db,'bookings',id),{ name:document.getElementById('modName').value, phone:document.getElementById('modPhone').value, eventDate:document.getElementById('modDate').value, venue:document.getElementById('modVenue').value, message:document.getElementById('modMsg').value, modifiedAt:serverTimestamp(), status:'pending' }); st.innerHTML='✓ Booking updated! Our team will review and confirm.'; showToast('Booking updated ✓'); if(currentUser) await loadMyBookings(currentUser.uid); setTimeout(()=>closeModify(),2000); }catch(e){st.innerHTML=`${e.message}`;} }; // ── FIRESTORE GALLERY LOAD ── async function loadFirestoreGallery(){ try{ const snap = await getDocs(collection(db,'gallery')); window._firestoreGallery = snap.docs.map(d=>{const data=d.data();return{url:data.url,caption:data.caption||'',eventCategory:data.eventCategory||'General',service:data.service||''};}); renderDynGallery(); }catch(e){renderDynGallery();} } window.loadFirestoreGallery=loadFirestoreGallery; // ── GALLERY SERVICE ── window.loadSvcGallery = async (name) => { document.getElementById('glTtl').textContent=name; document.getElementById('glCount').textContent=''; document.getElementById('glGrid').innerHTML='
Loading photos…
'; openGl(); try{ const snap=await getDocs(query(collection(db,'gallery'),where('service','==',name))); const fbImgs=snap.docs.map(d=>({url:d.data().url,caption:d.data().caption||name})); const staticImgs=(window._svcPhotos[name]||[]).map(u=>({url:u,caption:name})); const all=[...fbImgs,...staticImgs]; window._glImgs=all; document.getElementById('glCount').textContent=`${all.length} photo${all.length!==1?'s':''}`; if(!all.length){document.getElementById('glGrid').innerHTML='
No photos yet for this service.
';return;} document.getElementById('glGrid').innerHTML=all.map((img,i)=>`
${img.caption}
${img.caption}
`).join(''); }catch(err){document.getElementById('glGrid').innerHTML='
Could not load photos.
';} }; // ── REVIEWS ── async function loadReviews(){ try{ // Fetch without orderBy to avoid composite index requirement, sort client-side const snap=await getDocs(query(collection(db,'reviews'),where('approved','==',true))); const revs=snap.docs.map(d=>({id:d.id,...d.data()})).sort((a,b)=>(b.createdAt?.seconds||0)-(a.createdAt?.seconds||0)); // Stars avg if(revs.length){ const avg=(revs.reduce((a,r)=>a+r.rating,0)/revs.length).toFixed(1); document.getElementById('revAvgNum').textContent=avg; document.getElementById('revAvgCount').textContent=`Based on ${revs.length} verified review${revs.length!==1?'s':''}`; const starsHtml=Array.from({length:5},(_,i)=>`${i`).join(''); document.getElementById('revAvgStars').innerHTML=starsHtml; document.getElementById('revGrid').innerHTML=revs.slice(0,6).map(r=>{ const stars=Array.from({length:5},(_,i)=>``).join(''); return `
${stars}

${r.text}

${(r.name||'A')[0].toUpperCase()}
${r.name||'Anonymous'}
${r.event||''}
`; }).join(''); } else { document.getElementById('revAvgNum').textContent='—'; document.getElementById('revAvgCount').textContent='No reviews yet — be the first!'; document.getElementById('revGrid').innerHTML='
No reviews yet. Be the first to share your experience!
'; } }catch(e){ // Fallback static reviews document.getElementById('revAvgNum').textContent='5.0'; document.getElementById('revAvgCount').textContent='Based on verified reviews'; document.getElementById('revGrid').innerHTML=`
★★★★★

AB Events transformed our wedding into an absolute fairytale. Every detail was perfect — from the floral mandap to the candlelit reception. Truly unforgettable.

P
Priya & Rahul Sharma
Wedding · Taj Falaknuma
★★★★★

Our daughter's first birthday was beyond magical. The decor, the photography — everything handled with such care and professionalism.

A
Anita Reddy
Birthday · Gachibowli
★★★★★

For our corporate gala, AB Events delivered an experience that left 400 guests speechless. An outstanding team through and through.

V
Vikram Nair
Corporate Gala · HICC
`; } } // Review submission handled via per-booking modal (openReviewModal / submitModalReview) // ── CUSTOMER NOTIFICATIONS ── function loadCustomerNotifications(uid){ // Use simple where query to avoid composite index requirement const q=query(collection(db,'notifications'),where('userId','==',uid)); onSnapshot(q,snap=>{ const notifs=snap.docs.map(d=>({id:d.id,...d.data()})).sort((a,b)=>(b.createdAt?.seconds||0)-(a.createdAt?.seconds||0)); const unread=notifs.filter(n=>!n.read).length; const badge=document.getElementById('custNotifBadge'); if(unread>0){badge.textContent=unread;badge.classList.add('show');}else{badge.classList.remove('show');} const list=document.getElementById('custNotifList'); if(!notifs.length){list.innerHTML='
No notifications yet
';return;} list.innerHTML=notifs.slice(0,10).map(n=>`
${n.message||''}
${n.createdAt?.toDate?n.createdAt.toDate().toLocaleString('en-IN',{day:'numeric',month:'short',hour:'2-digit',minute:'2-digit'}):''}
`).join(''); }); } window.readNotif=async(id)=>{ try{await updateDoc(doc(db,'notifications',id),{read:true});}catch(e){} }; window.markAllRead=async(e)=>{ e.stopPropagation(); if(!currentUser)return; const snap=await getDocs(query(collection(db,'notifications'),where('userId','==',currentUser.uid))); snap.docs.filter(d=>!d.data().read).forEach(d=>updateDoc(doc(db,'notifications',d.id),{read:true})); }; function fe(c){const m={'auth/user-not-found':'No account with that email.','auth/wrong-password':'Incorrect password.','auth/invalid-credential':'Invalid email or password.','auth/email-already-in-use':'Email already registered.','auth/weak-password':'Password needs 6+ characters.','auth/invalid-email':'Invalid email address.','auth/too-many-requests':'Too many attempts. Try later.','auth/missing-password':'Please enter your password.'};return m[c]||'Something went wrong. Try again.';}