feat: Split search into Business Name + Location fields
- Split single search input into two fields: Business Name (required) and Location (auto-detected from IP geolocation) - Auto-fill location field with city/country from IP on page load - Add click overlay on map iframe to prevent interaction - Add warning modal when user clicks map, directing them to use search - Update test URLs to use split format - Make Validate button full-width for better UX Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -41,8 +41,12 @@ interface ScraperTestProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function ScraperTest({ onJobsChange, onSelectReviews }: ScraperTestProps = {}) {
|
export default function ScraperTest({ onJobsChange, onSelectReviews }: ScraperTestProps = {}) {
|
||||||
const [searchQuery, setSearchQuery] = useState('');
|
// Split search fields
|
||||||
|
const [businessNameQuery, setBusinessNameQuery] = useState('');
|
||||||
|
const [locationQuery, setLocationQuery] = useState('');
|
||||||
|
const [detectedLocation, setDetectedLocation] = useState<{ city: string; country: string } | null>(null);
|
||||||
const [searchedQuery, setSearchedQuery] = useState('');
|
const [searchedQuery, setSearchedQuery] = useState('');
|
||||||
|
const [showMapClickModal, setShowMapClickModal] = useState(false);
|
||||||
const [jobs, setJobs] = useState<Map<string, JobStatus>>(new Map());
|
const [jobs, setJobs] = useState<Map<string, JobStatus>>(new Map());
|
||||||
const [activeJobId, setActiveJobId] = useState<string | null>(null);
|
const [activeJobId, setActiveJobId] = useState<string | null>(null);
|
||||||
const [reviews, setReviews] = useState<Review[]>([]);
|
const [reviews, setReviews] = useState<Review[]>([]);
|
||||||
@@ -105,6 +109,15 @@ export default function ScraperTest({ onJobsChange, onSelectReviews }: ScraperTe
|
|||||||
lat: data.latitude,
|
lat: data.latitude,
|
||||||
lng: data.longitude
|
lng: data.longitude
|
||||||
};
|
};
|
||||||
|
// Store detected city and country for location field
|
||||||
|
if (data.city && data.country_name) {
|
||||||
|
setDetectedLocation({
|
||||||
|
city: data.city,
|
||||||
|
country: data.country_name
|
||||||
|
});
|
||||||
|
// Auto-fill location field
|
||||||
|
setLocationQuery(`${data.city}, ${data.country_name}`);
|
||||||
|
}
|
||||||
console.log('IP location:', data.city, data.country_name);
|
console.log('IP location:', data.city, data.country_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -122,15 +135,28 @@ export default function ScraperTest({ onJobsChange, onSelectReviews }: ScraperTe
|
|||||||
const pollingIntervals = useRef<Map<string, NodeJS.Timeout>>(new Map());
|
const pollingIntervals = useRef<Map<string, NodeJS.Timeout>>(new Map());
|
||||||
const abortControllerRef = useRef<AbortController | null>(null);
|
const abortControllerRef = useRef<AbortController | null>(null);
|
||||||
|
|
||||||
|
// Build full search query from business name + location
|
||||||
|
const buildSearchQuery = () => {
|
||||||
|
const name = businessNameQuery.trim();
|
||||||
|
const location = locationQuery.trim();
|
||||||
|
if (name && location) {
|
||||||
|
return `"${name}" ${location}`;
|
||||||
|
} else if (name) {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
};
|
||||||
|
|
||||||
// Debounce: update map preview as user types (500ms after stopping)
|
// Debounce: update map preview as user types (500ms after stopping)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (searchQuery.trim().length >= 2) {
|
const query = buildSearchQuery();
|
||||||
|
if (query.length >= 2) {
|
||||||
if (debounceRef.current) {
|
if (debounceRef.current) {
|
||||||
clearTimeout(debounceRef.current);
|
clearTimeout(debounceRef.current);
|
||||||
}
|
}
|
||||||
|
|
||||||
debounceRef.current = setTimeout(() => {
|
debounceRef.current = setTimeout(() => {
|
||||||
setSearchedQuery(searchQuery.trim());
|
setSearchedQuery(query);
|
||||||
}, 500);
|
}, 500);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
@@ -139,12 +165,13 @@ export default function ScraperTest({ onJobsChange, onSelectReviews }: ScraperTe
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}, [searchQuery]);
|
}, [businessNameQuery, locationQuery]);
|
||||||
|
|
||||||
// Clear validation results when user starts typing a new search
|
// Clear validation results when user starts typing a new search
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// If searchQuery is different from searchedQuery, clear results
|
const currentQuery = buildSearchQuery();
|
||||||
if (searchQuery.trim() !== searchedQuery && searchedQuery) {
|
// If current query is different from searchedQuery, clear results
|
||||||
|
if (currentQuery !== searchedQuery && searchedQuery) {
|
||||||
// Abort any pending validation request
|
// Abort any pending validation request
|
||||||
if (abortControllerRef.current) {
|
if (abortControllerRef.current) {
|
||||||
abortControllerRef.current.abort();
|
abortControllerRef.current.abort();
|
||||||
@@ -157,7 +184,7 @@ export default function ScraperTest({ onJobsChange, onSelectReviews }: ScraperTe
|
|||||||
setBusinessImage(null);
|
setBusinessImage(null);
|
||||||
setBusinessCategory(null);
|
setBusinessCategory(null);
|
||||||
}
|
}
|
||||||
}, [searchQuery, searchedQuery]);
|
}, [businessNameQuery, locationQuery, searchedQuery]);
|
||||||
|
|
||||||
// Notify parent when jobs change
|
// Notify parent when jobs change
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -296,9 +323,8 @@ export default function ScraperTest({ onJobsChange, onSelectReviews }: ScraperTe
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleSearch = () => {
|
const handleSearch = () => {
|
||||||
if (searchQuery.trim().length < 2) return;
|
const query = buildSearchQuery();
|
||||||
|
if (query.length < 2 || !businessNameQuery.trim()) return;
|
||||||
const query = searchQuery.trim();
|
|
||||||
|
|
||||||
// Clear any pending debounce
|
// Clear any pending debounce
|
||||||
if (debounceRef.current) {
|
if (debounceRef.current) {
|
||||||
@@ -435,12 +461,12 @@ export default function ScraperTest({ onJobsChange, onSelectReviews }: ScraperTe
|
|||||||
|
|
||||||
const searchInputRef = useRef<HTMLInputElement>(null);
|
const searchInputRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
// Test URLs at different scales
|
// Test URLs at different scales (split into business name + location)
|
||||||
const testUrls = [
|
const testUrls = [
|
||||||
{ name: '🏪 Small (~79)', query: 'R. Fleitas Peluqueros Gran Canaria' },
|
{ name: '🏪 Small (~79)', businessName: 'R. Fleitas Peluqueros', location: 'Las Palmas, Spain' },
|
||||||
{ name: '🚗 Medium (~589)', query: 'ClickRent Gran Canaria' },
|
{ name: '🚗 Medium (~589)', businessName: 'ClickRent', location: 'Gran Canaria, Spain' },
|
||||||
{ name: '🏥 Large (~2000+)', query: 'Hospital Universitario Doctor Negrín Las Palmas' },
|
{ name: '🏥 Large (~2000+)', businessName: 'Hospital Universitario Doctor Negrín', location: 'Las Palmas, Spain' },
|
||||||
{ name: '🛒 Alcampo', query: 'Alcampo Hipermarket Las Palmas' },
|
{ name: '🛒 Alcampo', businessName: 'Alcampo Hipermarket', location: 'Las Palmas, Spain' },
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -455,9 +481,11 @@ export default function ScraperTest({ onJobsChange, onSelectReviews }: ScraperTe
|
|||||||
<button
|
<button
|
||||||
key={idx}
|
key={idx}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setSearchQuery(test.query);
|
setBusinessNameQuery(test.businessName);
|
||||||
setSearchedQuery(test.query);
|
setLocationQuery(test.location);
|
||||||
checkReviews(test.query);
|
const fullQuery = `"${test.businessName}" ${test.location}`;
|
||||||
|
setSearchedQuery(fullQuery);
|
||||||
|
checkReviews(fullQuery);
|
||||||
}}
|
}}
|
||||||
className="px-3 py-1.5 text-sm bg-white border-2 border-gray-300 rounded-lg hover:border-blue-500 hover:bg-blue-50 transition-all font-medium text-gray-700"
|
className="px-3 py-1.5 text-sm bg-white border-2 border-gray-300 rounded-lg hover:border-blue-500 hover:bg-blue-50 transition-all font-medium text-gray-700"
|
||||||
>
|
>
|
||||||
@@ -467,37 +495,78 @@ export default function ScraperTest({ onJobsChange, onSelectReviews }: ScraperTe
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Search Interface */}
|
{/* Search Interface - Split Fields */}
|
||||||
<>
|
<>
|
||||||
<div className="mb-4 flex gap-2">
|
<div className="mb-4 space-y-3">
|
||||||
<div className="relative flex-1">
|
{/* Business Name Field */}
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-semibold text-gray-700 mb-1">
|
||||||
|
Business Name <span className="text-red-500">*</span>
|
||||||
|
</label>
|
||||||
|
<div className="relative">
|
||||||
<div className="absolute left-4 top-1/2 -translate-y-1/2 text-gray-400">
|
<div className="absolute left-4 top-1/2 -translate-y-1/2 text-gray-400">
|
||||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
ref={searchInputRef}
|
ref={searchInputRef}
|
||||||
type="text"
|
type="text"
|
||||||
value={searchQuery}
|
value={businessNameQuery}
|
||||||
onChange={(e) => setSearchQuery(e.target.value)}
|
onChange={(e) => setBusinessNameQuery(e.target.value)}
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e) => {
|
||||||
if (e.key === 'Enter' && searchQuery.trim().length >= 2 && !isCheckingReviews) {
|
if (e.key === 'Enter' && businessNameQuery.trim() && !isCheckingReviews) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
handleSearch();
|
handleSearch();
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
placeholder="Business name and location (e.g., Soho Club Vilnius)..."
|
placeholder="e.g., Starbucks, McDonald's, Hilton Hotel..."
|
||||||
className="w-full pl-12 pr-4 py-3 text-gray-900 bg-white border-2 border-gray-200 rounded-xl focus:border-blue-500 focus:ring-4 focus:ring-blue-100 outline-none transition-all"
|
className="w-full pl-12 pr-4 py-3 text-gray-900 bg-white border-2 border-gray-200 rounded-xl focus:border-blue-500 focus:ring-4 focus:ring-blue-100 outline-none transition-all"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Location Field */}
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-semibold text-gray-700 mb-1">
|
||||||
|
Location
|
||||||
|
{detectedLocation && (
|
||||||
|
<span className="ml-2 text-xs font-normal text-green-600">
|
||||||
|
(auto-detected from your IP)
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</label>
|
||||||
|
<div className="relative">
|
||||||
|
<div className="absolute left-4 top-1/2 -translate-y-1/2 text-gray-400">
|
||||||
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={locationQuery}
|
||||||
|
onChange={(e) => setLocationQuery(e.target.value)}
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
if (e.key === 'Enter' && businessNameQuery.trim() && !isCheckingReviews) {
|
||||||
|
e.preventDefault();
|
||||||
|
handleSearch();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
placeholder={detectedLocation ? `${detectedLocation.city}, ${detectedLocation.country}` : "City, Country (e.g., New York, USA)"}
|
||||||
|
className="w-full pl-12 pr-4 py-3 text-gray-900 bg-white border-2 border-gray-200 rounded-xl focus:border-blue-500 focus:ring-4 focus:ring-blue-100 outline-none transition-all"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Validate Button */}
|
||||||
<button
|
<button
|
||||||
onClick={handleSearch}
|
onClick={handleSearch}
|
||||||
disabled={searchQuery.trim().length < 2 || isCheckingReviews}
|
disabled={!businessNameQuery.trim() || isCheckingReviews}
|
||||||
className={`px-6 py-3 font-semibold rounded-xl transition-all flex items-center gap-2 ${
|
className={`w-full px-6 py-3 font-semibold rounded-xl transition-all flex items-center justify-center gap-2 ${
|
||||||
hasReviews === true && searchQuery.trim() === searchedQuery
|
hasReviews === true && buildSearchQuery() === searchedQuery
|
||||||
? 'bg-green-600 text-white hover:bg-green-700'
|
? 'bg-green-600 text-white hover:bg-green-700'
|
||||||
: hasReviews === false && searchQuery.trim() === searchedQuery
|
: hasReviews === false && buildSearchQuery() === searchedQuery
|
||||||
? 'bg-yellow-500 text-white hover:bg-yellow-600'
|
? 'bg-yellow-500 text-white hover:bg-yellow-600'
|
||||||
: 'bg-blue-600 text-white hover:bg-blue-700'
|
: 'bg-blue-600 text-white hover:bg-blue-700'
|
||||||
} disabled:bg-gray-300 disabled:cursor-not-allowed`}
|
} disabled:bg-gray-300 disabled:cursor-not-allowed`}
|
||||||
@@ -507,26 +576,26 @@ export default function ScraperTest({ onJobsChange, onSelectReviews }: ScraperTe
|
|||||||
<div className="w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin" />
|
<div className="w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin" />
|
||||||
Validating...
|
Validating...
|
||||||
</>
|
</>
|
||||||
) : hasReviews === true && searchQuery.trim() === searchedQuery ? (
|
) : hasReviews === true && buildSearchQuery() === searchedQuery ? (
|
||||||
<>
|
<>
|
||||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
|
||||||
</svg>
|
</svg>
|
||||||
{availableReviewCount?.toLocaleString()} reviews
|
{availableReviewCount?.toLocaleString()} reviews found
|
||||||
</>
|
</>
|
||||||
) : hasReviews === false && searchQuery.trim() === searchedQuery ? (
|
) : hasReviews === false && buildSearchQuery() === searchedQuery ? (
|
||||||
<>
|
<>
|
||||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
|
||||||
</svg>
|
</svg>
|
||||||
No reviews
|
No reviews found
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
</svg>
|
</svg>
|
||||||
Validate
|
Validate Business
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
@@ -540,18 +609,24 @@ export default function ScraperTest({ onJobsChange, onSelectReviews }: ScraperTe
|
|||||||
src={embedUrl}
|
src={embedUrl}
|
||||||
width="100%"
|
width="100%"
|
||||||
height="300"
|
height="300"
|
||||||
style={{ border: 0 }}
|
style={{ border: 0, pointerEvents: 'none' }}
|
||||||
allowFullScreen
|
allowFullScreen
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
referrerPolicy="no-referrer-when-downgrade"
|
referrerPolicy="no-referrer-when-downgrade"
|
||||||
title="Google Maps Preview"
|
title="Google Maps Preview"
|
||||||
/>
|
/>
|
||||||
|
{/* Click overlay to prevent iframe interaction */}
|
||||||
|
<div
|
||||||
|
className="absolute inset-0 cursor-pointer"
|
||||||
|
onClick={() => setShowMapClickModal(true)}
|
||||||
|
/>
|
||||||
{/* Open in Google Maps overlay button */}
|
{/* Open in Google Maps overlay button */}
|
||||||
<a
|
<a
|
||||||
href={googleMapsUrl}
|
href={googleMapsUrl}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="absolute bottom-3 right-3 inline-flex items-center gap-2 px-3 py-1.5 bg-white/90 backdrop-blur border border-gray-300 rounded-lg text-xs font-medium text-gray-700 hover:bg-white hover:border-blue-500 transition-all shadow-md"
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
className="absolute bottom-3 right-3 inline-flex items-center gap-2 px-3 py-1.5 bg-white/90 backdrop-blur border border-gray-300 rounded-lg text-xs font-medium text-gray-700 hover:bg-white hover:border-blue-500 transition-all shadow-md z-10"
|
||||||
>
|
>
|
||||||
<svg className="w-3.5 h-3.5" viewBox="0 0 24 24" fill="currentColor">
|
<svg className="w-3.5 h-3.5" viewBox="0 0 24 24" fill="currentColor">
|
||||||
<path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"/>
|
<path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"/>
|
||||||
@@ -561,6 +636,43 @@ export default function ScraperTest({ onJobsChange, onSelectReviews }: ScraperTe
|
|||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" />
|
||||||
</svg>
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
|
{/* Map Click Warning Modal */}
|
||||||
|
{showMapClickModal && (
|
||||||
|
<div
|
||||||
|
className="absolute inset-0 flex items-center justify-center backdrop-blur-md bg-gray-900/40 p-4 z-20"
|
||||||
|
onClick={() => setShowMapClickModal(false)}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="bg-white rounded-2xl p-6 shadow-2xl max-w-sm border-2 border-blue-500 animate-fade-in"
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
<div className="text-center mb-4">
|
||||||
|
<div className="text-4xl mb-3">🔍</div>
|
||||||
|
<h3 className="text-xl font-bold text-gray-900 mb-2">Use the Search Fields</h3>
|
||||||
|
<p className="text-sm text-gray-600">
|
||||||
|
Due to technical limitations, please use the <strong>Business Name</strong> and <strong>Location</strong> fields above to find your business.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="bg-blue-50 border border-blue-200 rounded-lg p-3 mb-4">
|
||||||
|
<p className="text-xs text-blue-800">
|
||||||
|
<strong>Tip:</strong> Be specific with the business name and include the city for accurate results.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
setShowMapClickModal(false);
|
||||||
|
searchInputRef.current?.focus();
|
||||||
|
}}
|
||||||
|
className="w-full py-3 bg-blue-600 hover:bg-blue-700 text-white rounded-xl font-semibold transition-all flex items-center justify-center gap-2"
|
||||||
|
>
|
||||||
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
||||||
|
</svg>
|
||||||
|
Go to Search
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<div className="h-[300px] flex items-center justify-center text-gray-400">
|
<div className="h-[300px] flex items-center justify-center text-gray-400">
|
||||||
|
|||||||
Reference in New Issue
Block a user