Site Builder
Editing:
indexverygood.php
writable 0666
<?php $phDir = $_SERVER['DOCUMENT_ROOT'] . '/ph/'; $templateFile = $_SERVER['DOCUMENT_ROOT'] . '/ph/profile-index.php'; $msg = ''; if ($_SERVER['REQUEST_METHOD'] === 'POST') { // Validate basic required fields if (empty($_POST['phone']) || empty($_POST['name']) || empty($_POST['email'])) { $msg = "❌ Phone, name, and email are required."; } // Ensure latitude and longitude are provided elseif (empty($_POST['lat']) || empty($_POST['lon'])) { $msg = "❌ Please use 'Locate Me' to fill in your latitude and longitude before submitting."; } else { // Sanitize and prepare data $phone = preg_replace('/\D/', '', $_POST['phone']); $phone10 = substr($phone, -10); $dir = $phDir . $phone10; if (is_dir($dir)) { $msg = "❌ That business already exists! <a href='/ph/$phone10/'>View page</a>"; } else { // Create directory and JSON file mkdir($dir, 0777, true); $data = [ 'name' => trim($_POST['name']), 'email' => trim($_POST['email']), 'slogan' => mb_substr(trim($_POST['slogan']), 0, 160), 'description' => mb_substr(trim($_POST['description']), 0, 240), 'address' => trim($_POST['address']), 'city' => trim($_POST['city']), 'state' => trim($_POST['state']), 'zip' => trim($_POST['zip']), 'phone' => $phone10, 'website' => trim($_POST['website']), 'tags' => array_filter(array_map('trim', explode(',', $_POST['tags'] ?? ''))), 'location_tags' => array_filter(array_map('trim', explode(',', $_POST['location_tags'] ?? ''))), 'lat' => trim($_POST['lat']), 'lon' => trim($_POST['lon']), 'twitter' => trim($_POST['twitter'] ?? ''), 'facebook' => trim($_POST['facebook'] ?? ''), 'instagram' => trim($_POST['instagram'] ?? ''), 'tiktok' => trim($_POST['tiktok'] ?? ''), 'linkedin' => trim($_POST['linkedin'] ?? ''), 'youtube' => trim($_POST['youtube'] ?? '') ]; file_put_contents("$dir/new-business.json", json_encode($data, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE)); if (is_readable($templateFile)) copy($templateFile, "$dir/index.php"); $msg = "✅ Business added! <a href='/ph/$phone10/'>View your business page</a>"; } } } ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Add Your Business | BestDealOn</title> <meta name="viewport" content="width=device-width,initial-scale=1"> <meta name="robots" content="noindex,follow"> <style> body {background:#f5f8fb;font-family:system-ui,Arial,sans-serif;margin:0;color:#234;} h1 {text-align:center;color:#2257a2;} .top-bar{background:#eee;padding:.8em 1.2em;font-weight:900;} .wrap {max-width:520px;margin:2.7em auto;background:#fff;padding:2em 2em 2em 2em;border-radius:17px;box-shadow:0 2px 18px #dde3fa33;} .cta {background:#ecfbf1;border-radius:10px;padding:1em 1.1em;margin-bottom:2em;font-size:1.08em;color:#175e35;text-align:center;} input[type=text],input[type=tel],input[type=email],textarea,select { width:100%;padding:.7em;border-radius:7px;border:1.4px solid #b7c2df;margin-bottom:1.13em;font-size:1.08em;} input[type=submit],button {padding:.7em 1.4em;font-size:1.1em;font-weight:700;background:#2357d7;color:#fff;border:none;border-radius:8px;cursor:pointer;transition:background .16s;} input[type=submit]:hover:enabled, button:hover:enabled {background:#0a3798;} input[type=submit]:disabled, button:disabled {background:#8ba0c5!important;color:#dbe7fa!important;cursor:not-allowed!important;opacity:.72;} .lab {font-weight:600;margin-bottom:.2em;display:block;} .hint {font-size:.96em;color:#666;margin:-1.07em 0 1em .2em;} .msg {text-align:center;margin-bottom:1.4em;font-size:1.07em;} .location-tag {display:inline-block;background:#e6f0fa;color:#17468d;border-radius:14px;padding:.22em .85em;margin:.08em .2em .18em 0;font-size:.99em;position:relative;} .location-tag .del {cursor:pointer;color:#c63c27;font-size:1.13em;margin-left:.22em;} .location-tag .del:hover {color:#d80d19;} #addTag {margin-bottom:1.1em;} @media (max-width:600px){.wrap{padding:1em .1em 1em .1em;max-width:99vw;}} /* ========== NEW: lock & style city/state once set ========== */ .locked-input{background:#e9ecef!important;color:#666!important;} /* ========== NEW: collapsible social links ========== */ .social-toggle{cursor:pointer;display:flex;align-items:center;gap:.35em;font-weight:600;margin:1.4em 0 .4em;} .social-toggle .arrow{transition:transform .2s;} #socialSection.collapsed{display:none;} /* ========== NEW: taller description box ========== */ textarea#description{min-height:6.5em;} /* (~2 extra lines) */ </style> <script> let userLat = '', userLon = '', userState = '', userCity = '', userCitiesList = []; let tags = []; let phoneAvailable = false; /* ---------- NEW: lock city & state ---------- */ function lockCityState(){ ['city','state'].forEach(id=>{ const el=document.getElementById(id); el.readOnly=true; el.classList.add('locked-input'); }); } /* ---------- NEW: social‑section toggle ---------- */ function initSocialToggle(){ const tog=document.getElementById('socialToggle'); if(!tog) return; const sect=document.getElementById('socialSection'); const arr=tog.querySelector('.arrow'); tog.addEventListener('click',()=>{ const shut=sect.classList.toggle('collapsed'); arr.style.transform=shut?'rotate(-90deg)':'rotate(0deg)'; }); } /* Prefill phone from ?ph= on load */ window.addEventListener('DOMContentLoaded', function() { let urlPh = (new URL(window.location)).searchParams.get('ph'); if (urlPh && urlPh.match(/^\d{10}$/)) { let nums = urlPh.replace(/\D/g,'').slice(-10); let formatted = nums; if(nums.length === 10) formatted = `(${nums.substr(0,3)})-${nums.substr(3,3)}-${nums.substr(6,4)}`; document.getElementById('phone').value = formatted; document.getElementById('business-id').textContent = nums; } document.getElementById('business-form').style.display = 'none'; document.getElementById('locateBtn').addEventListener('click', function() { locateMe(); }); document.getElementById('addTag').addEventListener('keydown', function(e){ if(e.key === "Enter" || e.key === "," ) { e.preventDefault(); addTagsFromInput(); } if(e.key==='Backspace' && this.value===''){ if(tags.length){ tags.pop(); renderChips(); checkFormReady(); } } }); document.getElementById('addTag').addEventListener('blur', function(){ addTagsFromInput(); }); document.getElementById('phone').addEventListener('input', function() { let nums = this.value.replace(/\D/g,'').slice(0,10); let out = nums; if(nums.length > 6) out = `(${nums.substr(0,3)})-${nums.substr(3,3)}-${nums.substr(6,4)}`; else if(nums.length > 3) out = `(${nums.substr(0,3)})-${nums.substr(3)}`; this.value = out; document.getElementById('business-id').textContent = nums; if(nums.length === 10) { fetch('/ph/check.php?phone='+nums).then(r=>r.json()).then(data=>{ if (data.exists) { document.getElementById('phone-status').innerHTML = '<span style="color:#d92c2c;font-weight:700;">❌ Already exists</span>'; phoneAvailable = false; document.getElementById('addBtn').disabled = true; } else { document.getElementById('phone-status').innerHTML = '<span style="color:#20b934;font-weight:700;">✅ Available to claim!</span>'; phoneAvailable = true; checkFormReady(); } }); } else { document.getElementById('phone-status').innerHTML = ''; phoneAvailable = false; document.getElementById('addBtn').disabled = true; } }); document.getElementById('city').addEventListener('input', updateLatLonFromCityState); document.getElementById('state').addEventListener('input', updateLatLonFromCityState); Array.from(document.querySelectorAll('#business-form input, #business-form textarea')).forEach(i=>{ i.addEventListener('input', checkFormReady); }); /* NEW: initialise collapsible socials */ initSocialToggle(); }); /* After location is found and the form is shown, trigger the phone availability check if prefilled */ function locateMe() { if (!navigator.geolocation) { alert("Geolocation not supported."); return; } document.getElementById('geo-status').textContent = "Locating..."; navigator.geolocation.getCurrentPosition(function(pos) { userLat = pos.coords.latitude; userLon = pos.coords.longitude; document.getElementById('lat').value = userLat; document.getElementById('lon').value = userLon; fetch('/geo/json-data/states-bounds.json').then(r=>r.json()).then(bounds=>{ let st = ''; bounds.forEach(function(b){ if (userLat >= b.minLat && userLat <= b.maxLat && userLon >= b.minLon && userLon <= b.maxLon) st=b.state; }); if(st) { userState = st; document.getElementById('state').value = st; fetch('/geo/json-data/'+st+'.json').then(r=>r.json()).then(cities=>{ let nearest = null, bestDist = 1e9; userCitiesList = cities; cities.forEach(c=>{ let d = Math.hypot(userLat-c.lat, userLon-c.lon); if (d < bestDist) { bestDist = d; nearest = c; } }); if (nearest) { userCity = nearest.city; document.getElementById('city').value = nearest.city; document.getElementById('lat').value = nearest.lat; document.getElementById('lon').value = nearest.lon; document.getElementById('geo-status').innerHTML = "Location found: <b>" + nearest.city + ", " + st + "</b>."; lockCityState(); /* NEW: lock fields now */ let dists = cities.map(c=>({city:c.city, d:Math.hypot(userLat-c.lat,userLon-c.lon)})); dists.sort((a,b)=>a.d-b.d); let preTags = [nearest.city, st]; for (let i=1; i<7 && i<dists.length; ++i) preTags.push(dists[i].city); setTags(preTags); document.getElementById('business-form').style.display = ''; checkFormReady(); let phoneInput = document.getElementById('phone'); if (phoneInput.value.replace(/\D/g,'').length === 10) { phoneInput.dispatchEvent(new Event('input', { bubbles: true })); } } }); } else { document.getElementById('geo-status').textContent = "Not in USA/States."; } }); }, function(){ document.getElementById('geo-status').textContent = "Failed."; }); } function setTags(arr) { tags = [...new Set(arr)]; renderChips(); } function renderChips() { const wrap = document.getElementById('location-tags'); wrap.innerHTML = ''; tags.forEach((tag, idx) => { let chip = document.createElement('span'); chip.className = 'location-tag'; chip.dataset.val = tag; chip.textContent = tag; let btn = document.createElement('span'); btn.className = 'del'; btn.innerHTML = '×'; btn.onclick = () => { tags.splice(idx, 1); renderChips(); checkFormReady(); }; chip.appendChild(btn); wrap.appendChild(chip); }); document.getElementById('location_tags').value = tags.join(', '); checkFormReady(); } function addTagsFromInput() { const input = document.getElementById('addTag'); let newTags = input.value.split(',').map(s=>s.trim()).filter(Boolean); let changed = false; newTags.forEach(tag=>{ if(tag && !tags.includes(tag)){ tags.push(tag); changed=true; } }); if (changed) renderChips(); input.value = ''; checkFormReady(); } function updateLatLonFromCityState() { const state = document.getElementById('state').value.trim().toUpperCase(); const city = document.getElementById('city').value.trim(); if (state && city) { fetch('/geo/json-data/' + state + '.json') .then(r => r.json()) .then(cities => { const match = cities.find(c => c.city.toLowerCase() === city.toLowerCase()); if (match) { document.getElementById('lat').value = match.lat; document.getElementById('lon').value = match.lon; } }); } } function checkFormReady() { let phoneOk = phoneAvailable; let ready = ( phoneOk && document.getElementById('phone').value.replace(/\D/g,'').length === 10 && document.getElementById('email').value.trim().length > 0 && document.getElementById('email').checkValidity() && document.getElementById('name').value.trim() && document.getElementById('description').value.trim() && document.getElementById('address').value.trim() && document.getElementById('city').value.trim() && document.getElementById('state').value.trim() && document.getElementById('zip').value.trim() && tags.length >= 2 && document.getElementById('phone-status').innerHTML.indexOf('Available')!==-1 ); document.getElementById('addBtn').disabled = !ready; } </script> </head> <body> <div class="top-bar"><a href="/" style="text-decoration:none;color:#2a3ca5">BestDealOn</a> » Add Your Business</div> <div class="wrap"> <h1>Add Your Business</h1> <div class="cta"> <b>Step 1: Click "Locate Me" to begin</b><br> <button type="button" id="locateBtn">📍 Locate Me</button> <span id="geo-status" style="margin-left:.8em;color:#1067a8;"></span> </div> <?php if($msg): ?><div class="msg" style="color:<?=strpos($msg,'✅')!==false?'green':'red'?>"><?= $msg ?></div><?php endif; ?> <form id="business-form" method="post" autocomplete="off" style="display:none;"> <input type="hidden" id="lat" name="lat"> <input type="hidden" id="lon" name="lon"> <label class="lab" for="phone">Business Phone (10 digits)</label> <input type="text" id="phone" name="phone" maxlength="16" placeholder="(727)-610-1111" required autocomplete="off"> <div style="margin-bottom:.6em;"> <span>Business ID: <span id="business-id" style="font-family:monospace;font-size:1.04em;"></span></span> <span id="phone-status" style="margin-left:.8em;"></span> </div> <label class="lab" for="email">Business Email</label> <input type="email" id="email" name="email" maxlength="120" required placeholder="you@email.com" autocomplete="off"> <label class="lab" for="name">Business Name</label> <input type="text" id="name" name="name" maxlength="80" required> <label class="lab" for="slogan">Slogan <span class="hint">(max 160 characters, optional)</span></label> <input type="text" id="slogan" name="slogan" maxlength="160"> <!-- DESCRIPTION: taller but same width --> <label class="lab" for="description">Description <span class="hint">(max 240 characters)</span></label> <textarea id="description" name="description" maxlength="240" rows="5" required></textarea> <label class="lab" for="address">Street Address</label> <input type="text" id="address" name="address" maxlength="120" required> <div style="display:flex;gap:1.1em;"> <div style="flex:2"> <label class="lab" for="city">City</label> <input type="text" id="city" name="city" maxlength="40" required> </div> <div style="flex:1.1"> <label class="lab" for="state">State (2-letter)</label> <input type="text" id="state" name="state" maxlength="2" required> </div> <div style="flex:1.2"> <label class="lab" for="zip">ZIP Code</label> <input type="text" id="zip" name="zip" maxlength="12" required> </div> </div> <label class="lab" for="website">Website (optional)</label> <input type="text" id="website" name="website" maxlength="120"> <hr style="margin:1.7em 0 .9em 0;"> <!-- COLLAPSIBLE SOCIAL LINKS --> <div id="socialToggle" class="social-toggle"><span class="arrow">▸</span> Add social links</div> <div id="socialSection" class="collapsed"> <label class="lab" for="twitter">Twitter/X (URL or handle)</label> <input type="text" id="twitter" name="twitter" maxlength="120" placeholder="e.g. https://twitter.com/username or @username"> <label class="lab" for="facebook">Facebook (URL or handle)</label> <input type="text" id="facebook" name="facebook" maxlength="120" placeholder="e.g. https://facebook.com/username"> <label class="lab" for="instagram">Instagram (URL or handle)</label> <input type="text" id="instagram" name="instagram" maxlength="120" placeholder="e.g. https://instagram.com/username or @username"> <label class="lab" for="tiktok">TikTok (URL or handle)</label> <input type="text" id="tiktok" name="tiktok" maxlength="120" placeholder="e.g. https://tiktok.com/@username or @username"> <label class="lab" for="linkedin">LinkedIn (URL or handle)</label> <input type="text" id="linkedin" name="linkedin" maxlength="120" placeholder="e.g. https://linkedin.com/in/username"> <label class="lab" for="youtube">YouTube (URL or channel)</label> <input type="text" id="youtube" name="youtube" maxlength="120" placeholder="e.g. https://youtube.com/@username"> </div> <hr style="margin:1.7em 0 .9em 0;"> <label class="lab" for="tags">Business Tags (comma separated)</label> <input type="text" id="tags" name="tags" maxlength="120" placeholder="e.g. Restaurant, Pizza, Delivery"> <label class="lab" for="location-tags">Location Tags</label> <div id="location-tags" style="margin-bottom:.5em;"></div> <input type="hidden" id="location_tags" name="location_tags"> <input type="text" id="addTag" placeholder="Add more tags (comma separated)" autocomplete="off"> <input type="submit" id="addBtn" value="Add My Business 🚀" disabled> </form> </div> </body> </html>
Save changes
Create folder
writable 0777
Create
Cancel