Updated search bar to remove location. Will get or ask for user's location. Removed Start Earning button. Works on desktop and mobile
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
const express = require("express");
|
||||
const { Op } = require("sequelize");
|
||||
const { Item, User, Rental } = require("../models"); // Import from models/index.js to get models with associations
|
||||
const { Op, Sequelize } = require("sequelize");
|
||||
const { Item, User, Rental, sequelize } = require("../models"); // Import from models/index.js to get models with associations
|
||||
const { authenticateToken, requireVerifiedEmail, requireAdmin, optionalAuth } = require("../middleware/auth");
|
||||
const logger = require("../utils/logger");
|
||||
const { validateS3Keys } = require("../utils/s3KeyValidator");
|
||||
@@ -61,6 +61,9 @@ router.get("/", async (req, res, next) => {
|
||||
city,
|
||||
zipCode,
|
||||
search,
|
||||
lat,
|
||||
lng,
|
||||
radius = 25,
|
||||
page = 1,
|
||||
limit = 20,
|
||||
} = req.query;
|
||||
@@ -74,8 +77,50 @@ router.get("/", async (req, res, next) => {
|
||||
if (minPrice) where.pricePerDay[Op.gte] = minPrice;
|
||||
if (maxPrice) where.pricePerDay[Op.lte] = maxPrice;
|
||||
}
|
||||
if (city) where.city = { [Op.iLike]: `%${city}%` };
|
||||
if (zipCode) where.zipCode = { [Op.iLike]: `%${zipCode}%` };
|
||||
|
||||
// Location filtering: Radius search OR city/ZIP fallback
|
||||
if (lat && lng) {
|
||||
// Parse and validate coordinates
|
||||
const latNum = parseFloat(lat);
|
||||
const lngNum = parseFloat(lng);
|
||||
const radiusNum = parseFloat(radius);
|
||||
|
||||
if (!isNaN(latNum) && !isNaN(lngNum) && !isNaN(radiusNum)) {
|
||||
// Bounding box pre-filter (fast, uses indexes)
|
||||
// ~69 miles per degree latitude, longitude varies by latitude
|
||||
const latDelta = radiusNum / 69;
|
||||
const lngDelta = radiusNum / (69 * Math.cos(latNum * Math.PI / 180));
|
||||
|
||||
where.latitude = {
|
||||
[Op.and]: [
|
||||
{ [Op.gte]: latNum - latDelta },
|
||||
{ [Op.lte]: latNum + latDelta },
|
||||
{ [Op.ne]: null }
|
||||
]
|
||||
};
|
||||
where.longitude = {
|
||||
[Op.and]: [
|
||||
{ [Op.gte]: lngNum - lngDelta },
|
||||
{ [Op.lte]: lngNum + lngDelta },
|
||||
{ [Op.ne]: null }
|
||||
]
|
||||
};
|
||||
|
||||
// Haversine formula for exact distance (applied after bounding box)
|
||||
// 3959 = Earth's radius in miles
|
||||
where[Op.and] = sequelize.literal(`
|
||||
(3959 * acos(
|
||||
cos(radians(${latNum})) * cos(radians("Item"."latitude")) *
|
||||
cos(radians("Item"."longitude") - radians(${lngNum})) +
|
||||
sin(radians(${latNum})) * sin(radians("Item"."latitude"))
|
||||
)) <= ${radiusNum}
|
||||
`);
|
||||
}
|
||||
} else {
|
||||
// Fallback to city/ZIP string matching
|
||||
if (city) where.city = { [Op.iLike]: `%${city}%` };
|
||||
if (zipCode) where.zipCode = { [Op.iLike]: `%${zipCode}%` };
|
||||
}
|
||||
if (search) {
|
||||
where[Op.or] = [
|
||||
{ name: { [Op.iLike]: `%${search}%` } },
|
||||
@@ -113,7 +158,7 @@ router.get("/", async (req, res, next) => {
|
||||
|
||||
const reqLogger = logger.withRequestId(req.id);
|
||||
reqLogger.info("Items search completed", {
|
||||
filters: { minPrice, maxPrice, city, zipCode, search },
|
||||
filters: { minPrice, maxPrice, city, zipCode, search, lat, lng, radius },
|
||||
resultsCount: count,
|
||||
page: parseInt(page),
|
||||
limit: parseInt(limit)
|
||||
|
||||
Reference in New Issue
Block a user