`
).join('');
}
window.pdSearchState = function(state){
pdSetTab('state');
qs('pd-input').value = state;
pdSearch();
};
/* ========================================
AUTOCOMPLETE
======================================== */
let acTimer = null;
window.pdAutoComplete = async function(q){
clearTimeout(acTimer);
const ac = qs('pd-ac');
if(q.length < 3){ ac.classList.remove('show'); return; }
acTimer = setTimeout(async()=>{
try{
let items = [];
if(pdTab==='pin' && /^\d+$/.test(q)){
const r = await fetch(`https://api.postalpincode.in/pincode/${q}`);
const d = await r.json();
if(d[0]?.Status==='Success'){
items = (d[0].PostOffice||[]).slice(0,6).map(p=>({
pin: q, place: p.Name+', '+p.District
}));
}
} else {
const r = await fetch(`https://api.postalpincode.in/postoffice/${encodeURIComponent(q)}`);
const d = await r.json();
if(d[0]?.Status==='Success'){
items = (d[0].PostOffice||[]).slice(0,8).map(p=>({
pin: p.Pincode, place: p.Name+', '+p.District+', '+p.State
}));
}
}
if(!items.length){ ac.classList.remove('show'); return; }
ac.innerHTML = items.map(it=>
`
`
).join('');
}
window.pdSort = function(key, btn){
pdSortKey = key;
document.querySelectorAll('.pindir-sort-btn').forEach(b=>b.classList.remove('active'));
btn.classList.add('active');
pdRenderCards(pdResults, qs('pd-rcount').innerHTML);
};
window.pdCopyPin = function(pin, btn){
navigator.clipboard?.writeText(pin).then(()=>{
btn.textContent='✓ Copied!';
setTimeout(()=>btn.textContent='📋 Copy', 1500);
});
};
/* ========================================
QUICK PIN (popular)
======================================== */
window.pdQuickPin = function(pin){
pdSetTab('pin');
qs('pd-input').value = pin;
pdSearch();
};
/* ========================================
DETAIL MODAL
======================================== */
window.pdOpenModal = function(idx){
const o = pdResults[idx];
if(!o) return;
qs('pd-m-pin').textContent = o.Pincode;
qs('pd-m-place').textContent = o.Name+' — '+o.District+', '+o.State;
qs('pd-m-grid').innerHTML = [
['Post Office', o.Name],
['Pincode', o.Pincode],
['Branch Type', o.BranchType],
['District', o.District],
['State', o.State],
['Division', o.Division],
['Region', o.Region],
['Circle', o.Circle],
['Taluk', o.Taluk||'—'],
['Delivery Status', o.DeliveryStatus||'—'],
].map(([l,v])=>
`
`
).join('');
// All POs with same pincode
const samePin = pdResults.filter(r=>r.Pincode===o.Pincode);
qs('pd-m-po').innerHTML = samePin.map(p=>
`
`
).join('');
qs('pd-modal').classList.add('show');
// Modal map
setTimeout(()=>{
if(pdModalMap){ pdModalMap.remove(); pdModalMap=null; }
pdModalMap = L.map('pindir-modal-map').setView([20.5937, 78.9629], 5);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',{
attribution:'© OpenStreetMap', maxZoom:19
}).addTo(pdModalMap);
pdGeoForModal(o.Name+' '+o.District+' '+o.State+' India', o.Pincode);
}, 150);
};
window.pdCloseModal = function(){
qs('pd-modal').classList.remove('show');
if(pdModalMap){ pdModalMap.remove(); pdModalMap=null; }
};
async function pdGeoForModal(query, pin){
try{
const r = await fetch(`https://nominatim.openstreetmap.org/search?format=json&limit=1&q=${encodeURIComponent(query)}`,
{headers:{'Accept-Language':'en'}});
const d = await r.json();
if(d&&d[0]){
const lat=parseFloat(d[0].lat), lon=parseFloat(d[0].lon);
pdModalMap.setView([lat,lon],14);
L.marker([lat,lon]).addTo(pdModalMap)
.bindPopup(`${pin}`).openPopup();
}
}catch(e){}
}
/* ========================================
MAIN MAP
======================================== */
function pdInitMap(){
if(pdMap) return;
// Wait for Leaflet
if(typeof L === 'undefined'){ setTimeout(pdInitMap, 200); return; }
pdMap = L.map('pindir-map').setView([22.5, 80.9], 4);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',{
attribution:'© OpenStreetMap', maxZoom:19
}).addTo(pdMap);
// Click to find nearby
pdMap.on('click', async function(e){
const lat=e.latlng.lat, lon=e.latlng.lng;
await pdFindNearby(lat, lon);
});
setTimeout(()=>pdMap.invalidateSize(), 300);
}
async function pdGeoAndMap(query, label){
try{
const r = await fetch(`https://nominatim.openstreetmap.org/search?format=json&limit=1&q=${encodeURIComponent(query)}`,
{headers:{'Accept-Language':'en'}});
const d = await r.json();
if(d&&d[0]){
const lat=parseFloat(d[0].lat), lon=parseFloat(d[0].lon);
pdMap.setView([lat,lon], 12);
pdMarkers.forEach(m=>pdMap.removeLayer(m));
pdMarkers=[];
const mk = L.marker([lat,lon]).addTo(pdMap)
.bindPopup(`${label}
${query}`).openPopup(); pdMarkers.push(mk); } }catch(e){} } window.pdMapFocus = async function(query, pin){ pdGeoAndMap(query, pin); qs('pindir-map').scrollIntoView({behavior:'smooth',block:'center'}); }; /* ======================================== NEARBY PINCODES ======================================== */ async function pdFindNearby(lat, lon){ qs('pd-nearby-title').style.display='flex'; qs('pd-nearby').innerHTML='
'); qs('pd-chat-msgs').appendChild(el); qs('pd-chat-msgs').scrollTop = 999999; } window.pdToggleChat = function(){ pdChatOpen = !pdChatOpen; const box = qs('pd-chat'); box.classList.toggle('show', pdChatOpen); if(pdChatOpen && !qs('pd-chat-msgs').children.length){ pdAddMsg("Namaste! 🙏 I'm PinBot. Ask me anything about India pincodes — type a city, state, or 6-digit pincode!", 'bot'); } if(pdChatOpen) setTimeout(()=>qs('pd-chat-in').focus(), 100); }; window.pdChatSend = function(){ const input = qs('pd-chat-in'); const msg = input.value.trim(); if(!msg) return; pdAddMsg(msg, 'user'); input.value = ''; // Typing indicator const typing = document.createElement('div'); typing.className = 'pindir-msg typing'; typing.innerHTML = '
${it.pin}
${it.place}
`
).join('');
ac.classList.add('show');
} catch(e){ ac.classList.remove('show'); }
}, 350);
};
window.pdPickAc = function(pin, place){
qs('pd-input').value = pin;
qs('pd-ac').classList.remove('show');
pdSearch();
};
document.addEventListener('click', e=>{
if(!e.target.closest('#pd-search-bar') && !e.target.closest('#pd-ac')){
qs('pd-ac').classList.remove('show');
}
});
/* ========================================
SEARCH
======================================== */
window.pdSearch = async function(){
const q = qs('pd-input').value.trim();
if(!q){ showErr('Please enter a pincode, city, or state name.'); return; }
hideAll();
showSpin(true);
qs('pd-btn').disabled = true;
qs('pd-ac').classList.remove('show');
try {
if(pdTab==='pin'){
if(!/^\d{6}$/.test(q)){ showErr('Please enter a valid 6-digit pincode.'); return; }
await pdFetchPin(q);
} else if(pdTab==='city'){
await pdFetchCity(q);
} else {
await pdFetchState(q);
}
} catch(e){
showErr('Something went wrong. Please try again.');
console.error(e);
} finally {
showSpin(false);
qs('pd-btn').disabled = false;
}
};
async function pdFetchPin(pin){
const r = await fetch(`https://api.postalpincode.in/pincode/${pin}`);
const d = await r.json();
if(!d||!d[0]||d[0].Status!=='Success'||!d[0].PostOffice?.length){
showErr('Pincode not found. Please check the number and try again.');
return;
}
const offices = d[0].PostOffice;
pdResults = offices;
pdSaveRecent(pin, offices[0].Name+', '+offices[0].District);
pdRenderCards(offices, `Found ${offices.length} post office${offices.length>1?'s':''} for PIN ${pin}`);
pdGeoAndMap(offices[0].Name+' '+offices[0].District+' '+offices[0].State+' India', pin);
}
async function pdFetchCity(city){
const r = await fetch(`https://api.postalpincode.in/postoffice/${encodeURIComponent(city)}`);
const d = await r.json();
if(!d||!d[0]||d[0].Status!=='Success'||!d[0].PostOffice?.length){
showErr('No results for "'+city+'". Try a different spelling or search by pincode.');
return;
}
const offices = d[0].PostOffice;
pdResults = offices;
pdRenderCards(offices, `Found ${offices.length} results for "${city}"`);
pdGeoAndMap(city+' India', city);
}
async function pdFetchState(state){
// Postalpincode.in doesn't have state search — we use postoffice search with state name
// and filter by State field
const r = await fetch(`https://api.postalpincode.in/postoffice/${encodeURIComponent(state)}`);
const d = await r.json();
if(!d||!d[0]||d[0].Status!=='Success'||!d[0].PostOffice?.length){
showErr('No results for state "'+state+'". Please check the spelling.');
return;
}
const offices = d[0].PostOffice.filter(o=>
o.State.toLowerCase().includes(state.toLowerCase())
);
const final = offices.length ? offices : d[0].PostOffice;
pdResults = final;
pdRenderCards(final, `Showing ${final.length} results in ${state}`);
pdGeoAndMap(state+' India', state);
}
/* ========================================
RENDER CARDS
======================================== */
function pdRenderCards(offices, countHtml){
hideAll();
show('pd-results');
qs('pd-rcount').innerHTML = countHtml;
// Sort
const sorted = [...offices].sort((a,b)=>{
if(pdSortKey==='pin') return (a.Pincode+'').localeCompare(b.Pincode+'');
return a.Name.localeCompare(b.Name);
});
qs('pd-cards').innerHTML = sorted.map((o,i)=>
`
${o.Pincode}
${o.BranchType||'Post Office'}
${o.Name}
📍 ${o.District}, ${o.State}
${l}
${v||'—'}
${p.Name}
${p.BranchType||'Post Office'} · ${p.DeliveryStatus||''}
${query}`).openPopup(); pdMarkers.push(mk); } }catch(e){} } window.pdMapFocus = async function(query, pin){ pdGeoAndMap(query, pin); qs('pindir-map').scrollIntoView({behavior:'smooth',block:'center'}); }; /* ======================================== NEARBY PINCODES ======================================== */ async function pdFindNearby(lat, lon){ qs('pd-nearby-title').style.display='flex'; qs('pd-nearby').innerHTML='
Finding nearby pincodes…
'; try{ const r = await fetch( `https://nominatim.openstreetmap.org/reverse?format=json&lat=${lat}&lon=${lon}`, {headers:{'Accept-Language':'en'}}); const d = await r.json(); const city = d.address?.city||d.address?.town||d.address?.county||''; const state= d.address?.state||''; if(!city&&!state){ qs('pd-nearby').innerHTML='No data for this area.
'; return; } const q = city||state; const pr = await fetch(`https://api.postalpincode.in/postoffice/${encodeURIComponent(q)}`); const pd = await pr.json(); if(!pd||!pd[0]||pd[0].Status!=='Success'){ qs('pd-nearby').innerHTML='No pincodes found nearby.
'; return; } const offices = pd[0].PostOffice.slice(0,8); qs('pd-nearby').innerHTML = offices.map(o=> `
${o.Pincode}
${o.Name}
${o.District}
`
).join('');
// Drop a marker
L.marker([lat,lon],{
icon: L.divIcon({className:'',html:''})
}).addTo(pdMap);
}catch(e){
qs('pd-nearby').innerHTML='Could not fetch nearby data.
'; } } /* ======================================== RECENT SEARCHES (localStorage) ======================================== */ function pdSaveRecent(pin, place){ try{ let r = JSON.parse(localStorage.getItem('pindir_recent')||'[]'); r = r.filter(x=>x.pin!==pin); r.unshift({pin,place}); r = r.slice(0,5); localStorage.setItem('pindir_recent', JSON.stringify(r)); pdRenderRecent(); }catch(e){} } function pdRenderRecent(){ try{ const r = JSON.parse(localStorage.getItem('pindir_recent')||'[]'); const el = qs('pd-recent'); if(!r.length){ el.innerHTML='No recent searches yet.
'; return; } el.innerHTML = r.map((x,i)=> `
${x.pin}
${x.place}
✕
`
).join('');
}catch(e){}
}
window.pdDelRecent = function(i){
try{
let r = JSON.parse(localStorage.getItem('pindir_recent')||'[]');
r.splice(i,1);
localStorage.setItem('pindir_recent', JSON.stringify(r));
pdRenderRecent();
}catch(e){}
};
/* ========================================
AI CHATBOT
======================================== */
const CHAT_KNOWLEDGE = {
greet: ['hi','hello','hey','hii','namaste'],
help: ['help','what can you do','kya kar sakte','how to use'],
pin: ['pincode','pin code','postal code','zip'],
state: ['state','rajya','pradesh'],
nearby:['nearby','pass mein','aas paas','close to'],
map: ['map','naksha','location'],
};
function pdChatMatch(msg, keys){ return keys.some(k=>msg.includes(k)); }
function pdChatBotReply(msg){
const m = msg.toLowerCase();
// Extract 6-digit pin
const pinMatch = m.match(/\b\d{6}\b/);
if(pinMatch){
return `Got it! Let me search pincode ${pinMatch[0]} for you... Click to search →`;
}
if(pdChatMatch(m, CHAT_KNOWLEDGE.greet)){
return "Namaste! 🙏 I'm PinBot. I can help you find pincodes, post offices, and area details across India. What are you looking for?";
}
if(pdChatMatch(m, CHAT_KNOWLEDGE.help)){
return "I can help you:\n• Find pincode by area name\n• Search by city or state\n• Find nearby pincodes\n• Get post office details\n\nJust type a pincode number or city name!";
}
if(pdChatMatch(m, CHAT_KNOWLEDGE.nearby)){
return "To find nearby pincodes, click anywhere on the 🗺️ map on the right side! I'll automatically find pincodes near that location.";
}
if(pdChatMatch(m, CHAT_KNOWLEDGE.map)){
return "The interactive map is on the right side ➡️. You can:\n• Click any pincode card's 📍 Map button to zoom to that area\n• Click directly on the map to find nearby pincodes!";
}
if(pdChatMatch(m, ['durgapur'])){
return "Durgapur is in West Bengal! Main pincodes are 713201, 713203, 713204, 713205. Search Durgapur →";
}
if(pdChatMatch(m, ['mumbai','bombay'])){
return "Mumbai's main pincode starts with 400. Central area: 400001. Search 400001 →";
}
if(pdChatMatch(m, ['delhi','new delhi'])){
return "New Delhi's main pincode is 110001 (Connaught Place). Search 110001 →";
}
if(pdChatMatch(m, ['kolkata','calcutta'])){
return "Kolkata's main pincode is 700001 (BBD Bagh area). Search 700001 →";
}
// Contains a city name — try to search it
if(m.length > 3){
return `I'll search "${msg}" for you! Search now →`;
}
return "I didn't understand that. Try typing a city name, state, or 6-digit pincode. Example: 711106 or Durgapur";
}
function pdAddMsg(text, role){
const el = document.createElement('div');
el.className = 'pindir-msg '+role;
el.innerHTML = text.replace(/\n/g,''); qs('pd-chat-msgs').appendChild(el); qs('pd-chat-msgs').scrollTop = 999999; } window.pdToggleChat = function(){ pdChatOpen = !pdChatOpen; const box = qs('pd-chat'); box.classList.toggle('show', pdChatOpen); if(pdChatOpen && !qs('pd-chat-msgs').children.length){ pdAddMsg("Namaste! 🙏 I'm PinBot. Ask me anything about India pincodes — type a city, state, or 6-digit pincode!", 'bot'); } if(pdChatOpen) setTimeout(()=>qs('pd-chat-in').focus(), 100); }; window.pdChatSend = function(){ const input = qs('pd-chat-in'); const msg = input.value.trim(); if(!msg) return; pdAddMsg(msg, 'user'); input.value = ''; // Typing indicator const typing = document.createElement('div'); typing.className = 'pindir-msg typing'; typing.innerHTML = '
';
qs('pd-chat-msgs').appendChild(typing);
qs('pd-chat-msgs').scrollTop = 999999;
setTimeout(()=>{
typing.remove();
pdAddMsg(pdChatBotReply(msg), 'bot');
}, 700 + Math.random()*400);
};
/* ========================================
INIT
======================================== */
document.addEventListener('DOMContentLoaded', function(){
pdInitMap();
pdRenderRecent();
});
// Also init if DOM already ready
if(document.readyState!=='loading'){
pdInitMap();
pdRenderRecent();
}
// Force map resize after load
window.addEventListener('load',function(){
setTimeout(()=>{ if(pdMap) pdMap.invalidateSize(); }, 500);
setTimeout(()=>{ if(pdMap) pdMap.invalidateSize(); }, 1500);
});
})();