import { useState, useRef, useEffect } from "react"; // ─── Global CSS Animations ────────────────────────────────────────────────────── function GlobalStyles(){ return( ); } // ─── Design Tokens ───────────────────────────────────────────────────────────── const C = { // Core brand — Electric Violet + Sky Blue refresh purple:"#7C3AED",purpleL:"#A78BFA",purpleFg:"#EDE9FE", mint:"#0EA5E9",mintL:"#E0F2FE", coral:"#F43F5E",coralL:"#FFF1F2", marigold:"#F59E0B",marigoldL:"#FFFBEB", crimson:"#DC2626",crimsonL:"#FEF2F2",crimsonM:"#EF4444", // Extended accent palette indigo:"#6366F1",indigoL:"#EEF2FF", rose:"#FB7185",roseL:"#FFF1F2", amber:"#F59E0B",amberL:"#FFFBEB", emerald:"#10B981",emeraldL:"#ECFDF5", sky:"#0EA5E9",skyL:"#E0F2FE", // Surface — crisp, clean surface:"#F8FAFC",card:"#FFFFFF", text:"#0F172A",muted:"#64748B",border:"#E2E8F0", // Shadow scale shadowSm:"0 1px 3px rgba(0,0,0,0.07)", shadowMd:"0 4px 16px rgba(0,0,0,0.08)", shadowLg:"0 8px 32px rgba(0,0,0,0.12)", }; const G = { purple: `linear-gradient(135deg, #7C3AED 0%, #A78BFA 100%)`, purpleDark: `linear-gradient(135deg, #4C1D95 0%, #7C3AED 100%)`, purpleVibrant:`linear-gradient(135deg, #7C3AED 0%, #C084FC 100%)`, mint: `linear-gradient(135deg, #0284C7 0%, #0EA5E9 100%)`, coral: `linear-gradient(135deg, #E11D48 0%, #F43F5E 100%)`, marigold: `linear-gradient(135deg, #D97706 0%, #F59E0B 100%)`, indigo: `linear-gradient(135deg, #4F46E5 0%, #6366F1 100%)`, rose: `linear-gradient(135deg, #E11D48 0%, #FB7185 100%)`, hero: `linear-gradient(145deg, #0D0420 0%, #2E1065 35%, #7C3AED 65%, #0EA5E9 100%)`, card: `linear-gradient(145deg, rgba(255,255,255,0.18), rgba(255,255,255,0.06))`, surface: `linear-gradient(180deg, #F8FAFC 0%, #F1F5F9 100%)`, // Per-tab accent gradients tabFeed: `linear-gradient(135deg,#7C3AED,#A78BFA)`, tabEvents: `linear-gradient(135deg,#4F46E5,#818CF8)`, tabCommunity: `linear-gradient(135deg,#D97706,#F59E0B)`, tabMessages: `linear-gradient(135deg,#0284C7,#0EA5E9)`, tabProfile: `linear-gradient(135deg,#E11D48,#F43F5E)`, }; const CM_AREAS = [ { id:"ep1", label:"EC Phase 1", pin:"560100" }, { id:"ep2", label:"EC Phase 2", pin:"560100" }, { id:"nn", label:"Neeladri Nagar", pin:"560100" }, { id:"bb", label:"Bommasandra", pin:"560099" }, ]; const CURRENT_MANAGERS = { ep1: { name:"Suresh Babu", apt:"GM Infinite E-City Town", since:"Jan 2025", avatar:"SB", color:"#5C2D91", events:14, posts:87 }, ep2: null, nn: { name:"Divya Menon", apt:"Celebrity Paradise", since:"Mar 2025", avatar:"DM", color:"#00B89F", events:9, posts:62 }, bb: null, }; const CANDIDATES_BY_AREA = { ep1: [], // current manager exists, no active election ep2: [ { id:1, name:"Rajesh Kumar", apt:"Shriram Liberty Square Ph2", eventsOrg:8, posts:34, votes:142, avatar:"RK", color:"#5C2D91", profession:"Software Engineer, Wipro", statement:"I want to make EC Phase 2 cleaner, safer and more connected for every family here." }, { id:2, name:"Priya Sharma", apt:"Mahaveer Ranches", eventsOrg:6, posts:51, votes:98, avatar:"PS", color:"#00B89F", profession:"Senior Doctor, Narayana HC",statement:"Community health awareness drives and weekend events for kids and seniors." }, { id:3, name:"Arun Nair", apt:"Ittina Mahavir", eventsOrg:7, posts:22, votes:76, avatar:"AN", color:"#FF6B7A", profession:"School Principal", statement:"Focus on youth programs, sports days and clean neighbourhood initiatives." }, { id:4, name:"Meenakshi Iyer",apt:"SV Grandur", eventsOrg:5, posts:18, votes:44, avatar:"MI", color:"#FFB347", profession:"HR Manager, Infosys", statement:"Better resident communication and faster issue resolution for everyone." }, ], nn: [], bb: [ { id:5, name:"Karthik Reddy", apt:"Ozone Urbana", eventsOrg:6, posts:29, votes:61, avatar:"KR", color:"#6B7FF0", profession:"Civil Engineer", statement:"Infrastructure, roads and parking solutions are my top priority." }, { id:6, name:"Anjali Singh", apt:"RK Township", eventsOrg:5, posts:41, votes:37, avatar:"AS", color:"#FF6B7A", profession:"Teacher, DPS", statement:"Cultural events, festivals and bringing neighbours together." }, ], }; const ELECTION_DEADLINE = { ep2:"15 Mar 2026", bb:"20 Mar 2026" }; // Logged-in user mock stats const MY_STATS = { eventsOrg:7, posts:24, area:"ep2", apt:"Shriram Liberty Square Ph2", verified:true }; // ── 6-Month Election Cycle Data ────────────────────────────────────────────── // Phases: "stable" | "pre_election" (≤30 days, apply open) | "voting" (top-4 live) | "no_admin" const ELECTION_PHASES = { ep1:"stable", ep2:"voting", nn:"pre_election", bb:"no_admin", }; const TERM_DATA = { ep1:{ managerName:"Suresh Babu", termStart:"1 Jan 2026", termEnd:"1 Jul 2026", daysElapsed:61, totalDays:181, daysLeft:120, nextElectionOpen:"1 Jun 2026" }, ep2:{ votingStart:"1 Mar 2026", votingEnd:"15 Mar 2026", daysLeftVoting:13, applyStart:"1 Feb 2026", applyEnd:"28 Feb 2026", totalApplicants:6, shortlistedTo:4 }, nn: { managerName:"Divya Menon", termStart:"1 Sep 2025", termEnd:"1 Mar 2026", daysElapsed:182, totalDays:182, daysLeft:0, applyDeadline:"14 Mar 2026", applicantsCount:3, slotsLeft:1 }, bb: { note:"No community admin elected yet. Start an election for your area!" }, }; // Applicant pool for EP2 — 6 applied, top 4 by activity score shortlisted for voting const EP2_POOL = [ { name:"Rajesh Kumar", eventsOrg:8, posts:34, score:58, shortlisted:true }, { name:"Priya Sharma", eventsOrg:6, posts:51, score:69, shortlisted:true }, { name:"Arun Nair", eventsOrg:7, posts:22, score:43, shortlisted:true }, { name:"Meenakshi Iyer",eventsOrg:5, posts:18, score:33, shortlisted:true }, { name:"Vikram Patel", eventsOrg:5, posts:11, score:26, shortlisted:false }, { name:"Sunita Das", eventsOrg:5, posts: 9, score:24, shortlisted:false }, ]; // Scoring rule: (events × 3) + posts const calcScore = (e,p) => e*3 + p; // ─── PII Detection Engine ───────────────────────────────────────────────────── const PII_REGEX = { card: /\b\d{4}[\s\-]?\d{4}[\s\-]?\d{4}[\s\-]?\d{4}\b/, cvv: /\b(cvv|cvc|security\s*code)\b/i, upi: /[a-zA-Z0-9.\-_]+@(upi|paytm|gpay|phonepe|ybl|oksbi|okaxis|okhdfcbank)\b/i, bank: /\b(account\s*(no|number)|ifsc|[A-Z]{4}0[A-Z0-9]{6})\b|\b\d{11,18}\b/i, phone: /(\+91[\s\-]?)?[6-9]\d{9}\b/, }; const PII_META = { card: { icon:"💳", label:"credit / debit card number", msg:"Card numbers are highly sensitive payment credentials." }, cvv: { icon:"🔐", label:"CVV / security code", msg:"CVV codes must never be shared — this is critical payment security." }, upi: { icon:"💸", label:"UPI payment ID", msg:"UPI IDs enable direct money transfers to your account." }, bank: { icon:"🏦", label:"bank account information", msg:"Bank details can be misused for unauthorised transactions." }, phone: { icon:"📞", label:"phone number", msg:"Phone numbers shared publicly can attract spam or harassment." }, }; function detectPII(text){ for(const [t,rx] of Object.entries(PII_REGEX)){if(rx.test(text))return t;} return null; } // ─── Content Moderation ────────────────────────────────────────────────────── const POLICY_TERMS=["nude","naked","porn","pornography","xxx","explicit adult","sexual content","nsfw","obscene","adult video","sex video","inappropriate image"]; function checkViolation(text){ const l=text.toLowerCase(); return POLICY_TERMS.some(k=>l.includes(k)); } // ─── Reactions & Cross-Share Data ──────────────────────────────────────────── const REACTIONS=[ {id:"like", emoji:"👍",label:"Like"}, {id:"heart",emoji:"❤️",label:"Love"}, {id:"haha", emoji:"😂",label:"Haha"}, {id:"sad", emoji:"😢",label:"Sad"}, {id:"cry", emoji:"😭",label:"Crying"}, {id:"wow", emoji:"😮",label:"Wow"}, {id:"angry", emoji:"😡",label:"Angry"}, {id:"thanks",emoji:"🙏",label:"Thanks"}, {id:"cheer", emoji:"🎉",label:"Cheer"}, ]; const POST_RXNS={ 8:{like:0, heart:0, sad:31,cry:44, wow:9, angry:2, thanks:7}, // Missing Person – mostly sad/crying 1:{like:23,heart:8, sad:2, cry:2, wow:5, angry:0, thanks:9}, 2:{like:14,heart:41,sad:3, cry:0, wow:7, angry:0, thanks:12}, 3:{like:57,heart:29,sad:0, cry:0, wow:4, angry:0, thanks:18}, 4:{like:19,heart:5, sad:0, cry:0, wow:2, angry:1, thanks:14}, 5:{like:83,heart:11,sad:4, cry:1, wow:9, angry:0, thanks:22}, 6:{like:8, heart:2, sad:5, cry:3, wow:11, angry:4, thanks:3}, 7:{like:5, heart:1, sad:8, cry:2, wow:3, angry:0, thanks:4}, }; const NEARBY_AREAS=["Electronic City Phase 1","Neeladri Nagar","Hebbagodi","Bommasandra","Veerasandra","Chandapura","Doddathogur"]; const ALERT_CATEGORIES=["Safety","Lost & Found","Missing Person"]; // ─── Community Members mock data ───────────────────────────────────────────── const COMMUNITY_MEMBERS=[ {id:1,name:"Rajesh Kumar", apt:"Shriram Liberty Square Ph2",av:"RK",avC:"#5C2D91"}, {id:2,name:"Priya Sharma", apt:"Mahaveer Ranches", av:"PS",avC:"#00B89F"}, {id:3,name:"Arun Nair", apt:"Ittina Mahavir", av:"AN",avC:"#FF6B7A"}, {id:4,name:"Meenakshi Iyer", apt:"SV Grandur", av:"MI",avC:"#FFB347"}, {id:5,name:"Vikram Patel", apt:"Ozone Urbana", av:"VP",avC:"#6B7FF0"}, {id:6,name:"Anjali Singh", apt:"RK Township", av:"AS",avC:"#FF6B7A"}, {id:7,name:"Karthik Reddy", apt:"Prestige Sunrise Park", av:"KR",avC:"#5C2D91"}, {id:8,name:"Sunita Das", apt:"Celebrity Paradise", av:"SD",avC:"#00B89F"}, ]; const CAT_META = { "Missing Person":{icon:"🆘",color:"#B91C1C",urgent:true}, "Safety": {icon:"🛡️",color:"#FF6B7A"}, "Lost & Found": {icon:"🔍",color:"#FFB347"}, "Services": {icon:"🔧",color:"#5C2D91"}, "Recommendation":{icon:"⭐",color:"#00B89F"}, "General": {icon:"💬",color:"#6B7FF0"}, }; // ─── Mock current user (verified=false → pending admin review) ─────────────── const MOCK_USER = { name:"Meena T.", apt:"Prestige Sunrise Park", area:"EC Phase 2", av:"MT", avC:C.purple, verified:true, // set true after admin approves account pendingReview:false, role:"admin", // "admin" | "moderator" | "resident" }; // Categories that block unverified users completely const NEEDS_VERIFIED_CATS = ["Services","Recommendation","General"]; // Categories allowed for unverified but go to admin review queue const REVIEW_QUEUE_CATS = ["Safety","Lost & Found","Missing Person"]; // ─── Validation Helpers ─────────────────────────────────────────────────────── // Allowed character sets const RE_NAME = /^[a-zA-Z\s.\-']+$/; // names: letters, space, dot, hyphen, apostrophe const RE_PHONE = /^[\d\s\-()+]+$/; // phone: digits + formatting chars const RE_ADDR = /^[a-zA-Z0-9\s,.\-\/]+$/; // address fields: alphanumeric + , . - / space const RE_FLAT = RE_ADDR; // flat/door same as address // ── Character STRIP functions — call on every keystroke to block invalid chars ── const stripName = v => v.replace(/[^a-zA-Z\s.\-']/g, ""); // names only const stripPhone = v => v.replace(/[^0-9\s\-()+]/g, ""); // phone digits+format const stripAddr = v => v.replace(/[^a-zA-Z0-9\s,.\-\/]/g, ""); // address/area/apt/flat const _hasVowel = s => /[aeiouAEIOU]/.test(s); const _vowelRatio = s => { const l = s.replace(/[^a-zA-Z]/g,""); if(!l.length) return 1; return ((l.match(/[aeiouAEIOU]/g)||[]).length) / l.length; }; const vName = v => { const s = v.trim(); if(!s) return "Name is required"; if(/\d/.test(s)) return "Name cannot contain numbers"; if(!RE_NAME.test(s)) return "Only letters, spaces, dots and hyphens allowed"; if(!_hasVowel(s)) return "Please enter a valid name"; if(s.replace(/\s/g,"").length > 4 && _vowelRatio(s) < 0.12) return "Please enter a valid name"; if(s.length < 2) return "Too short"; return null; }; const vPhone = v => { const d = v.replace(/[\s\-()]/g,""); if(!d) return "Mobile number is required"; if(!/^\d+$/.test(d)) return "Numbers only — no letters or symbols"; if(d.length !== 10) return "Must be exactly 10 digits"; if(!/^[6-9]/.test(d)) return "Must start with 6, 7, 8 or 9"; return null; }; const vArea = v => { // Strip parenthetical annotations added by dropdown (e.g. "(PIN: 560100)") const clean = v.replace(/\s*\([^)]*\)/g,"").trim(); if(!clean) return "Area is required"; if(!RE_ADDR.test(clean)) return "Only letters, numbers, spaces, comma, dot, - and / allowed"; return null; }; const vApt = v => { const clean = v.replace(/\s*\([^)]*\)/g,"").trim(); if(!clean) return "Apartment name is required"; if(!RE_ADDR.test(clean)) return "Only letters, numbers, spaces, comma, dot, - and / allowed"; if(clean.length < 3) return "Too short"; if(/^\d+$/.test(clean)) return "Please enter a valid apartment name"; return null; }; const vFlat = v => { if(!v.trim()) return "Flat/Door number is required"; if(!RE_ADDR.test(v)) return "Only letters, numbers, spaces, comma, dot, - and / allowed"; return null; }; const vBizName = v => { if(!v.trim()) return "Business name is required"; if(!RE_ADDR.test(v)) return "Only letters, numbers, spaces, comma, dot, - and / allowed"; if(v.trim().length < 2) return "Too short"; if(/^[^a-zA-Z0-9]/.test(v.trim())) return "Must start with a letter or number"; return null; }; const vOwnerName = v => vName(v); // same rules as personal name const RE_EMAIL = /^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$/; const stripEmail = v => v.replace(/[^a-zA-Z0-9@._+\-]/g,""); const vEmail = v => { const s = v.trim(); if(!s) return "Email address is required"; if(!RE_EMAIL.test(s)) return "Enter a valid email address (e.g. name@gmail.com)"; return null; }; const vPassword = v => { if(!v) return "Password is required"; if(v.length < 6) return "Password must be at least 6 characters"; return null; }; // ─── All local data ───────────────────────────────────────────────────────────── const AREA_NAMES = [ // ── Electronic City Phase 1 & its sub-localities ── "Electronic City Phase 1 (PIN: 560100)", "Gollahalli (PIN: 560100)", "Shikaripalya (PIN: 560100)", "Neotown, EC Phase 1 (PIN: 560100)", "Doddathogur (PIN: 560100)", "Neeladri Nagar (PIN: 560100)", "Veerasandra (PIN: 560100)", // ── Electronic City Phase 2 & its sub-localities ── "Electronic City Phase 2 (PIN: 560100)", "Shanthipura, EC Phase 2 (PIN: 560100)", "BTM Phase 1, EC Phase 2 (PIN: 560100)", "Konappana Agrahara (PIN: 560100)", "Ananth Nagar, EC Phase 2 (PIN: 560100)", "Doddanagamangala (PIN: 560100)", "Kammasandra (PIN: 560100)", // ── Surrounding areas ── "Huskur Road Area (PIN: 560100)", "Hebbagodi (PIN: 560099)", "Bommasandra (PIN: 560099)", "Chandapura (PIN: 562106)", "Kudlu (PIN: 560068)", ]; // Grouped version of AREA_NAMES — used by SmartInput groupedOptions prop const AREA_GROUPS = [ { group:"EC Phase 1 & Sub-localities", icon:"🏙️", items:[ "Electronic City Phase 1 (PIN: 560100)", "Gollahalli (PIN: 560100)", "Shikaripalya (PIN: 560100)", "Neotown, EC Phase 1 (PIN: 560100)", "Doddathogur (PIN: 560100)", "Neeladri Nagar (PIN: 560100)", "Veerasandra (PIN: 560100)", ]}, { group:"EC Phase 2 & Sub-localities", icon:"🏢", items:[ "Electronic City Phase 2 (PIN: 560100)", "Shanthipura, EC Phase 2 (PIN: 560100)", "BTM Phase 1, EC Phase 2 (PIN: 560100)", "Konappana Agrahara (PIN: 560100)", "Ananth Nagar, EC Phase 2 (PIN: 560100)", "Doddanagamangala (PIN: 560100)", "Kammasandra (PIN: 560100)", ]}, { group:"Surrounding Areas", icon:"🗺️", items:[ "Huskur Road Area (PIN: 560100)", "Hebbagodi (PIN: 560099)", "Bommasandra (PIN: 560099)", "Chandapura (PIN: 562106)", "Kudlu (PIN: 560068)", ]}, ]; const APT_BY_AREA = { "Electronic City Phase 1":[ // A "Ajmera Infinity","Ajmera Stone Park","Ajmera Annex", "Akshaya Residency","Alps Pleasanton","Amethyst Central Serviced Apartments", "Apple Residency","Aristo Marvel","Aashrayam Apartments", // C "Celebrity Signature","Concorde Manhattans","Concorde Tech Turf", "Countryside Raindance", // D "DS Max Sigma","DS-Max Starry","DS Max Star Nest", // G "GM Infinite E-City Town Phase 1","GM Infinite Smondo", "Godrej E-City","Godrej Nurture","Golden Abode","Gopalan Lakefront", // H "Hamsa Residency","Happy Homes 2", // I–K "Ittina Mahaveer Apartments","Keerthi Royal Palms","Keya The Lake Terraces", "Kolte Patil iTowers Exente", // M "Mahendra Aarna","Manya Elite","Manya Hi-Living", "My Fortune Apartments","My Nivas", // N–O "Neeladri Castle Apartment","Neo Elite Apartments","Nest Apartment", "Oakstone Paradise Apartment","Omkar Nivas - Luxury Apartments", // P "Patel Smondo 2","Patel Townsville","Pragathi Royale II","Pragna Uptown", "Prestige Norwood","Prestige Sunrise Park","Prestige Tanglewood", "PSR Krish Kamal", // R "Ramky One Karnival","Rangashree Residency","Royal Apartment", // S "Shriram Liberty Square","Shriram Signiaa","Shriram Summit", "SJR Equinox Apartment","SJR Fiesta Homes","SLV Elite","SNN Raj GreenBay", // T "The Green Terraces","The Lake View Address", ], "Electronic City Phase 2":[ // A "Ajmera Nucleus","Amaravathi Icon","Aswani Aaeesha", // B "BASH Enclave","Bhagya Nilayam","Bren Woods","Brons Apartment", // C "Columbia Aaltius","Concorde Wind Rush", // E–G "Elegance Elite","Gopalan Lakefront", // I "Icon Happy Living","Inspira Tropical Garden","Ittina Mahavir", // J–K "JK Residency","Kaveri Pebbles", // M "Mahaveer Edenfield","Mahaveer Ranches","Mahendra Aarya", // P "Pavani Chandana","Pragathi Amber","Prakruthi Solitaire", "Prabhavathi Meadows","Pramuk Aqua Heights","Purnima Elite", // R "Royal Apartment", // S "Salarpuria Sattva","Shanders Dwellington","Shanders Enclave","Shanders South City", "Shriram Liberty Square Phase 2", "SJR Fiesta Homes","SNN Raj Greenbay","Sree Devi Nilayam", "Sri Sai Meadows","Sri Vishnu Pearls Apartment","SRS Pranav","Surbacon Cedar","SUVRITH SHELTER", "SV Grandur", // T "Tarika Mansion", // V "Vijay Nest", ], // ── EC Phase 1 sub-localities ── "Gollahalli":[ "Countryside Raindance","DS Max Sigma","Gopalan Lakefront", "Rangashree Residency","Shriram Summit","The Lake View Address", ], "Shikaripalya":[ "Concorde Tech Turf","Godrej Nurture","Keya The Lake Terraces", ], "Neotown, EC Phase 1":[ "GM Infinite E-City Town Phase 1","GM Infinite Smondo", "Ramky One Karnival","The Green Terraces", ], "Neeladri Nagar":[ "Celebrity Paradise","Celebrity Signature","DSR Sunrise", "MANYA ELITE","Manya Hi-Living","Omkar Nivas - Luxury Apartments", "Paradise Residency","Pragna Uptown","PSR Krish Kamal", "SLV Apartment","SLV Elite","Vaishnavi Terraces", ], "Doddathogur":[ "Alps Pleasanton","Godrej E-City","Hamsa Residency", "Neo Elite Apartments","Prestige Sunrise Park", "Pristine Temple Bells","Purva Fountain Square", "Sai Ashraya Layout","Temple Bells Premier", ], "Veerasandra":[ "Columbia Aaltius","Gopalan Lakefront","Sai Brindavan Apartments", "Silicon Ozone","Sri Tirumala Splendor", ], // ── EC Phase 2 sub-localities ── "Shanthipura, EC Phase 2": [ "GPR Royale Layout","Sai Sarana Layout","Shanthipura Apartments", "Ecity Luxury Stay","Royal Guest House","Huskur Gate Residency", ], "BTM Phase 1, EC Phase 2": [ "BTM Phase 1 Residency","Ananda Reddy Layout","Tech Mahindra Back Gate Layout", "Shivam Residency","Precision Compaid Building", ], "Konappana Agrahara":[ "Aswani Aaeesha","Kolte Patil iTowers Exente", "SNN Raj Greenbay","SV Grandur","Vijay Nest", ], "Ananth Nagar, EC Phase 2":[ "Ajmera Nucleus","Amaravathi Icon","Elegance Elite", "Pragathi Amber","Vijay Nest", ], "Doddanagamangala":[ "Bren Woods","Brons Apartment","Shanders Dwellington", "Shanders Enclave","Shanders South City","SJR Fiesta Homes", ], "Kammasandra":[ "Inspira Tropical Garden","Mahendra Aarya","Purnima Elite", "Sri Vishnu Pearls Apartment", ], // ── Surrounding areas ── "Huskur Road Area":["Salarpuria Sattva Greenage","Radiant Heritage","BEML Layout Residences"], "Bommasandra":["Habulus Samruddi","RK Township","Pristine Residency","Ozone Urbana"], "Chandapura":["JR Habitat","Nayana Greens","Aswani Sitara","My Home Bhooja"], "Hebbagodi":["Hebbagodi Layout","Adarsh Welkin Park","Godrej Ananda","Shriram Summitt"], "Kudlu":["Kudlu Gate Layout","SNN Mark","Adarsh Palm Retreat","Provident Kenworth"], }; const ALL_APTS = Object.values(APT_BY_AREA).flat(); const STREETS = [ // National Highways "Hosur Road (NH 44)","Outer Ring Road (NH 275)","NH 75", // Major roads "Neeladri Road","Veerasandra Road", "Gollahalli Main Road","Shikaripalya Main Road","Kammasandra Main Road", "Doddathogur Main Road","Doddanagamangala Road","Huskur Road", "Shanthi Pura Main Road","ITC 5 Path (Doddanagamangala)", "Veerasandra Main Road, EC Phase 2","BTM Phase 1 Road", "Anantha Nagar Road, Kammasandra","GPR Royale Layout Road", "Konappana Agrahara Main Road","Hebbagodi Main Road","Bommasandra Ring Road", "Velankani Drive","Neotown Main Road","Smondoville Road", "Electronic City Elevated Expressway","Electronic City Service Road", "Jigani Road","Chandapura–Anekal Road","NICE Road","Sarjapur Road", "Gollahalli–Electronic City Road", // Campus / institution avenues (official names) "Infosys Avenue","Hewlett Packard Avenue", "Bangalore Bioinnovation Centre Road","Symbiosis–CGI Road", "Abbaiah Reddy Street","Lotus Path", "Infosys Gate Road","Wipro Gate Road (Gate 13)", // Numbered roads — Phase 1 "1st Cross, EC Phase 1","2nd Cross, EC Phase 1","3rd Cross, EC Phase 1", "4th Cross Road, EC Phase 1","5th Cross Road, EC Phase 1", "6th Cross Road, EC Phase 1","11th Cross Road, EC Phase 1", "12th Cross Road, EC Phase 1","13th Cross Road, EC Phase 1", "16th Cross Road, EC Phase 1", // Numbered roads — Phase 2 "1st Main Road, EC Phase 2","2nd Main Road, EC Phase 2", "4th Main Road, EC Phase 2","9th Cross Road, EC Phase 2", // Local streets "Bachappa Road","Veerasandra Main Road", ]; // Grouped version of STREETS — used by SmartInput groupedOptions prop const STREET_GROUPS = [ { group:"National Highways", icon:"🛣️", items:[ "Hosur Road (NH 44)","Outer Ring Road (NH 275)","NH 75", ]}, { group:"Major Roads", icon:"🚗", items:[ "Neeladri Road","Veerasandra Road", "Gollahalli Main Road","Shikaripalya Main Road","Kammasandra Main Road", "Doddathogur Main Road","Doddanagamangala Road","Huskur Road", "Shanthi Pura Main Road","ITC 5 Path (Doddanagamangala)", "Veerasandra Main Road, EC Phase 2","BTM Phase 1 Road", "Anantha Nagar Road, Kammasandra","GPR Royale Layout Road", "Konappana Agrahara Main Road","Hebbagodi Main Road","Bommasandra Ring Road", "Velankani Drive","Neotown Main Road","Smondoville Road", "Electronic City Elevated Expressway","Electronic City Service Road", "Jigani Road","Chandapura–Anekal Road","NICE Road","Sarjapur Road", "Gollahalli–Electronic City Road", ]}, { group:"Campus & Tech Park Avenues", icon:"💼", items:[ "Infosys Avenue","Hewlett Packard Avenue", "Bangalore Bioinnovation Centre Road","Symbiosis–CGI Road", "Abbaiah Reddy Street","Lotus Path", "Infosys Gate Road","Wipro Gate Road (Gate 13)", ]}, { group:"EC Phase 1 Cross Roads", icon:"🔢", items:[ "1st Cross, EC Phase 1","2nd Cross, EC Phase 1","3rd Cross, EC Phase 1", "4th Cross Road, EC Phase 1","5th Cross Road, EC Phase 1", "6th Cross Road, EC Phase 1","11th Cross Road, EC Phase 1", "12th Cross Road, EC Phase 1","13th Cross Road, EC Phase 1", "16th Cross Road, EC Phase 1", ]}, { group:"EC Phase 2 Main Roads", icon:"🔢", items:[ "1st Main Road, EC Phase 2","2nd Main Road, EC Phase 2", "4th Main Road, EC Phase 2","9th Cross Road, EC Phase 2", ]}, { group:"Local Streets", icon:"🏘️", items:[ "Bachappa Road","Veerasandra Main Road", ]}, ]; const LANDMARKS = [ // IT Campuses "Infosys Campus (EC Phase 1)","Wipro Campus (Phase 1, Gate 13)", "Tech Mahindra (EC Phase 2)","Biocon","BEML Complex", "DXC Technologies","Velankani Tech Park", // Malls & Commercial "EC Mall","Forum Mall (Hosur Rd)","M5 Ecity Mall","Neotown", // Banks & ATMs "HDFC Bank, EC Phase 2","State Bank of India, Electronic City", "Canara Bank, Electronic City","ICICI Bank, Electronic City", // Transport "Electronic City Metro Station","Hebbagodi Bus Terminal", "BMTC Depot, Electronic City", "Heelalige Railway Station","Karmelaram Railway Station", // Hotels "Golden Tulip Hotel, EC Phase 1","Lemon Tree Hotel, Electronic City", // Educational Institutes "IIIT Bangalore","Welingkar Institute of Management", "ISBR Business School","Symbiosis Institute, Electronic City", "Sri Chaitanya School, EC Phase 1", "Gitam University Bangalore (EC Phase 1)", "IZee Business School (Konappana Agrahara)", "Suvidya Institute (Electronics City)", // Healthcare "Trinity Healthcare Clinic","NIMHANS (Hosur Road)", // Police & Civic "Electronics City Traffic Police Station", "Electronic City Fire Station", // Places of Worship "Shirdi Sai Baba Temple, Gollahalli", "Sri Ganesha Temple, Gollahalli", "Kaveramma Temple, EC Phase 1", "Masjide Abbas, Shikaripalya", "Madeena Masjid, Shikaripalya", "Noor Masjid, Shikaripalya", // Parks & Recreation "Electronics City Park","Neeladri Nagar Park", "Doddathogur Lake Park","Veerasandra Lake","Heelalige Lake", "Huskur Lake","Bommasandra Park","Begur Fort & Lake", ]; // ─── Parks & Recreation (EC area) ──────────────────────────────────────────────── const PARKS = [ { name:"Electronics City Park", area:"EC Phase 1", type:"Park", icon:"🌳", desc:"Main community park near Infosys campus. Popular for morning walks and evening strolls.", timings:"5:00 AM – 8:00 PM", mapX:38, mapY:38, }, { name:"Neeladri Nagar Park", area:"Neeladri Nagar", type:"Park", icon:"🌿", desc:"Neighbourhood park with jogging track and children's play area.", timings:"5:30 AM – 8:00 PM", mapX:52, mapY:68, }, { name:"Doddathogur Lake", area:"Doddathogur", type:"Lake", icon:"🏞", desc:"Scenic lake with walking trail. Good spot for birdwatching in the early mornings.", timings:"Open all day", mapX:44, mapY:50, }, { name:"Veerasandra Lake", area:"Veerasandra", type:"Lake", icon:"🏞", desc:"Peaceful lake with walking path. Often used for morning fitness walks.", timings:"Open all day", mapX:58, mapY:56, }, { name:"Heelalige Lake", area:"Heelalige", type:"Lake", icon:"🏞", desc:"Lake near Heelalige railway station. Quiet retreat from the IT bustle.", timings:"Open all day", mapX:28, mapY:44, }, { name:"Huskur Lake", area:"Huskur Road", type:"Lake", icon:"🦅", desc:"Bird-watching hotspot. Migratory birds visit in winter months (Oct–Feb).", timings:"Open all day", mapX:64, mapY:67, }, { name:"Bommasandra Park", area:"Bommasandra", type:"Park", icon:"🌳", desc:"Community park near the industrial area. Maintained by BBMP.", timings:"6:00 AM – 7:30 PM", mapX:72, mapY:60, }, { name:"Begur Fort & Lake", area:"Begur (~3 km)", type:"Heritage + Lake", icon:"🏰", desc:"Historic fort with a lake. Popular weekend outing for EC families. Features ancient temple.", timings:"Open all day", mapX:34, mapY:62, }, { name:"Silk Board–EC Cycling Track", area:"Hosur Road", type:"Cycling / Jogging", icon:"🚴", desc:"Dedicated cycling and jogging stretch along Hosur Road. Best before 7 AM on weekdays.", timings:"Best: 5:00–7:30 AM", mapX:48, mapY:24, }, ]; // ─── Supermarkets & Grocery (EC area) ──────────────────────────────────────────── const SUPERMARKETS = [ { name:"Reliance Fresh", area:"EC Phase 1", icon:"🛒", type:"Supermarket", desc:"Daily essentials, fresh produce, dairy. Near Infosys Gate.", timings:"8:00 AM – 10:00 PM", mapX:40, mapY:34, }, { name:"More Supermarket", area:"EC Phase 1", icon:"🛒", type:"Supermarket", desc:"Full supermarket — staples, produce, household items.", timings:"8:00 AM – 10:00 PM", mapX:46, mapY:28, }, { name:"Nilgiri's", area:"EC Phase 2", icon:"🥛", type:"Supermarket", desc:"Fresh dairy, bakery, packaged foods and beverages.", timings:"8:00 AM – 9:30 PM", mapX:62, mapY:44, }, { name:"Spencer's", area:"EC Phase 2", icon:"🛍", type:"Supermarket", desc:"Mid-size supermarket with apparel, electronics and groceries.", timings:"9:00 AM – 10:00 PM", mapX:66, mapY:50, }, { name:"Safal / Mother Dairy", area:"EC Phase 1", icon:"🥦", type:"Fresh Produce", desc:"Fresh fruits, vegetables and dairy at subsidised prices.", timings:"7:00 AM – 8:00 PM", mapX:36, mapY:32, }, { name:"D-Mart", area:"Hosur Main Road, EC", icon:"🏬", type:"Hypermarket", desc:"D-Mart at Survey No.21, Hosur Main Road, Electronic City. Bulk buying hub for EC residents.", timings:"8:00 AM – 10:00 PM", mapX:71, mapY:63, }, { name:"Spar Hypermarket", area:"Silk Board (~4 km)", icon:"🏬", type:"Hypermarket", desc:"Full-format hypermarket on Hosur Road. Wide international brands selection.", timings:"9:00 AM – 10:00 PM", mapX:50, mapY:14, }, { name:"Local Kirana – Neeladri Nagar", area:"Neeladri Nagar", icon:"🏪", type:"Kirana / Daily Needs", desc:"Neighbourhood kirana for daily top-ups — milk, eggs, snacks, basics.", timings:"7:00 AM – 9:00 PM", mapX:53, mapY:70, }, { name:"Local Kirana – Doddathogur", area:"Doddathogur", icon:"🏪", type:"Kirana / Daily Needs", desc:"Local grocery store for residents of Doddathogur and surrounding layouts.", timings:"7:00 AM – 9:00 PM", mapX:43, mapY:52, }, { name:"Local Kirana – Gollahalli", area:"Gollahalli", icon:"🏪", type:"Kirana / Daily Needs", desc:"Neighbourhood store serving Gollahalli and Shikaripalya residents.", timings:"7:00 AM – 9:00 PM", mapX:30, mapY:38, }, ]; // ─── Schools & Daycare (EC area) ───────────────────────────────────────────────── const SCHOOLS = [ // K–12 Schools { name:"Delhi Public School (DPS)", area:"EC Phase 1", icon:"🏫", type:"CBSE · K–12", desc:"One of EC's most sought-after schools. Strong academics, sports and extracurriculars.", timings:"8:00 AM – 3:30 PM", phone:"080 2783 2020", mapX:40, mapY:26, }, { name:"National Public School (NPS)", area:"EC Phase 1", icon:"🏫", type:"CBSE · K–12", desc:"Well-regarded school known for board exam results and co-curricular activities.", timings:"8:00 AM – 3:00 PM", phone:"080 2852 4455", mapX:44, mapY:22, }, { name:"Harvest International School", area:"EC Phase 1", icon:"🏫", type:"CBSE + Cambridge · K–12", desc:"Dual-curriculum school offering CBSE and Cambridge pathways from KG to Grade 12.", timings:"8:00 AM – 3:30 PM", phone:"080 4168 3000", mapX:38, mapY:30, }, { name:"Orchids The International School", area:"EC Phase 2", icon:"🏫", type:"CBSE · K–12", desc:"Modern campus with activity-based learning. Strong focus on holistic development.", timings:"8:00 AM – 3:30 PM", phone:"1800 102 3737", mapX:62, mapY:42, }, { name:"Sri Chaitanya School", area:"EC Phase 1", icon:"🏫", type:"CBSE · K–12", desc:"Popular for IIT/NEET foundation from Class 6. Competitive academic environment.", timings:"7:30 AM – 3:30 PM", phone:"080 2783 0000", mapX:36, mapY:36, }, { name:"DAV Public School", area:"EC Phase 2", icon:"🏫", type:"CBSE · K–12", desc:"DAV group school with values-based education. Hindi medium option available.", timings:"8:00 AM – 3:00 PM", phone:"080 4121 9900", mapX:64, mapY:48, }, { name:"Ryan International School", area:"Bommasandra", icon:"🏫", type:"CBSE · K–12", desc:"Large campus near Bommasandra. Good sports facilities and tech labs.", timings:"8:00 AM – 3:30 PM", phone:"080 2783 5555", mapX:70, mapY:58, }, { name:"Ebenezer International School", area:"Neeladri Nagar", icon:"🏫", type:"CBSE · K–12", desc:"Community-oriented school in Neeladri Nagar. Affordable fees, good faculty.", timings:"8:00 AM – 3:00 PM", phone:"080 2783 1234", mapX:54, mapY:66, }, { name:"Kendriya Vidyalaya", area:"Electronic City", icon:"🏛", type:"CBSE · K–12 (Govt)", desc:"Central government school. Priority for govt employees. Subsidised fees.", timings:"7:30 AM – 2:30 PM", phone:"080 2852 0101", mapX:48, mapY:32, }, { name:"Podar International School", area:"EC Phase 2", icon:"🏫", type:"CBSE · K–12", desc:"Modern infrastructure with strong focus on digital learning.", timings:"8:00 AM – 3:30 PM", phone:"022 6633 5555", mapX:66, mapY:44, }, // Preschools & Daycares { name:"EuroKids Preschool", area:"EC Phase 1", icon:"👶", type:"Preschool · Age 1.5–6", desc:"Play-based curriculum. Extended daycare available till 7 PM.", timings:"8:30 AM – 7:00 PM", phone:"1800 210 8008", mapX:42, mapY:24, }, { name:"Kidzee", area:"EC Phase 2", icon:"👶", type:"Preschool · Age 1.5–6", desc:"Structured EYFS curriculum. AC classrooms with trained Montessori staff.", timings:"8:30 AM – 6:30 PM", phone:"1800 200 4444", mapX:60, mapY:40, }, { name:"Bachpan Play School", area:"Neeladri Nagar", icon:"👶", type:"Preschool + Daycare", desc:"Neighbourhood preschool with affordable fees. Good staff-to-child ratio.", timings:"8:00 AM – 6:00 PM", phone:"080 4500 5000", mapX:56, mapY:64, }, { name:"Maharishi Global School", area:"EC Phase 1 (near BHEL)", icon:"🏫", type:"CBSE · K–12", desc:"NDR Campus near BHEL Signal, Electronic City. Good academics and infrastructure.", timings:"8:00 AM – 3:30 PM", phone:"080 2852 9000", mapX:50, mapY:28, }, { name:"SFS Academy", area:"Kammasandra, EC Phase 1", icon:"🏫", type:"CBSE · K–12", desc:"SFS Academy at Kammasandra, Electronic City. Serves Ananth Nagar and nearby layouts.", timings:"8:00 AM – 3:00 PM", phone:"080 4500 1234", mapX:56, mapY:46, }, { name:"Shree Ananthnagar Vidyaniketan", area:"Ananth Nagar, EC Phase 1", icon:"🏫", type:"State Board · K–10", desc:"Local Kannada-medium school at 25th Cross, Shree Ananth Nagar. Affordable fees.", timings:"8:00 AM – 2:30 PM", phone:"080 4500 5678", mapX:54, mapY:44, }, { name:"Pavithra Public High School", area:"Hebbagodi", icon:"🏫", type:"State Board · K–10", desc:"School near Hebbagodi Arch, Electronic City. Serves Hebbagodi and Bommasandra layouts.", timings:"8:00 AM – 2:30 PM", phone:"080 2783 6789", mapX:26, mapY:55, }, ]; // ─── Hospitals & Clinics (EC area) ─────────────────────────────────────────────── const HOSPITALS = [ { name:"Narayana Health City", area:"Bommasandra", icon:"🏥", type:"Multi-Speciality", desc:"One of India's largest hospitals. Full emergency, ICU, cardiac, cancer care. 24×7.", timings:"24 Hours", phone:"1800 102 6672", mapX:72, mapY:65, }, { name:"Fortis Hospital", area:"Hosur Road (~5 km)", icon:"🏥", type:"Multi-Speciality", desc:"Fortis group hospital with advanced surgery, orthopaedics and neurology.", timings:"24 Hours", phone:"080 6621 4444", mapX:46, mapY:16, }, { name:"Trinity Healthcare Clinic", area:"EC Phase 1", icon:"🏥", type:"Clinic / OPD", desc:"General physician, paediatrics, gynaecology OPD. Nearest clinic for EC Phase 1.", timings:"9:00 AM – 9:00 PM", phone:"080 4968 0000", mapX:40, mapY:28, }, { name:"Manipal Hospital", area:"Sarjapur (~8 km)", icon:"🏥", type:"Multi-Speciality", desc:"Manipal group tertiary hospital. Strong ortho, neuro and transplant units.", timings:"24 Hours", phone:"080 2502 4444", mapX:78, mapY:28, }, { name:"Sparsh Hospital", area:"EC Phase 2", icon:"🏥", type:"Orthopaedics Speciality", desc:"India's leading orthopaedic chain. Sports injuries, joint replacement, spine.", timings:"24 Hours", phone:"080 4600 0000", mapX:62, mapY:46, }, { name:"PHC Doddathogur", area:"Doddathogur", icon:"🏥", type:"Govt Primary Health Centre", desc:"Government PHC serving Doddathogur, Kammasandra and nearby villages. Free OPD.", timings:"9:00 AM – 5:00 PM", phone:"080 2852 0200", mapX:44, mapY:52, }, { name:"NIMHANS", area:"Hosur Road (~6 km)", icon:"🏥", type:"Mental Health (Govt)", desc:"National Institute of Mental Health and Neurosciences. OPD by appointment.", timings:"9:00 AM – 4:00 PM", phone:"080 4611 5900", mapX:40, mapY:12, }, ]; // ─── Petrol Pumps (EC area) ─────────────────────────────────────────────────────── const PETROL_PUMPS = [ { name:"HPCL Petrol Pump", area:"Neeladri Road, EC Ph1", icon:"⛽", type:"HPCL", desc:"24-hour fuel station on Neeladri Road. Petrol, diesel, air & CNG.", timings:"24 Hours", mapX:50, mapY:36, }, { name:"BPCL Petrol Pump", area:"EC Phase 2", icon:"⛽", type:"BPCL", desc:"Bharat Petroleum outlet near EC Phase 2. Petrol, diesel, lubricants.", timings:"24 Hours", mapX:62, mapY:50, }, { name:"Indian Oil Petrol Pump", area:"Hosur Road (near EC)", icon:"⛽", type:"Indian Oil", desc:"Indian Oil station on Hosur Road service road. Petrol, diesel, EV charging bay.", timings:"24 Hours", mapX:44, mapY:16, }, { name:"HP Petrol Pump", area:"Bommasandra", icon:"⛽", type:"HP", desc:"HP pump near Bommasandra Junction. Petrol, diesel, tyre-air.", timings:"6:00 AM – 10:00 PM", mapX:68, mapY:60, }, { name:"Shell Petrol Pump", area:"Hosur Road", icon:"⛽", type:"Shell", desc:"Shell premium fuel station. Petrol, diesel, Shell V-Power and convenience store.", timings:"24 Hours", mapX:38, mapY:14, }, ]; // ─── Hotels & Stay (EC area) ────────────────────────────────────────────────────── const HOTELS = [ { name:"Golden Tulip Hotel", area:"EC Phase 1", icon:"🏨", type:"4-Star", desc:"Business hotel with banquet halls, restaurant and pool. Popular for corporate stays.", timings:"24 Hours", phone:"080 4040 4040", mapX:38, mapY:34, }, { name:"Lemon Tree Hotel", area:"Electronic City", icon:"🏨", type:"3-Star", desc:"Comfortable mid-scale hotel near IT campuses. Restaurant, bar and gym.", timings:"24 Hours", phone:"080 6175 6175", mapX:44, mapY:38, }, { name:"Treebo Trend", area:"EC Phase 2", icon:"🏨", type:"Budget", desc:"Clean, affordable Treebo-certified hotel. Good for short corporate or family stays.", timings:"24 Hours", phone:"1800 266 0000", mapX:64, mapY:52, }, { name:"FabHotel EC Phase 1", area:"EC Phase 1", icon:"🏨", type:"Budget", desc:"Budget hotel with AC rooms and complimentary breakfast. Well-reviewed.", timings:"24 Hours", phone:"1800 212 4545", mapX:46, mapY:32, }, { name:"OYO Rooms EC Phase 2", area:"EC Phase 2", icon:"🏨", type:"Budget", desc:"Multiple OYO-certified guesthouses in EC Phase 2. Book via OYO app.", timings:"24 Hours", phone:"093 1393 1393", mapX:66, mapY:46, }, { name:"Shivam Hotel", area:"EC Phase 2", icon:"🏨", type:"Budget", desc:"Budget hotel beside Tech Mahindra back gate, opp. TCS. Popular with IT professionals.", timings:"24 Hours", phone:"080 4500 2222", mapX:60, mapY:48, }, { name:"Ecity Luxury Stay", area:"Shanthipura, EC Phase 2", icon:"🏨", type:"PG / Serviced Apt", desc:"GPR Huskur area. Serviced apartments near APMC Wholesale Fruit Market.", timings:"24 Hours", mapX:58, mapY:42, }, { name:"Royal Delux PG", area:"Huskur Gate", icon:"🏨", type:"PG / Guest House", desc:"PG accommodation at 5th Cross, GPR Royale Layout, Huskur Gate. Good for long stays.", timings:"24 Hours", mapX:64, mapY:40, }, ]; // ─── Temples & Places of Worship (EC area) ──────────────────────────────────────── const TEMPLES = [ { name:"Kaveramma Temple", area:"EC Phase 1", icon:"🛕", type:"Hindu Temple", desc:"Presiding deity of Electronic City. Annual Kaveramma Jatre festival draws large crowds.", timings:"6:00 AM – 8:00 PM", mapX:42, mapY:32, }, { name:"Shirdi Sai Baba Temple", area:"Gollahalli", icon:"🛕", type:"Hindu Temple", desc:"Popular Sai Baba temple in Gollahalli. Bhajans on Thursdays.", timings:"6:00 AM – 8:30 PM", mapX:30, mapY:36, }, { name:"Sri Ganesha Temple", area:"Gollahalli", icon:"🛕", type:"Hindu Temple", desc:"Neighbourhood Ganesha temple. Vinayaka Chaturthi celebrations are grand.", timings:"6:00 AM – 8:00 PM", mapX:28, mapY:40, }, { name:"Anjaneya Temple", area:"Veerasandra", icon:"🛕", type:"Hindu Temple", desc:"Hanuman temple in Veerasandra. Saturdays are especially busy.", timings:"6:00 AM – 8:30 PM", mapX:56, mapY:58, }, { name:"Doddathogur Anjaneya Temple",area:"Doddathogur", icon:"🛕", type:"Hindu Temple", desc:"Ancient Anjaneya temple in Doddathogur village. Peaceful surroundings.", timings:"6:00 AM – 7:30 PM", mapX:44, mapY:48, }, { name:"Murugan Temple", area:"EC Phase 2", icon:"🛕", type:"Hindu Temple", desc:"Murugan temple serving the large Tamil community in EC Phase 2.", timings:"6:00 AM – 8:00 PM", mapX:60, mapY:50, }, { name:"Masjide Abbas", area:"Shikaripalya", icon:"🕌", type:"Mosque", desc:"Main mosque serving the Shikaripalya community. Friday Jumu'ah prayers.", timings:"5:00 AM – 9:00 PM", mapX:32, mapY:42, }, { name:"Madeena Masjid", area:"Shikaripalya", icon:"🕌", type:"Mosque", desc:"Neighbourhood mosque in Shikaripalya. Five daily prayers.", timings:"5:00 AM – 9:00 PM", mapX:26, mapY:44, }, { name:"St. Mary's Church", area:"EC Phase 1", icon:"⛪", type:"Church", desc:"Catholic church serving EC's Christian community. Sunday Mass at 7 AM and 9 AM.", timings:"Sun Mass 7 AM & 9 AM", mapX:44, mapY:26, }, { name:"Muneshwara Temple", area:"EC Phase 2", icon:"🛕", type:"Hindu Temple", desc:"Muneshwara Temple in Electronic City Phase II. Local deity temple, peaceful surroundings.", timings:"6:00 AM – 8:00 PM", mapX:56, mapY:44, }, { name:"Sri Kaveramma Temple", area:"Veerasandra, EC Phase 2", icon:"🛕", type:"Hindu Temple", desc:"Sri Kaveramma Temple on Veerasandra Main Road. Popular among IT professionals.", timings:"6:00 AM – 8:30 PM", mapX:58, mapY:54, }, { name:"Fruit Market Masjid", area:"Gulimangala", icon:"🕌", type:"Mosque", desc:"Masjid near the fruit market in Gulimangala, EC Phase 2 area.", timings:"5:00 AM – 9:00 PM", mapX:62, mapY:56, }, { name:"Masjid Maimun-O-Shams", area:"Konappana Agrahara", icon:"🕌", type:"Mosque", desc:"Masjid on Service Road, Muniswamy Layout, Konappana Agrahara.", timings:"5:00 AM – 9:00 PM", mapX:54, mapY:38, }, { name:"Masjid Abu Ubaida", area:"Gollahalli", icon:"🕌", type:"Mosque", desc:"Masjid in Gollahalli serving the local Muslim community.", timings:"5:00 AM – 9:00 PM", mapX:26, mapY:42, }, ]; // ─── Cinemas & Entertainment (near EC) ─────────────────────────────────────────── const CINEMAS = [ { name:"Srinivasa Chitramandira", area:"Hebbagodi (~2 km)", icon:"🎬", type:"Single Screen", desc:"Local theatre on Bhavani Road, Hebbagodi. Kannada and Tamil films. Budget-friendly.", timings:"10:00 AM – 10:00 PM", mapX:28, mapY:58, }, { name:"Shrinivasa Theatre", area:"EC Phase 2 (Bhavani Rd)", icon:"🎬", type:"Single Screen", desc:"Popular local theatre in Electronic City. Shows Kannada, Telugu and Tamil films.", timings:"10:00 AM – 10:30 PM", mapX:32, mapY:56, }, { name:"Sri Venkateshwara Theatre", area:"Konappana Agrahara", icon:"🎬", type:"Single Screen", desc:"Neighbourhood theatre on Hosur Road, Konappana Agrahara. Kannada, Tamil films.", timings:"10:00 AM – 10:00 PM", mapX:56, mapY:36, }, { name:"Sre Venkata Theater", area:"Konappana Agrahara", icon:"🎬", type:"Single Screen", desc:"Local single-screen theatre on Service Road, Konappana Agrahara.", timings:"10:00 AM – 10:00 PM", mapX:58, mapY:38, }, { name:"PVR Cinemas – Forum Mall", area:"Hosur Road (~4 km)", icon:"🎬", type:"Multiplex", desc:"Nearest PVR multiplex. Latest releases in Hindi, Tamil, Kannada, Telugu, English.", timings:"10:00 AM – 11:30 PM", phone:"0844 2144 444", mapX:44, mapY:12, }, ]; // ─── ATMs (EC area) ─────────────────────────────────────────────────────────────── const ATMS = [ { name:"SBI ATM", area:"EC Phase 1", icon:"🏧", type:"State Bank of India", desc:"SBI branch ATM on EC Phase 1 main road. 24-hour access.", timings:"24 Hours", mapX:40, mapY:30, }, { name:"HDFC Bank ATM", area:"EC Phase 2", icon:"🏧", type:"HDFC Bank", desc:"HDFC ATM near EC Phase 2 main junction.", timings:"24 Hours", mapX:62, mapY:44, }, { name:"ICICI Bank ATM", area:"EC Phase 1", icon:"🏧", type:"ICICI Bank", desc:"ICICI ATM inside IT campus service road. Accessible to all.", timings:"24 Hours", mapX:44, mapY:26, }, { name:"Canara Bank ATM", area:"EC Phase 1", icon:"🏧", type:"Canara Bank", desc:"Canara Bank ATM near Electronic City main bus stop.", timings:"24 Hours", mapX:38, mapY:28, }, { name:"Axis Bank ATM", area:"Neeladri Nagar", icon:"🏧", type:"Axis Bank", desc:"Axis Bank ATM in Neeladri Nagar. Convenient for apartment residents.", timings:"24 Hours", mapX:52, mapY:72, }, { name:"Kotak Bank ATM", area:"EC Phase 2", icon:"🏧", type:"Kotak Mahindra Bank", desc:"Kotak ATM near EC Phase 2 commercial area.", timings:"24 Hours", mapX:64, mapY:46, }, { name:"Yes Bank ATM", area:"Hosur Road", icon:"🏧", type:"Yes Bank", desc:"Yes Bank ATM on Hosur Road service road near EC entrance.", timings:"24 Hours", mapX:42, mapY:14, }, { name:"Doddathogur SBI ATM", area:"Doddathogur", icon:"🏧", type:"State Bank of India", desc:"SBI ATM serving Doddathogur, Kammasandra and Neotown residents.", timings:"24 Hours", mapX:46, mapY:54, }, { name:"Karnataka Bank ATM", area:"Kammasandra, EC Phase 2", icon:"🏧", type:"Karnataka Bank", desc:"Karnataka Bank ATM on Anantha Nagar Road, Kammasandra.", timings:"24 Hours", mapX:58, mapY:50, }, { name:"Central Bank of India ATM", area:"Kammasandra, EC Phase 2", icon:"🏧", type:"Central Bank of India", desc:"Central Bank ATM serving Kammasandra and Ananth Nagar residents.", timings:"24 Hours", mapX:60, mapY:52, }, ]; // ─── Restaurants & Cafés (EC area) ─────────────────────────────────────────────── const RESTAURANTS = [ { name:"Hotel Millennium Plaza", area:"Huskur Gate", icon:"🍽️", type:"Multi-Cuisine", desc:"Popular restaurant at Huskur Gate opp. Vimalaya Hospital, near Biocon Factory.", timings:"7:00 AM – 11:00 PM", phone:"080 4500 3000", mapX:62, mapY:36, }, { name:"Brunch & Munch", area:"Huskur Gate", icon:"🥗", type:"Café / Brunch", desc:"Café at Huskur Gate near Biocon. Brunch, sandwiches, healthy bowls.", timings:"8:00 AM – 10:00 PM", mapX:64, mapY:34, }, { name:"Café Coffee Day", area:"Hosur Main Road", icon:"☕", type:"Café", desc:"CCD outlet next to Biocon on Hosur Main Road, Bommasandra. Coffee, snacks, free Wi-Fi.", timings:"7:00 AM – 10:30 PM", mapX:68, mapY:58, }, { name:"Bhukkads", area:"Shanthipura, EC Phase 2", icon:"🍽️", type:"Multi-Cuisine", desc:"Popular restaurant on Shanthipura Main Road, EC Phase 2. Budget meals and thalis.", timings:"11:00 AM – 11:00 PM", mapX:60, mapY:38, }, { name:"Pizza Republic", area:"EC Phase 2", icon:"🍕", type:"Pizza / Fast Food", desc:"Pizza and fast food in Electronic City Phase II. Dine-in and delivery.", timings:"11:00 AM – 11:30 PM", mapX:62, mapY:40, }, { name:"Veg Thali Corner", area:"Neeladri Nagar", icon:"🍛", type:"Vegetarian", desc:"Popular veg thali restaurant in Neeladri Nagar. Affordable and filling meals.", timings:"11:30 AM – 10:30 PM", mapX:52, mapY:68, }, { name:"Darshini (EC Phase 1)", area:"EC Phase 1", icon:"☕", type:"South Indian / Darshini", desc:"Quick-service South Indian darshini near Infosys Gate. Idli, dosa, coffee.", timings:"6:30 AM – 10:00 PM", mapX:40, mapY:30, }, { name:"Andhra Mess", area:"Doddathogur", icon:"🍽️", type:"Andhra / Non-Veg", desc:"Authentic Andhra meals and biryani in Doddathogur. Favourite of IT workers.", timings:"12:00 PM – 10:30 PM", mapX:44, mapY:50, }, ]; // ─── Bus Stops (EC Phase 1 & surrounding) ──────────────────────────────────────── const BUS_STOPS = [ // BMTC stops — EC Phase 1 "Shikaripalya Cross","Electronic City Infosys Gate", "Electronic City Wipro Gate","Electronic City State Bank", "Dodda Togur","Electronic City Phase 1 (Main Stop)", "Gollahalli Bus Stop","Neotown Bus Stop", "Velankani Tech Park Stop","Neeladri Nagar Stop", // EC Phase 2 / surrounding "Electronic City Phase 2 Bus Stop","Hebbagodi Bus Terminal", "Bommasandra Bus Stop","Veerasandra Bus Stop", "Konappana Agrahara Bus Stop","Huskur Road Bus Stop", "Shanthipura Bus Stop","Huskur Gate Bus Stop", "Veerasandra (EC Phase 2) Bus Stop","BTM Phase 1 Bus Stop", "Electronic City Phase 2 (Main)","Gulimangala Bus Stop", // Railway stations (nearest) "Heelalige Railway Station","Karmelaram Railway Station", ]; // BMTC bus routes serving EC Phase 1 const BUS_ROUTES = [ "G2 (Silk Board ↔ Electronic City)","V356Q","V375A","V505A","V505C", "335E (Majestic ↔ Electronic City)","KBS-14 (Kempegowda Bus Station)", "410D (Electronic City ↔ Bharathnagar)", "411D (Marathahalli Bridge ↔ Chandapura Circle)", "500H (Chandapura Circle ↔ K R Puram)", "500J (Chandapura Circle ↔ Yeshwanthpur)", "600 (Banashankari ↔ Banashankari)", ]; // ─── Helpline Numbers ──────────────────────────────────────────────────────────── const HELPLINES = [ // National Emergency { cat:"Emergency", icon:"🚨", name:"Police", phone:"100", color:"#DC2626" }, { cat:"Emergency", icon:"🔥", name:"Fire Station", phone:"101", color:"#EA580C" }, { cat:"Emergency", icon:"🚑", name:"Ambulance", phone:"108", color:"#DC2626" }, { cat:"Emergency", icon:"👩", name:"Women Helpline", phone:"1091", color:"#9333EA" }, { cat:"Emergency", icon:"👶", name:"Child Helpline", phone:"1098", color:"#2563EB" }, { cat:"Emergency", icon:"🚨", name:"Disaster Helpline", phone:"1077", color:"#B45309" }, // Electronic City Local { cat:"EC Local", icon:"👮", name:"EC Traffic Police Station", phone:"080 2852 3253", color:"#1D4ED8" }, { cat:"EC Local", icon:"👮", name:"Hebbagodi Police Station", phone:"080 2783 5900", color:"#1D4ED8" }, { cat:"EC Local", icon:"🚒", name:"EC Fire Station", phone:"080 2782 1101", color:"#EA580C" }, { cat:"EC Local", icon:"🏥", name:"Narayana Health (EC)", phone:"1800 102 6672", color:"#059669" }, { cat:"EC Local", icon:"🏥", name:"Trinity Healthcare Clinic", phone:"080 4968 0000", color:"#059669" }, // Utilities { cat:"Utilities", icon:"⚡", name:"BESCOM (Power Outage)", phone:"1912", color:"#D97706" }, { cat:"Utilities", icon:"💧", name:"BWSSB (Water)", phone:"1916", color:"#0284C7" }, { cat:"Utilities", icon:"🔗", name:"BBMP Ward Office (EC)", phone:"080 2252 0330", color:"#7C3AED" }, { cat:"Utilities", icon:"🏛", name:"Bangalore One (Citizens)", phone:"080 2295 5568", color:"#6D28D9" }, // Transport { cat:"Transport", icon:"🚌", name:"BMTC Helpline (Toll-Free)", phone:"1800 425 1663", color:"#0369A1" }, { cat:"Transport", icon:"🚍", name:"KSRTC (Majestic)", phone:"080 2226 9508", color:"#065F46" }, { cat:"Transport", icon:"🚇", name:"BMRCL Metro Helpline", phone:"080 4969 4969", color:"#7C3AED" }, // Medical { cat:"Medical", icon:"🏥", name:"NIMHANS", phone:"080 4611 5900", color:"#059669" }, { cat:"Medical", icon:"💊", name:"Apollo Pharmacy (24hr)", phone:"1860 500 1066", color:"#DC2626" }, { cat:"Medical", icon:"🩸", name:"Blood Bank (BBMP)", phone:"104", color:"#DC2626" }, // Police / Citywide { cat:"Police", icon:"🖥", name:"Cyber Crime Police", phone:"080 2237 5522", color:"#1D4ED8" }, { cat:"Police", icon:"👮", name:"Commissioner of Police", phone:"080 2294 2222", color:"#1E40AF" }, { cat:"Police", icon:"🚦", name:"Traffic Control Room", phone:"080 2294 3131", color:"#1D4ED8" }, ]; // ─── SmartInput ───────────────────────────────────────────────────────────────── // groupedOptions: [{group, icon, items[]}] – show category headers in dropdown // options: string[] – flat list (legacy / apartment picker) // fromDropdown=true → value came from a list pick (trusted, no char-validation needed) // fromDropdown=false → value was typed manually (run stripFn + validate) function SmartInput({ label, placeholder, options=[], groupedOptions=null, value, onChange, icon="🔍", filterFn, error }) { const [query, setQuery] = useState(value||""); const [open, setOpen] = useState(false); const [manual, setManual] = useState(false); const [confirmed,setConfirmed]= useState(!!value); const ref = useRef(null); useEffect(()=>{ const h=e=>{ if(ref.current&&!ref.current.contains(e.target)) setOpen(false); }; document.addEventListener("mousedown",h); return ()=>document.removeEventListener("mousedown",h); },[]); // Build a flat list from grouped options for easy filtering const allGroupedFlat = groupedOptions ? groupedOptions.flatMap(g=>g.items) : []; const effectiveOptions = groupedOptions ? allGroupedFlat : options; // When typing: flat filtered results; when browsing: use grouped layout (handled in render) const flatSuggestions = query.length>=1 ? effectiveOptions.filter(o=>o.toLowerCase().includes(query.toLowerCase())).slice(0,10) : effectiveOptions.slice(0,6); const select=(opt)=>{ setQuery(opt); setConfirmed(true); setOpen(false); setManual(false); onChange(opt, true); }; const goManual=()=>{ const pre = filterFn ? filterFn(query) : query; setManual(true); setOpen(false); setConfirmed(false); setQuery(pre); onChange(pre, false); }; const clear=()=>{ setQuery(""); setConfirmed(false); setManual(false); onChange("", false); setOpen(false); }; const handleChange=(e)=>{ let v=e.target.value; if(filterFn) v=filterFn(v); setQuery(v); setConfirmed(false); onChange(v, false); if(!manual) setOpen(true); }; // Renders a single option row with query highlight const OptionRow = ({opt, rowIcon}) => { const q = query.toLowerCase(); const idx = q.length>0 ? opt.toLowerCase().indexOf(q) : -1; const b=idx>=0?opt.slice(0,idx):"", m=idx>=0?opt.slice(idx,idx+q.length):"", a=idx>=0?opt.slice(idx+q.length):opt; return ( ); }; // Grouped browse view (no query typed): show section headers + items const GroupedList = () => ( <> {groupedOptions.map(grp=>(
{grp.icon} {grp.group}
{grp.items.map(opt=>)}
))} ); // Flat filtered view (query typed): results from all groups const FlatList = () => ( flatSuggestions.length>0?( flatSuggestions.map(opt=>{ const grpIcon = groupedOptions ? (groupedOptions.find(g=>g.items.includes(opt))||{}).icon : "🏢"; return ; }) ):(
🤔
No matches found
Try different spelling or enter manually
) ); return (
{label && }
{icon} { if(!manual) setOpen(true); }} autoComplete="off" /> {confirmed&&!open&&( )} {query.length>0&&( )}
{manual&&(
✏️ Entering manually –
)} {open&&!manual&&(
{/* Show grouped headers when browsing; flat filtered results when typing */} {groupedOptions && query.length===0 ? : }
Not in the list?
)}
); } // ─── Logo ─────────────────────────────────────────────────────────────────────── // MT mark: M = double-peak roofline · T = chimney/tower // Four pillars: HOME · SECURITY (shield) · CONNECTING (WiFi arcs) · HELPFUL (♥ door) function Logo({size=44}){ return( {/* ══ SECURITY — Shield body ══ */} {/* Inner depth highlight */} {/* ══ CONNECTING — WiFi broadcast arcs above chimney ══ */} {/* Signal apex dot */} {/* Outer arc — broadest reach */} {/* Inner arc — closer signal */} {/* ══ T — chimney tower (T = Together / Transmit) ══ */} {/* T crossbar */} {/* T vertical stem — drops to M valley */} {/* ══ M — double-peak roofline (M = MyTown) ══ */} {/* Left peak (16,20)·valley (26,26)·right peak (36,20) spells M */} {/* ══ HOME — house walls, windows ══ */} {/* Left window */} {/* Right window */} {/* Mint door — welcoming entry */} {/* ══ HELPFUL — heart inside door ══ */} ); } // ─── Avatar ───────────────────────────────────────────────────────────────────── function Avatar({initials,color=C.purple,size=36}){ return(
{initials}
); } // ─── Verified ─────────────────────────────────────────────────────────────────── function Verified(){ return( Verified ); } // ─── Bottom Nav ───────────────────────────────────────────────────────────────── const TABS=[ {id:"feed", icon:"🏘", label:"Feed", grad:G.tabFeed}, {id:"events", icon:"📅", label:"Events", grad:G.tabEvents}, {id:"community", icon:"🏛", label:"Leaders", grad:G.tabCommunity}, {id:"messages", icon:"✉️", label:"Messages", grad:G.tabMessages}, {id:"profile", icon:"👤", label:"Profile", grad:G.tabProfile}, ]; function BottomNav({tab,setTab}){ const myPhase = ELECTION_PHASES[MY_STATS.area]; const electionLive = myPhase==="voting" || myPhase==="pre_election"; return( ); } const NOTIF_ITEMS=[ {id:1, icon:"⚠️", title:"Safety Alert", body:"Suspicious activity near Gate 3, EC Phase 1", time:"2 min ago", col:"#FF6B7A", read:false}, {id:2, icon:"🗳", title:"Election Update", body:"Nominations open for EC Phase 2 Community Admin",time:"1 hr ago", col:"#D97706", read:false}, {id:3, icon:"🎉", title:"Event Reminder", body:"Holi Celebration at Electronics City Park — tomorrow 6 PM",time:"3 hr ago",col:"#4F46E5",read:false}, {id:4, icon:"✓", title:"Account Verified", body:"Your resident account has been approved", time:"Yesterday", col:"#00B89F", read:true}, {id:5, icon:"📢", title:"Community Announcement", body:"Water supply maintenance 9 AM–1 PM on 5th March", time:"Yesterday", col:"#5C2D91", read:true}, ]; function TopBar({setScreen, onMenuOpen}){ const [notifOpen, setNotifOpen] = useState(false); const [notifs, setNotifs] = useState(NOTIF_ITEMS); const unread = notifs.filter(n=>!n.read).length; const markAllRead = () => setNotifs(n=>n.map(x=>({...x,read:true}))); const markRead = (id) => setNotifs(n=>n.map(x=>x.id===id?{...x,read:true}:x)); return(
{/* Hamburger */} {/* Logo + brand */}
MyTown 360
EC · Bangalore ✦
{/* Bell button */} {/* Avatar */}
{/* ── Notification panel (slides down) ── */} {notifOpen&&(
{/* Panel header */}
Notifications {unread>0&&{unread} new}
{unread>0&&( )}
{/* Notification list */}
{notifs.map(n=>(
markRead(n.id)} style={{ display:"flex",gap:11,padding:"11px 16px", background:n.read?"#fff":"linear-gradient(135deg,rgba(92,45,145,0.04),#fff)", borderBottom:`1px solid ${C.border}`, cursor:"pointer", borderLeft:`3px solid ${n.read?"transparent":n.col}`, }}> {/* Icon bubble */}
{n.icon}
{/* Text */}
{n.title} {n.time}
{n.body}
{/* Unread dot */} {!n.read&&
}
))}
{/* Footer */}
)}
); } // ─── Sidebar Drawer ────────────────────────────────────────────────────────── // Sidebar only contains items NOT already in the bottom nav // Bottom nav covers: Feed · Events · Leaders · Messages · Profile const SIDEBAR_ACTIONS=[ { id:"map", icon:"🗺", label:"Neighbours Map", sub:"Interactive map of your area", color:C.purple }, { id:"community_apply",icon:"✍️", label:"Apply for Community Admin", sub:"Stand for election in your area", color:C.mint, highlight:true }, { id:"contact_admin", icon:"📞", label:"Contact Community Admin", sub:"Message your area's current manager", color:C.purple }, ]; const SIDEBAR_QUICK=[ {icon:"🛡️", label:"Safety Alerts", color:"#FF6B7A", id:"feed"}, {icon:"🔧", label:"Service Providers", color:"#5C2D91", id:"feed"}, {icon:"⭐", label:"Recommendations", color:"#00B89F", id:"feed"}, {icon:"🗺️", label:"Area Map", color:"#4F46E5", id:"map"}, {icon:"📞", label:"Helplines", color:"#DC2626", id:"helplines"}, {icon:"📅", label:"Events", color:"#D97706", id:"events"}, ]; function Sidebar({open, onClose, nav, activeTab}){ useEffect(()=>{ document.body.style.overflow = open ? "hidden" : ""; return ()=>{ document.body.style.overflow=""; }; },[open]); useEffect(()=>{ const h=(e)=>{ if(e.key==="Escape") onClose(); }; window.addEventListener("keydown",h); return ()=>window.removeEventListener("keydown",h); },[onClose]); return( <> {/* Backdrop */}
{/* Panel */} ); } // ─── SCREEN: Login ──────────────────────────────────────────────────────────── function LoginScreen({nav}){ const [mode,setMode]=useState("email"); // "email" | "phone" const [identifier,setIdentifier]=useState(""); // email or phone value const [password,setPassword]=useState(""); const [showPw,setShowPw]=useState(false); const [errs,setErrs]=useState({}); const [submitted,setSubmitted]=useState(false); const setErr=(k,msg)=>setErrs(e=>msg?{...e,[k]:msg}:(({[k]:_,...rest})=>rest)(e)); const idLabel = mode==="email"?"Email Address":"Mobile Number"; const idPlaceholder = mode==="email"?"name@gmail.com":"98450 XXXXX"; const validateId = v => mode==="email" ? vEmail(v) : vPhone(v); const filterInput = v => mode==="email" ? stripEmail(v) : stripPhone(v); const handleIdChange = e => { const v = filterInput(e.target.value); setIdentifier(v); if(errs.identifier) setErr("identifier", validateId(v)); }; const handlePwChange = e => { setPassword(e.target.value); if(errs.password) setErr("password", vPassword(e.target.value)); }; const handleSignIn = () => { const idErr = validateId(identifier); const pwErr = vPassword(password); const newErrs = {}; if(idErr) newErrs.identifier = idErr; if(pwErr) newErrs.password = pwErr; if(Object.keys(newErrs).length){ setErrs(newErrs); return; } setSubmitted(true); // Simulate success — navigate to feed setTimeout(()=>nav("feed"), 900); }; if(submitted) return(
Signing you in…
Welcome back to MyTown 360
); return(
{/* Header */}
Sign in to MyTown 360
mytown360.in ✦
{/* Body — centred, responsive */}
{/* Logo + welcome */}
Welcome Back!
Sign in to your verified neighbourhood account
{/* Mode toggle */}
{[["email","📧 Email"],["phone","📱 Phone"]].map(([m,l])=>( ))}
{/* Identifier field */}
{mode==="email"?"📧":"📱"} setErr("identifier",validateId(identifier))} autoComplete={mode==="email"?"email":"tel"}/>
{errs.identifier&&

⚠ {errs.identifier}

}
{/* Password field */}
🔒 setErr("password",vPassword(password))} autoComplete="current-password"/>
{errs.password&&

⚠ {errs.password}

}
{/* Forgot password */}
{/* Sign in button */} {/* Divider */}
OR
{/* Recovery / create account options */}
); } // ─── SCREEN: Forgot Account Recovery ───────────────────────────────────────── function ForgotScreen({nav}){ const [step,setStep]=useState(0); // 0=choose method, 1=enter details, 2=otp, 3=success const [method,setMethod]=useState(""); // "email" | "phone" const [value,setValue]=useState(""); const [otp,setOtp]=useState(["","","","","",""]); const [recoverType,setRecoverType]=useState("password"); // "password" | "userid" const [errs,setErrs]=useState({}); const setErr=(k,msg)=>setErrs(e=>msg?{...e,[k]:msg}:(({[k]:_,...rest})=>rest)(e)); const validate=()=>{ const err = method==="email"?vEmail(value):vPhone(value); if(err){setErr("value",err);return false;} return true; }; const handleSend=()=>{ if(!method){setErr("method","Please choose a recovery method");return;} if(!validate()) return; setStep(2); }; const handleOtpChange=(i,v)=>{ const d=v.replace(/\D/,"").slice(0,1); const next=[...otp]; next[i]=d; setOtp(next); if(d&&i<5){ const el=document.getElementById(`otp-${i+1}`); if(el) el.focus(); } }; const handleVerify=()=>{ if(otp.join("").length<6){setErr("otp","Enter all 6 digits");return;} setStep(3); }; const Screen0=(
🔐
Recover Your Account
What would you like to recover?
{/* Recover type */}
{[["password","🔑 Password"],["userid","🪪 Email / Phone"]].map(([t,l])=>( ))}
How do you want to receive the OTP?
{[["email","📧","Via Email Address","Enter your registered email"],["phone","📱","Via Mobile Number","Enter your registered phone"]].map(([m,ic,title,sub])=>( ))}
{errs.method&&

⚠ {errs.method}

} {method&&(
{method==="email"?"📧":"📱"} { const v=method==="email"?stripEmail(e.target.value):stripPhone(e.target.value); setValue(v); if(errs.value)setErr("value",method==="email"?vEmail(v):vPhone(v)); }} onBlur={()=>validate()}/>
{errs.value&&

⚠ {errs.value}

}
)}
); const Screen2=(
{method==="email"?"📧":"📱"}
Enter Verification Code
We sent a 6-digit OTP to {method==="email"?"your email":"your mobile"}
{value}
{otp.map((digit,i)=>( handleOtpChange(i,e.target.value)} onKeyDown={e=>{if(e.key==="Backspace"&&!digit&&i>0){const el=document.getElementById(`otp-${i-1}`);if(el)el.focus();}}}/> ))}
{errs.otp&&

⚠ {errs.otp}

}

