Add unified product search routes (CIMA OTC + Open Food Facts)
- GET /api/products/search?q={query} - parallel search across both sources
- GET /api/products/:source/:id - product detail by source (cima/openfoodfacts)
- Uses Promise.allSettled for fault-tolerant parallel search
- Added imports for searchOTC and OFF service functions
This commit is contained in:
+50
-1
@@ -19,7 +19,8 @@ import pinoHttp from 'pino-http';
|
||||
import multer from 'multer';
|
||||
import { createWorker } from 'tesseract.js';
|
||||
import { BarcodeDetector } from 'barcode-detector';
|
||||
import { searchMedicines, getMedicineDetails } from './cima-service.js';
|
||||
import { searchMedicines, getMedicineDetails, searchOTC } from './cima-service.js';
|
||||
import { searchBabyProducts, getBabyProductDetails } from './off-service.js';
|
||||
import { runFarmaciaWebhookImport, DEFAULT_FARMACIAS_WEBHOOK, importPharmaciesFromRows } from './farmacias-webhook-import.js';
|
||||
import { fetchPharmaciesExternal } from '../API/index.js';
|
||||
|
||||
@@ -598,6 +599,54 @@ app.get('/api/medicines/:medicineId', async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// ========== UNIFIED PRODUCT SEARCH ==========
|
||||
|
||||
app.get('/api/products/search', async (req, res) => {
|
||||
try {
|
||||
const { q } = req.query;
|
||||
if (!q || q.trim().length < 2) {
|
||||
return res.json({ results: [], total: 0 });
|
||||
}
|
||||
const searchTerm = q.trim();
|
||||
const [cimaResults, offResults] = await Promise.allSettled([
|
||||
searchOTC(searchTerm),
|
||||
searchBabyProducts(searchTerm)
|
||||
]);
|
||||
const cimaProducts = cimaResults.status === 'fulfilled' ? cimaResults.value : [];
|
||||
const offProducts = offResults.status === 'fulfilled' ? offResults.value : [];
|
||||
const allProducts = [...cimaProducts, ...offProducts]
|
||||
.sort((a, b) => a.name.localeCompare(b.name));
|
||||
res.json({
|
||||
results: allProducts,
|
||||
total: allProducts.length,
|
||||
sources: { cima: cimaProducts.length, openfoodfacts: offProducts.length }
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('[Products] Search error:', err);
|
||||
res.status(500).json({ error: 'Error searching products' });
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/api/products/:source/:id', async (req, res) => {
|
||||
try {
|
||||
const { source, id } = req.params;
|
||||
if (source === 'cima') {
|
||||
const product = await getMedicineDetails(id);
|
||||
if (!product) return res.status(404).json({ error: 'Product not found' });
|
||||
return res.json({ ...product, source: 'cima', category: 'otc' });
|
||||
}
|
||||
if (source === 'openfoodfacts') {
|
||||
const product = await getBabyProductDetails(id);
|
||||
if (!product) return res.status(404).json({ error: 'Product not found' });
|
||||
return res.json(product);
|
||||
}
|
||||
res.status(400).json({ error: 'Invalid source' });
|
||||
} catch (err) {
|
||||
console.error('[Products] Detail error:', err);
|
||||
res.status(500).json({ error: 'Error fetching product details' });
|
||||
}
|
||||
});
|
||||
|
||||
// ========== AUTHENTICATION MIDDLEWARE ==========
|
||||
|
||||
// Middleware to check if user is authenticated
|
||||
|
||||
Reference in New Issue
Block a user