← back to NationalPaperHangers
Fix /api/near-me: accept county/town/zip filters without coordinates
2e14b8b1508c9f4db6d86c5b993f76554ad4065c · 2026-05-18 16:21:02 -0700 · SteveStudio2
The handler computed countyHit/townHit/zipHit matches but the guard
rejected every request lacking lat/lng with 400 — so those three match
paths were unreachable dead logic. Now accepts a request with coordinates
OR any county/town/zip filter; distance_miles is null for filter-only
matches and they sort last. (Endpoint had zero callers since the /map
rewrite — keeping it as a working JSON API rather than shipping it broken.)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Files touched
Diff
commit 2e14b8b1508c9f4db6d86c5b993f76554ad4065c
Author: SteveStudio2 <steve@designerwallcoverings.com>
Date: Mon May 18 16:21:02 2026 -0700
Fix /api/near-me: accept county/town/zip filters without coordinates
The handler computed countyHit/townHit/zipHit matches but the guard
rejected every request lacking lat/lng with 400 — so those three match
paths were unreachable dead logic. Now accepts a request with coordinates
OR any county/town/zip filter; distance_miles is null for filter-only
matches and they sort last. (Endpoint had zero callers since the /map
rewrite — keeping it as a working JSON API rather than shipping it broken.)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---
routes/public.js | 27 ++++++++++++++++++++-------
1 file changed, 20 insertions(+), 7 deletions(-)
diff --git a/routes/public.js b/routes/public.js
index b848c7a..79abbd1 100644
--- a/routes/public.js
+++ b/routes/public.js
@@ -861,8 +861,11 @@ router.get('/api/near-me', async (req, res, next) => {
const county = String(req.query.county || '').replace(/\s+County$/i, '').trim().toLowerCase();
const town = String(req.query.town || '').trim().toLowerCase();
const zip = String(req.query.zip || '').trim();
- if (!Number.isFinite(lat) || !Number.isFinite(lng)) {
- return res.status(400).json({ error: 'lat/lng required' });
+ const hasCoords = Number.isFinite(lat) && Number.isFinite(lng);
+ // Accept either coordinates (radius search) OR a county/town/zip filter —
+ // the match logic below supports all four. Reject only when none are given.
+ if (!hasCoords && !county && !town && !zip) {
+ return res.status(400).json({ error: 'lat/lng or county/town/zip required' });
}
const rows = await db.many(
`SELECT i.id, i.slug, i.business_name, i.city, i.state,
@@ -875,8 +878,8 @@ router.get('/api/near-me', async (req, res, next) => {
);
const matches = [];
for (const r of rows) {
- const d = distanceMiles(lat, lng, r.lat, r.lng);
- const radiusHit = d <= (r.service_radius_miles || 50);
+ const d = hasCoords ? distanceMiles(lat, lng, r.lat, r.lng) : null;
+ const radiusHit = d !== null && d <= (r.service_radius_miles || 50);
const countyHit = county && (r.service_counties || []).some(c =>
c.toLowerCase().replace(/\s+county$/i, '').trim() === county);
const townHit = town && (r.service_towns || []).some(t => t.toLowerCase().trim() === town);
@@ -888,13 +891,23 @@ router.get('/api/near-me', async (req, res, next) => {
lat: r.lat, lng: r.lng,
tier: r.tier, verified: r.verified, claim_status: r.claim_status,
response_time_hours: r.response_time_hours,
- distance_miles: Math.round(d * 10) / 10
+ distance_miles: d === null ? null : Math.round(d * 10) / 10
});
}
}
- matches.sort((a, b) => a.distance_miles - b.distance_miles);
+ // Sort by distance when coordinates were supplied; nulls (filter-only
+ // matches) sort last.
+ matches.sort((a, b) => {
+ if (a.distance_miles === null) return b.distance_miles === null ? 0 : 1;
+ if (b.distance_miles === null) return -1;
+ return a.distance_miles - b.distance_miles;
+ });
res.set('cache-control', 'public, max-age=60');
- res.json({ count: matches.length, user: { lat, lng }, installers: matches });
+ res.json({
+ count: matches.length,
+ user: hasCoords ? { lat, lng } : { county: county || null, town: town || null, zip: zip || null },
+ installers: matches
+ });
} catch (err) { next(err); }
});
← 283685a Clear all 6 npm audit vulns — audit fix + bcrypt 5.x→6.0.0
·
back to NationalPaperHangers
·
Surface the structured booking brief in the installer notifi 841f9be →