Didn't receive it?

); const Screen3=(
🎉
Verified!
{recoverType==="password"?"You can now set a new password for your account.":"Your registered email / phone has been sent to you."}
{recoverType==="password"&&(
🔒
)}
); return(
{/* Header */}
Account Recovery
MyTown 360 · mytown360.in
{/* Step dots */}
{[0,2,3].map((s,i)=>(
s?C.mint:step===s?C.purple:C.border}}/> ))}
{step===0&&Screen0} {step===2&&Screen2} {step===3&&Screen3}
); } // ─── SCREEN: Landing ───────────────────────────────────────────────────────── function LandingScreen({nav}){ return(
{/* ── Animated mesh gradient background ── */}
{/* Main gradient layer */}
{/* Orb 1 — purple */}
{/* Orb 2 — mint */}
{/* Orb 3 — coral accent */}
{/* Fine dot grid overlay */}
{/* ── Hero section ── */}
{/* Logo with glow ring */}
{/* Brand name with gradient text */}

MyTown 360

✦ mytown360.in ✦

Your Real Neighbourhood, Online.

Electronic City · Hebbagodi · Bommasandra & beyond

{/* ── Feature cards — glassy 2×2 grid ── */}
{[ {col:"#7B4BB8",ic:"🛡️",t:"ID Verified", s:"Real neighbours only", grad:"linear-gradient(135deg,rgba(92,45,145,0.5),rgba(123,75,184,0.2))"}, {col:"#00B89F",ic:"📍",t:"Hyper-Local", s:"Your exact sub-area", grad:"linear-gradient(135deg,rgba(0,184,159,0.45),rgba(0,150,126,0.2))"}, {col:"#FF6B7A",ic:"🔒",t:"Safe Space", s:"Moderated & trusted", grad:"linear-gradient(135deg,rgba(255,107,122,0.4),rgba(232,55,74,0.15))"}, {col:"#A78BFA",ic:"🗺️",t:"Area Map", s:"EC & surroundings", grad:"linear-gradient(135deg,rgba(167,139,250,0.4),rgba(107,127,240,0.15))"}, ].map(({col,ic,t,s,grad},idx)=>(
{ic}
{t}
{s}
))}
{/* ── Stats bar — glassmorphism card ── */}
{[["2,400+","Verified Residents","#D4BCFF"],["160+","Apartments","#6EE7DF"],["21","Areas Covered","#FBB17B"]].map(([n,l,col])=>(
{n}
{l}
))} {/* Dividers */}
{/* ── Trust chips ── */}
{["🏛️ Govt-verified","📵 Zero spam","🔐 Privacy first","🆓 Always free"].map(chip=>( {chip} ))}
{/* ── CTA buttons ── */}

