feat/parapharmacy-baby-products #31
@@ -356,3 +356,44 @@
|
|||||||
color: var(--primary);
|
color: var(--primary);
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Filter tabs */
|
||||||
|
.filter-tabs {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-tab {
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
border-radius: 9999px;
|
||||||
|
border: none;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
background: var(--surface-container-lowest, #f3f4f6);
|
||||||
|
color: var(--on-surface-variant, #6b7280);
|
||||||
|
transition: all 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-tab:hover {
|
||||||
|
background: var(--surface-container-low, #e5e7eb);
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-tab--active {
|
||||||
|
background: var(--primary, #2563eb);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Products section */
|
||||||
|
.products-section {
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-subtitle {
|
||||||
|
font-size: 1.125rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--on-surface);
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React, { useState, useEffect, useMemo, useCallback } from 'react';
|
import React, { useState, useEffect, useMemo, useCallback } from 'react';
|
||||||
import SearchBar from '../components/SearchBar';
|
import SearchBar from '../components/SearchBar';
|
||||||
import MedicineResults from '../components/MedicineResults';
|
import MedicineResults from '../components/MedicineResults';
|
||||||
|
import ProductResults from '../components/ProductResults';
|
||||||
import PharmacyList from '../components/PharmacyList';
|
import PharmacyList from '../components/PharmacyList';
|
||||||
import PharmacyMap from '../components/PharmacyMap';
|
import PharmacyMap from '../components/PharmacyMap';
|
||||||
import { haversineKm, getUserPosition, hasCachedPosition } from '../utils/geo';
|
import { haversineKm, getUserPosition, hasCachedPosition } from '../utils/geo';
|
||||||
@@ -16,6 +17,8 @@ const suggestions = [
|
|||||||
function SearchView({ currentUser, onLoginRequest, initialQuery = '' }) {
|
function SearchView({ currentUser, onLoginRequest, initialQuery = '' }) {
|
||||||
const [searchQuery, setSearchQuery] = useState(initialQuery);
|
const [searchQuery, setSearchQuery] = useState(initialQuery);
|
||||||
const [medicines, setMedicines] = useState([]);
|
const [medicines, setMedicines] = useState([]);
|
||||||
|
const [products, setProducts] = useState([]);
|
||||||
|
const [searchMode, setSearchMode] = useState('all');
|
||||||
const [selectedMedicine, setSelectedMedicine] = useState(null);
|
const [selectedMedicine, setSelectedMedicine] = useState(null);
|
||||||
const [pharmacies, setPharmacies] = useState([]);
|
const [pharmacies, setPharmacies] = useState([]);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
@@ -76,6 +79,7 @@ function SearchView({ currentUser, onLoginRequest, initialQuery = '' }) {
|
|||||||
const searchMedicines = async () => {
|
const searchMedicines = async () => {
|
||||||
if (searchQuery.trim().length < 2) {
|
if (searchQuery.trim().length < 2) {
|
||||||
setMedicines([]);
|
setMedicines([]);
|
||||||
|
setProducts([]);
|
||||||
setSelectedMedicine(null);
|
setSelectedMedicine(null);
|
||||||
setPharmacies([]);
|
setPharmacies([]);
|
||||||
return;
|
return;
|
||||||
@@ -90,6 +94,16 @@ function SearchView({ currentUser, onLoginRequest, initialQuery = '' }) {
|
|||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const productsResponse = await fetch(`/api/products/search?q=${encodeURIComponent(searchQuery)}`);
|
||||||
|
if (productsResponse.ok) {
|
||||||
|
const productsData = await productsResponse.json();
|
||||||
|
setProducts(productsData.results || []);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Product search error:', err);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
const timeoutId = setTimeout(searchMedicines, 300);
|
const timeoutId = setTimeout(searchMedicines, 300);
|
||||||
return () => clearTimeout(timeoutId);
|
return () => clearTimeout(timeoutId);
|
||||||
@@ -276,6 +290,29 @@ function SearchView({ currentUser, onLoginRequest, initialQuery = '' }) {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{searchQuery && !selectedMedicine && (
|
{searchQuery && !selectedMedicine && (
|
||||||
|
<>
|
||||||
|
<div className="filter-tabs">
|
||||||
|
<button
|
||||||
|
className={`filter-tab ${searchMode === 'all' ? 'filter-tab--active' : ''}`}
|
||||||
|
onClick={() => setSearchMode('all')}
|
||||||
|
>
|
||||||
|
Todos ({medicines.length + products.length})
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className={`filter-tab ${searchMode === 'medicines' ? 'filter-tab--active' : ''}`}
|
||||||
|
onClick={() => setSearchMode('medicines')}
|
||||||
|
>
|
||||||
|
Medicamentos ({medicines.length})
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className={`filter-tab ${searchMode === 'products' ? 'filter-tab--active' : ''}`}
|
||||||
|
onClick={() => setSearchMode('products')}
|
||||||
|
>
|
||||||
|
Parafarmacia ({products.length})
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{(searchMode === 'all' || searchMode === 'medicines') && (
|
||||||
<MedicineResults
|
<MedicineResults
|
||||||
medicines={medicines}
|
medicines={medicines}
|
||||||
onSelect={(m) => {
|
onSelect={(m) => {
|
||||||
@@ -288,6 +325,20 @@ function SearchView({ currentUser, onLoginRequest, initialQuery = '' }) {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{(searchMode === 'all' || searchMode === 'products') && products.length > 0 && (
|
||||||
|
<div className="products-section">
|
||||||
|
<h3 className="section-subtitle">Parafarmacia y Bebé</h3>
|
||||||
|
<ProductResults
|
||||||
|
products={products}
|
||||||
|
onSelect={(p) => {
|
||||||
|
window.location.href = `/product/${p.source}/${p.id}`;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
{selectedMedicine && (
|
{selectedMedicine && (
|
||||||
<div className="selected-medicine-section">
|
<div className="selected-medicine-section">
|
||||||
<div className="medicine-info">
|
<div className="medicine-info">
|
||||||
|
|||||||
Reference in New Issue
Block a user