🔒 Government ID required · Your data stays safe

); } // ─── SCREEN: Signup with SmartInput ───────────────────────────────────────── const STEPS=["About You","Your Home","Identity","Selfie"]; const BIZ_STEPS=["Account Type","Business Info","Documents","Verification"]; const BIZ_TYPES=["Restaurant / Food","Grocery / Supermart","Services / Repairs","Medical / Pharmacy","Education / Coaching","Beauty / Wellness","Retail / Shop","Other"]; const ID_TYPES=["Aadhaar Card","Voter ID","Passport","Driving Licence"]; function SignupScreen({nav}){ const [acctType,setAcctType]=useState(""); // "personal" | "business" const [step,setStep]=useState(0); // 0=choose type; personal:1-4; business:1-4 const [form,setForm]=useState({name:"",email:"",phone:"",area:"",apartment:"",street:"",flat:""}); const [idType,setIdType]=useState("Aadhaar Card"); const [uploaded,setUploaded]=useState({}); const [bizForm,setBizForm]=useState({bizName:"",bizType:"",ownerName:"",phone:"",area:""}); const [hasLicense,setHasLicense]=useState(null); // null | true | false const [errs,setErrs]=useState({}); const set=(k,v)=>setForm(f=>({...f,[k]:v})); const setBiz=(k,v)=>setBizForm(f=>({...f,[k]:v})); const setErr=(k,msg)=>setErrs(e=>msg?{...e,[k]:msg}:(({[k]:_,...rest})=>rest)(e)); const blur=(k,val,fn)=>setErr(k,fn(val)); /* Returns null if step is valid, or an errors object if not */ const validateStep=()=>{ const e={}; if(!isBiz&&step===1){ const n=vName(form.name); if(n) e.name=n; const em=vEmail(form.email); if(em) e.email=em; const p=vPhone(form.phone); if(p) e.phone=p; } if(!isBiz&&step===2){ const a=vArea(form.area); if(a) e.area=a; const ap=vApt(form.apartment); if(ap) e.apartment=ap; const fl=vFlat(form.flat); if(fl) e.flat=fl; } if(!isBiz&&step===3){ if(!uploaded.id) e.id="Government ID is required"; if(!uploaded.address) e.address="Address proof is required"; } if(isBiz&&step===1){ const bn=vBizName(bizForm.bizName); if(bn) e.bizName=bn; const on=vName(bizForm.ownerName); if(on) e.ownerName=on; const bp=vPhone(bizForm.phone); if(bp) e.phone=bp; if(!bizForm.bizType) e.bizType="Please select a business category"; } if(isBiz&&step===2){ const ba=vArea(bizForm.area); if(ba) e.bizArea=ba; if(!uploaded.bizFront) e.bizFront="Live photo of business front is required"; } if(isBiz&&step===3){ if(hasLicense===null) e.hasLicense="Please indicate if you have a license"; else if(hasLicense&&!uploaded.bizLicense) e.bizLicense="Please upload your business license"; else if(!hasLicense&&!uploaded.bizDoc) e.bizDoc="Please upload a business document"; if(!uploaded.ownerId) e.ownerId="Owner ID is required"; } return Object.keys(e).length?e:null; }; const handleContinue=()=>{ const e=validateStep(); if(e){setErrs(prev=>({...prev,...e}));return;} setStep(s=>s+1); }; const selectedArea=form.area.replace(/\s*\(PIN:.*\)/,"").trim(); const aptOptions=selectedArea&&APT_BY_AREA[selectedArea] ? APT_BY_AREA[selectedArea] : ALL_APTS; const isBiz=acctType==="business"; const steps=isBiz?BIZ_STEPS:STEPS; const maxStep=steps.length; // ── Step 0: Choose account type ── if(step===0) return(
{/* Subtle background orbs */}
🏘️
Join MyTown 360
Choose your account type to get started
{/* Personal */} {/* Business */}
); return(
{/* Header */}
{isBiz?"🏪":"🧑"}
{isBiz?"Business Account":"Personal Account"}
{steps[step-1]}
{/* Step dots */}
{steps.map((_,i)=>(
))}
{/* ══════════════ PERSONAL FLOW ══════════════ */} {!isBiz&&step===1&&(

👋 Fill your details exactly as they appear on your government ID.

{[["Full Name","name","Priya Venkataraman","🪪",vName,stripName],["Email Address","email","name@gmail.com","📧",vEmail,stripEmail],["Mobile Number","phone","98450 XXXXX","📱",vPhone,stripPhone]].map(([l,k,p,ic,vfn,sfn])=>(
{ic} {const v=sfn(e.target.value);set(k,v);if(errs[k])setErr(k,vfn(v));}} onBlur={()=>blur(k,form[k],vfn)}/>
{errs[k]&&

⚠ {errs[k]}

}
))}
)} {!isBiz&&step===2&&(

📍 Start typing to see suggestions — or enter your own if not listed.

{set("area",v);set("apartment","");fromDropdown?setErr("area",null):setErr("area",vArea(v));}} icon="📍" filterFn={stripAddr} error={errs.area}/> {errs.area&&

⚠ {errs.area}

}
{set("apartment",v);fromDropdown?setErr("apartment",null):setErr("apartment",vApt(v));}} icon="🏢" filterFn={stripAddr} error={errs.apartment}/> {selectedArea&&APT_BY_AREA[selectedArea]&&(

✦ {APT_BY_AREA[selectedArea].length} apartments listed in {selectedArea}

)} {errs.apartment&&

⚠ {errs.apartment}

}
set("street",v)}/>
🚪 {const v=stripAddr(e.target.value);set("flat",v);if(errs.flat)setErr("flat",vFlat(v));}} onBlur={()=>blur("flat",form.flat,vFlat)}/>
{errs.flat&&

⚠ {errs.flat}

}
{form.area&&form.apartment&&(

📋 YOUR ADDRESS SUMMARY

{[form.flat,form.apartment,form.street,form.area].filter(Boolean).join(", ")}

)}
)} {!isBiz&&step===3&&(

🔒 Documents are encrypted end-to-end. Used only to verify residency. Never shared publicly.

{ID_TYPES.map(t=>( ))}

⚠️ Both documents are mandatory to proceed.

{[["id",`Upload ${idType}`,"📄"],["address","Upload Address Proof","🏠"]].map(([k,l,ic])=>(
{errs[k]&&

⚠ {errs[k]}

}
))}
)} {!isBiz&&step===4&&(

A live selfie matches your face to your ID. Only verified residents join.

{uploaded.selfie&&(

⏳ Under review! SMS confirmation within 24 hours.

)}
)} {/* ══════════════ BUSINESS FLOW ══════════════ */} {isBiz&&step===1&&(

🏪 Set up your business profile. Verified businesses get a badge and can promote posts to local residents.

{[["Business Name","bizName","e.g. CloudKitchen Express","🏪",vBizName,stripAddr],["Owner / Contact Name","ownerName","Your full name","🧑",vName,stripName],["Mobile Number","phone","98450 XXXXX","📱",vPhone,stripPhone]].map(([l,k,p,ic,vfn,sfn])=>(
{ic} {const v=sfn(e.target.value);setBiz(k,v);if(errs[k])setErr(k,vfn(v));}} onBlur={()=>blur(k,bizForm[k],vfn)}/>
{errs[k]&&

⚠ {errs[k]}

}
))}
{BIZ_TYPES.map(t=>( ))}
{errs.bizType&&

⚠ {errs.bizType}

}
)} {isBiz&&step===2&&(
{setBiz("area",v);fromDropdown?setErr("bizArea",null):setErr("bizArea",vArea(v));}} icon="📍" filterFn={stripAddr} error={errs.bizArea}/> {errs.bizArea&&

⚠ {errs.bizArea}

}
🏢 setBiz("address",stripAddr(e.target.value))}/>
{/* Live front photo — mandatory */}

📸 Live photo of business front is mandatory

{errs.bizFront&&

⚠ {errs.bizFront}

}
)} {isBiz&&step===3&&(

🔒 All documents are encrypted. Used only for verification — never shown publicly.

⚠️ All documents are mandatory before proceeding.

{/* License or alternative */}
{[["yes","✅ Yes, I have one"],["no","❌ No license"]].map(([v,l])=>( ))}
{errs.hasLicense&&

⚠ {errs.hasLicense}

}
{hasLicense===true&&(
{errs.bizLicense&&

⚠ {errs.bizLicense}

}
)} {hasLicense===false&&(

No license? Upload any one of these business-related documents to confirm your business:

GST Registration · UDYAM Certificate · Shop & Establishment Registration · Trade License · FSSAI (for food businesses) · Bank account in business name

{errs.bizDoc&&

⚠ {errs.bizDoc}

}
)} {/* Owner ID — mandatory */}
{errs.ownerId&&

⚠ {errs.ownerId}

}
)} {isBiz&&step===4&&(

🤳 A live selfie of the business owner holding their ID confirms identity.

{uploaded.ownerSelfie&&(

🎉 Almost there! Documents submitted for review.

Verification within 24–48 hours. Once approved, you can post and promote.

💡 After verification, you can promote your business posts to all verified residents of EC Phase 2 and nearby areas!

)}
)}
{stepContinue → : }
); } // ─── SCREENS: Feed, Events, Map, Messages, Profile ──────────────────────────── // (Same as v2 – keeping them compact here) const POSTS=[ // ── MISSING PERSON alert (pinned top – highest urgency) ── {id:8,author:"Anand Kumar",apartment:"GM Infinite Smondo",area:"EC Ph 2",av:"AK",avC:"#B91C1C",time:"45m", category:"Missing Person",sharedFrom:null, missingType:"child",missingName:"Aarav Kumar",missingAge:"7 years", missingDesc:"Wearing blue school uniform, white shoes. Last seen near Park Gate C, GM Infinite Smondo.", missingLastSeen:"Today 3:30 PM – Park area, EC Phase 2", missingContact:"Anand Kumar – 98XX-XXXXX", content:"🆘 MISSING CHILD: Aarav Kumar, 7 yrs. Wearing blue school uniform, white shoes. Last seen near Park Gate C, GM Smondo at 3:30 PM today. Please call police 100 or contact Anand Kumar immediately.", likes:0,comments:14}, {id:1,author:"Priya Venkat",apartment:"Prestige Sunrise Park",area:"EC Ph 1",av:"PV",avC:"#7B4BB8",time:"2h",category:"Safety",content:"🛡️ Alert: Suspicious persons near Gate 2 last night ~10 PM. Security notified. Please lock up and call 100 if you see anything unusual.",likes:47,comments:12,sharedFrom:null}, {id:2,author:"Ramesh Babu",apartment:"Shriram Signia",area:"EC Ph 1",av:"RB",avC:"#FFB347",time:"4h",category:"Lost & Found",content:"🐕 Found a golden retriever near Infosys Signal – blue collar, no name tag. DM if yours. Safe with me.",likes:89,comments:31,sharedFrom:null}, {id:3,author:"Deepa Krishnan",apartment:"Mahaveer Ranches",area:"EC Ph 2",av:"DK",avC:"#00B89F",time:"6h",category:"Recommendation",content:"⭐ Sri Lakshmi Vegetables near Hebbagodi bus stop – freshest produce! Ask for Kumar. Open 6 AM–9 PM.",likes:134,comments:44,sharedFrom:null}, // Cross-shared posts from nearby communities (admin can remove these) {id:6,author:"Kavya Sharma",apartment:"Adarsh Welkin Park",area:"Hebbagodi",av:"KS",avC:"#FF6B7A",time:"3h",category:"Safety",content:"🚨 Warning: Chain snatching incident near Hebbagodi bus terminal around 7 PM today. Avoid that stretch after dark. Shared for awareness.",likes:31,comments:8,sharedFrom:"Hebbagodi"}, {id:7,author:"Suresh P.",apartment:"Ozone Urbana",area:"Bommasandra",av:"SP",avC:"#FFB347",time:"5h",category:"Lost & Found",content:"🔍 Lost: Brown leather wallet near Bommasandra industrial area yesterday afternoon. Contains Aadhar & ATM card. Please contact if found – reward.",likes:14,comments:5,sharedFrom:"Bommasandra"}, {id:4,author:"Arjun Nair",apartment:"Godrej E-City",area:"EC Ph 1",av:"AN",avC:"#FF6B7A",time:"8h",category:"Services",content:"🔧 Reliable plumber – Suresh (9845-XXXXX). Fixed pipeline in under 2 hrs for ₹500. Adding to community directory!",likes:62,comments:18,sharedFrom:null}, {id:5,author:"Meena S.",apartment:"Celebrity Paradise",area:"Neeladri Nagar",av:"MS",avC:"#6B7FF0",time:"1d",category:"General",content:"💡 BESCOM power cut tomorrow 9 AM–2 PM across Neeladri Nagar. Charge your devices tonight!",likes:201,comments:67,sharedFrom:null}, ]; // ─── Business & Promotion Data ──────────────────────────────────────────────── const PROMO_TIERS=[ {tier:500,label:"Premium Sidebar",desc:"Featured in sidebar of every feed view. Maximum visibility.",badge:"⭐ FEATURED",color:"#F59E0B",colorL:"#FFFBEB",icon:"🏆",perks:["Sidebar placement","Top of feed","Bold border","All-day display"]}, {tier:250,label:"Priority Feed",desc:"Pinned at the top of the regular feed, above ₹100 promotions.",badge:"🔼 PRIORITY",color:"#8B5CF6",colorL:"#F5F3FF",icon:"🥈",perks:["Top of main feed","Priority over ₹100","Bold highlight","All-day display"]}, {tier:100,label:"Boosted Post",desc:"Boosted above regular posts in the feed. Cost-effective reach.",badge:"📢 BOOSTED",color:C.mint,colorL:C.mintL,icon:"🥉",perks:["Above regular posts","Boosted label","All-day display"]}, ]; const BIZ_POSTS=[ {id:101,bizName:"CloudKitchen Express",bizType:"Restaurant / Food",owner:"Ravi Kumar",av:"CK",avC:"#EF4444",area:"EC Phase 2", content:"🍱 Freshly cooked North & South Indian meals — tiffin subscriptions starting ₹99/day! Free delivery within EC Phase 2. Order by 9 AM for lunch.", promoTier:500,promoTime:1,contact:"Order via WhatsApp: 98XX-XXXXX",verified:true}, {id:102,bizName:"QuickFix Electricals",bizType:"Services / Repairs",owner:"Suresh T.",av:"QF",avC:"#3B82F6",area:"EC Phase 1 & 2", content:"⚡ Licensed electrician — wiring, MCB, inverter installation, fan & AC repairs. Same-day service. All EC areas. 10% off for MyTown360 members!", promoTier:250,promoTime:2,contact:"Call: 97XX-XXXXX",verified:true}, {id:103,bizName:"FreshMart Organics",bizType:"Grocery / Supermart",owner:"Priya S.",av:"FM",avC:"#10B981",area:"Neeladri Nagar", content:"🥦 100% organic vegetables & fruits — sourced directly from farms. Daily delivery 7 AM–9 AM. First order 20% off with code MYTOWN20.", promoTier:100,promoTime:3,contact:"Order: 96XX-XXXXX",verified:true}, {id:104,bizName:"Glow Beauty Studio",bizType:"Beauty / Wellness",owner:"Anita R.",av:"GB",avC:"#EC4899",area:"EC Phase 1", content:"💅 Hair, skin & bridal packages at unbeatable prices. Women's only. Book appointments in advance. Mention MyTown360 for 15% off!", promoTier:100,promoTime:4,contact:"Book: 95XX-XXXXX",verified:true}, ]; const EVENTS=[ {id:1,title:"Community Yoga Camp",date:"Mar 8",time:"6:30 AM",location:"Prestige Sunrise Park Clubhouse",category:"Wellness",attendees:43,icon:"🧘",col:"#00B89F"}, {id:2,title:"Holi Celebrations 2026",date:"Mar 14",time:"10:00 AM",location:"GM Infinite Smondo Park",category:"Festival",attendees:312,icon:"🎨",col:"#FF6B7A"}, {id:3,title:"Women's Safety Drive",date:"Mar 18",time:"5:00 PM",location:"EC Community Hall Ph 1",category:"Safety",attendees:78,icon:"🛡️",col:"#5C2D91"}, {id:4,title:"Kids Coding Workshop",date:"Mar 22",time:"10:00 AM",location:"Kolte Patil iTowers",category:"Education",attendees:25,icon:"💻",col:"#6B7FF0"}, ]; const LISTINGS=[ {id:1,type:"For Sale",title:"Philips Air Fryer 2L",price:"₹2,800",seller:"Kavitha R.",area:"EC Ph 2",icon:"🍳",age:"2h",col:"#FFB347"}, {id:2,type:"Free",title:"Baby clothes 0–6 months",price:"FREE",seller:"Sunitha P.",area:"Hebbagodi",icon:"👶",age:"5h",col:"#00B89F"}, {id:3,type:"For Rent",title:"2BHK Shriram Signia (Furn)",price:"₹28k/mo",seller:"Venkat K.",area:"EC Ph 1",icon:"🏠",age:"1d",col:"#5C2D91"}, {id:4,type:"Service",title:"Home Deep Clean 3BHK",price:"₹1,200",seller:"CleanPro EC",area:"All areas",icon:"🧹",age:"2d",col:"#6B7FF0"}, ]; const MSGS=[ {id:1,name:"Ramesh Babu",av:"RB",avC:"#FFB347",preview:"Is the dog still with you?",time:"10:23 AM",unread:2}, {id:2,name:"MyTown 360 Admin",av:"MT",avC:C.purple,preview:"Your address verification is complete!",time:"9:45 AM",unread:1}, {id:3,name:"Kavitha R.",av:"KR",avC:"#6B7FF0",preview:"Still interested in the Air Fryer?",time:"Yesterday",unread:0}, ]; const AREAS_LIST=[ {name:"Electronic City Phase 1",pin:"560100"},{name:"Electronic City Phase 2",pin:"560100"}, {name:"Neeladri Nagar",pin:"560100"},{name:"Doddathogur",pin:"560100"}, {name:"Hebbagodi",pin:"560099"},{name:"Bommasandra",pin:"560099"}, {name:"Veerasandra",pin:"560100"},{name:"Huskur Road Area",pin:"560100"}, {name:"Chandapura",pin:"562106"},{name:"Kudlu",pin:"560068"}, ]; // ─── Nearby Localities (within ~10 km of EC) ───────────────────────────────────── const NEARBY_LOCALITIES = [ { name:"Begur", dist:"~3 km", dir:"N", note:"Historic fort & lake. Weekend outing spot.", color:"#7C3AED" }, { name:"Haralur", dist:"~4 km", dir:"NE", note:"Popular residential area for EC professionals.", color:"#0891B2" }, { name:"Doddakannelli", dist:"~4 km", dir:"NE", note:"Growing layout near Sarjapura Road.", color:"#059669" }, { name:"Kasavanahalli", dist:"~5 km", dir:"NE", note:"Residential & commercial corridor near ORR.", color:"#D97706" }, { name:"Dommasandra", dist:"~5 km", dir:"E", note:"Adjacent to EC boundary. Village-to-urban layout.",color:"#DC2626" }, { name:"Panathur", dist:"~5 km", dir:"NE", note:"Near ORR–Sarjapura junction. Good connectivity.", color:"#2563EB" }, { name:"Gunjur", dist:"~6 km", dir:"NE", note:"Expanding residential zone on Sarjapura Road.", color:"#059669" }, { name:"Bellandur", dist:"~6 km", dir:"N", note:"Tech corridor on ORR. Many IT offices & malls.", color:"#7C3AED" }, { name:"HSR Layout", dist:"~7 km", dir:"NW", note:"Popular residential hub. Good schools & eateries.",color:"#EA580C" }, { name:"Sarjapura", dist:"~8 km", dir:"E", note:"Major nearby township. Schools, hospitals, malls.",color:"#0891B2" }, { name:"Varthur", dist:"~10 km", dir:"NE", note:"Near Whitefield corridor. Growing residential.", color:"#6B7280" }, { name:"Chandapura", dist:"~5 km", dir:"SE", note:"KSRTC connectivity, Bommasandra adjacent.", color:"#B45309" }, ]; const DIRECTORY=[["🍽️","Restaurants & Cafés","8"],["🛒","Grocery & Supermarkets","10"],["🔧","Service Providers","41"],["🏥","Hospitals & Clinics","7"],["🚌","Transport & Autos","9"],["🏫","Schools & Daycare","13"],["🌳","Parks & Recreation","9"],["⛽","Petrol Pumps","5"],["🏨","Hotels & Stay","5"],["🛕","Temples & Worship","9"],["🎬","Cinemas","3"],["🏧","ATMs","8"]]; // ─── Police Alert Gate (shown before Missing Person form) ──────────────────── function PoliceAlertModal({onOk}){ return(
{/* Red header */}
🚨
MISSING PERSON?
Please contact the police immediately
{/* Emergency numbers */}
{[ {icon:"🚔",label:"Police",num:"100",col:"#1D4ED8",colL:"#EFF6FF"}, {icon:"👶",label:"Childline (Missing Children)",num:"1098",col:"#7C3AED",colL:"#F5F3FF"}, {icon:"🆘",label:"Emergency Services",num:"112",col:C.crimson,colL:C.crimsonL}, ].map(({icon,label,num,col,colL})=>(
{icon}
{label}
{num}
CALL NOW
))}
⚠️ Posting on MyTown 360 does not replace an official police report. Always file a First Information Report (FIR) first.
); } // ─── Image Upload (for posts/listings) ─────────────────────────────────────── function ImageUpload({images, onChange, maxImages=4, label="Add Photos"}){ const handleClick=()=>{ // Simulate selecting up to 2 demo images if(images.lengthonChange(images.filter(x=>x.id!==id)); return(
📷 {label} (up to {maxImages})
{images.map(img=>(
🖼️
))} {images.length 📷 Add )}
{images.length>0&&
{images.length} photo{images.length>1?"s":""} added
}
); } // ─── Dispatch Modal (shown after posting an alert category) ────────────────── function DispatchModal({category, memberCount, onDone}){ const isMissing=category==="Missing Person"; const isLF=category==="Lost & Found"; const col=isMissing?C.crimson:isLF?C.marigold:C.coral; const colL=isMissing?C.crimsonL:isLF?C.marigoldL:C.coralL; const channels=[ {icon:"📱",label:"App Push Notification",detail:`${memberCount} verified members in EC Phase 2`,done:true}, {icon:"📧",label:"Email Alert",detail:`${memberCount} registered email addresses`,done:true}, {icon:"💬",label:"SMS Alert",detail:`${memberCount} registered mobile numbers`,done:true}, ...(isMissing?[{icon:"🔊",label:"Urgent Tone Alert",detail:"Special alarm tone played on all active devices in area",done:true,urgent:true}]:[]), ]; return(
{/* Header */}
{isMissing?"🚨":isLF?"🔍":"🛡️"}
{isMissing?"MISSING PERSON ALERT":"COMMUNITY ALERT"} DISPATCHED
Notification sent to your area
{/* Member count badge */}
👥
{memberCount} Members Notified
Verified residents of EC Phase 2
{/* Channel breakdown */}
{channels.map((ch,i)=>(
{ch.icon}
{ch.label}
{ch.detail}
))}
{/* Special tone note */} {isMissing&&(
ℹ️
Special alert tone is a unique high-priority sound played on all MyTown360 apps even when the phone is on silent, to ensure maximum visibility for missing person cases.
)}
); } // ─── Notification Toast ─────────────────────────────────────────────────────── function NotificationToast({alerts, onDismiss}){ if(!alerts.length) return null; return(
{alerts.map(a=>{ const isMissing=a.cat==="Missing Person"; const isLF=a.cat==="Lost & Found"; const col=isMissing?C.crimson:isLF?C.marigold:C.coral; const colL=isMissing?C.crimsonL:isLF?C.marigoldL:C.coralL; const toastIcon=isMissing?"🚨":isLF?"🔍":"⚠️"; const label=isMissing?"MISSING PERSON ALERT":isLF?"LOST & FOUND":"SAFETY ALERT"; return(
{/* Coloured header */}
{toastIcon} {label} · {a.area} {isMissing&&🔊 URGENT TONE}
{/* Content */}
{isMissing?"👶":isLF?"🐾":"⚠️"}
{a.content}
Posted by {a.author} · Just now
{/* Dispatch channel badges */}
🔔 {a.memberCount} push 📧 email sent 💬 SMS sent {isMissing&&🔊 urgent tone} {a.sharedAreas&&a.sharedAreas.length>0&&( 📡 {a.sharedAreas.length} areas )}
); })}
); } // ─── Cross-Share Modal ──────────────────────────────────────────────────────── function CrossShareModal({category, onShare, onSkip}){ const [sel,setSel]=useState([]); const toggle=(a)=>setSel(s=>s.includes(a)?s.filter(x=>x!==a):[...s,a]); return(
Share with Nearby Communities?
Your {category} post has been sent to your area. Nearby communities may benefit from this information too.
ℹ️ Community admins of selected areas can remove your post if they consider it off-topic or spam.
{NEARBY_AREAS.map(area=>{ const on=sel.includes(area); return( ); })}
); } // ─── Reaction Bar ───────────────────────────────────────────────────────────── function ReactionBar({postId, baseCounts, myReaction, onReact}){ const [open,setOpen]=useState(false); const counts={...baseCounts}; if(myReaction) counts[myReaction]=(counts[myReaction]||0)+1; const top=Object.entries(counts).filter(([,v])=>v>0).sort((a,b)=>b[1]-a[1]).slice(0,3); const total=Object.values(counts).reduce((s,v)=>s+v,0); return(
{/* Reaction summary row */} {total>0&&(
{top.map(([id])=>{const r=REACTIONS.find(x=>x.id===id);return r?{r.emoji}:null;})}
{total} reaction{total!==1?"s":""}
)} {/* Picker popup */} {open&&(
{REACTIONS.map(r=>{ const chosen=myReaction===r.id; return( ); })}
)} {/* Action bar */}
); } // ─── Post Composer (Category-First) ────────────────────────────────────────── function PostComposer({onPost}){ const [step,setStep]=useState(0); // 0=closed 1=pick-category 2=write const [cat,setCat]=useState(""); const [draft,setDraft]=useState(""); const [urgency,setUrgency]=useState("high"); const [lostType,setLostType]=useState("lost"); const [blocked,setBlocked]=useState(false); const [images,setImages]=useState([]); const [policeAlert,setPoliceAlert]=useState(false); // show police gate modal // Missing Person specific fields const [missingType,setMissingType]=useState("child"); const [missingName,setMissingName]=useState(""); const [missingAge,setMissingAge]=useState(""); const [missingLastSeen,setMissingLastSeen]=useState(""); const [missingContact,setMissingContact]=useState(""); const meta=CAT_META[cat]||{}; const isAlert=ALERT_CATEGORIES.includes(cat); const isMissing=cat==="Missing Person"; const isLF=cat==="Lost & Found"; const handleDraft=(v)=>{ setDraft(v); setBlocked(checkViolation(v)); }; const resetAll=()=>{setStep(0);setCat("");setDraft("");setBlocked(false);setImages([]);setMissingName("");setMissingAge("");setMissingLastSeen("");setMissingContact("");setPoliceAlert(false);}; const missingReady=isMissing&&missingName.trim()&&missingLastSeen.trim(); const canPost=isMissing?missingReady:(draft.trim()&&!blocked); const doPost=()=>{ if(!canPost) return; let content=draft; let extra={}; if(isMissing){ content=`🆘 MISSING ${missingType==="child"?"CHILD":"PERSON"}: ${missingName}${missingAge?`, ${missingAge}`:""}. Last seen: ${missingLastSeen}.${draft.trim()?" "+draft.trim():""}${missingContact?" Contact: "+missingContact:""}`; extra={missingType,missingName,missingAge,missingLastSeen,missingContact}; } onPost({category:cat,content,urgency:cat==="Safety"?urgency:null,lostType:cat==="Lost & Found"?lostType:null,images,...extra}); resetAll(); }; if(step===0) return(
MT
); if(step===1) return(
What are you posting about?
{/* Police Alert Gate Modal */} {policeAlert&&{setPoliceAlert(false);setStep(2);}}/>}
{/* Missing Person – full-width, visually distinct urgent button */} {/* Other categories – 2-column grid */}
{Object.entries(CAT_META).filter(([n])=>n!=="Missing Person").map(([name,m])=>( ))}
); return(
{/* Category header stripe */}
{meta.icon} {cat} {isMissing&&🔊 URGENT TONE ALERT} {isAlert&&!isMissing&&🔔 INSTANT ALERT}
{/* ── Verification gate for restricted categories ── */} {NEEDS_VERIFIED_CATS.includes(cat)&&!MOCK_USER.verified&&(
🔒
Account Verification Required
To post in {cat}, your account must be verified by our admin team. {MOCK_USER.pendingReview?" Your verification is under review.":""}
{MOCK_USER.pendingReview ?
⏳ Verification in progress — we'll notify you by SMS once approved.
:
→ Complete signup & submit your documents to get verified.
}
)} {/* ── Review-queue notice for Safety/L&F/Missing (unverified) ── */} {REVIEW_QUEUE_CATS.includes(cat)&&!isMissing&&!MOCK_USER.verified&&(
Pending verification: Your post will be reviewed by our admin/customer support team before it's visible to the community. We prioritise safety and emergency posts.
)} {/* Only show the form when allowed */} {(!NEEDS_VERIFIED_CATS.includes(cat)||MOCK_USER.verified)&&( <> {/* ── MISSING PERSON form ── */} {isMissing&&( <> {/* Child / Adult toggle */}
Who is missing?
{[["child","👶 Missing Child"],["adult","🧑 Missing Adult"]].map(([v,l])=>( ))}
{/* Name */}
Full Name *
setMissingName(e.target.value)} placeholder={missingType==="child"?"Child's full name…":"Person's full name…"} style={{width:"100%",padding:"9px 12px",borderRadius:10,border:`1.5px solid ${C.border}`,fontSize:13,outline:"none",boxSizing:"border-box",fontFamily:"inherit"}}/>
{/* Age + Physical description – side by side */}
Age
setMissingAge(e.target.value)} placeholder="e.g. 7 years" style={{width:"100%",padding:"9px 12px",borderRadius:10,border:`1.5px solid ${C.border}`,fontSize:13,outline:"none",boxSizing:"border-box",fontFamily:"inherit"}}/>
Contact Number
setMissingContact(e.target.value)} placeholder="Your mobile number" style={{width:"100%",padding:"9px 12px",borderRadius:10,border:`1.5px solid ${C.border}`,fontSize:13,outline:"none",boxSizing:"border-box",fontFamily:"inherit"}}/>
{/* Last seen */}
Last Seen Location & Time *
setMissingLastSeen(e.target.value)} placeholder="e.g. Park Gate C, GM Smondo – Today 3:30 PM" style={{width:"100%",padding:"9px 12px",borderRadius:10,border:`1.5px solid ${C.border}`,fontSize:13,outline:"none",boxSizing:"border-box",fontFamily:"inherit"}}/>
{/* Additional description */}
Physical Description / Clothing