Files
FarmaFinder/apps/frontend-mobile/services/products.ts
T
Antoni Nuñez Romeu b34657c78f feat: add parapharmacy API with MongoDB and N8N setup
- Create parapharmacy-api microservice with Express + Swagger + MongoDB
- Add product model with full-text search and deduplication
- Add CRUD endpoints and bulk upsert for scrapers
- Update docker-compose.yml with MongoDB, N8N, and parapharmacy-api services
- Add proxy endpoints in FarmaFinder backend for parapharmacy
- Update frontend services to use parapharmacy API
- Add Swagger documentation at /api/docs
2026-07-16 12:26:54 +02:00

120 lines
3.2 KiB
TypeScript

import api from './api';
export interface Product {
id: string;
_id?: string;
source: 'cima' | 'openfoodfacts' | 'promofarma' | 'pharmarket' | 'docmorris' | '1001farma' | 'primor' | 'mifarma';
name: string;
brand: string;
category: string;
subcategory?: string;
image_url: string | null;
source_url?: string;
price?: number;
original_price?: number;
available?: boolean;
rating?: number;
review_count?: number;
active_ingredient?: string;
dosage?: string;
form?: string;
prescription?: string;
commercialized?: boolean;
photos?: { tipo: string; url: string }[];
docs?: { tipo: number; url: string }[];
nutriscore?: string;
ingredients?: string;
nova_group?: number;
eco_score?: string;
}
export interface ProductSearchResponse {
results: Product[];
total: number;
page?: number;
pages?: number;
sources?: {
cima: number;
openfoodfacts: number;
};
}
export async function searchProducts(query: string): Promise<Product[]> {
if (!query || query.trim().length < 2) return [];
try {
const { data } = await api.get<ProductSearchResponse>('/products/search', {
params: { q: query }
});
return data.results || [];
} catch (error) {
console.error('[Products] Search error:', error);
return [];
}
}
export async function searchParapharmacy(query: string, options?: {
category?: string;
brand?: string;
page?: number;
limit?: number;
}): Promise<ProductSearchResponse> {
if (!query || query.trim().length < 2) {
return { results: [], total: 0 };
}
try {
const params: Record<string, string | number> = { q: query };
if (options?.category) params.category = options.category;
if (options?.brand) params.brand = options.brand;
if (options?.page) params.page = options.page;
if (options?.limit) params.limit = options.limit;
const { data } = await api.get<ProductSearchResponse>('/products/parapharmacy/search', {
params
});
return data;
} catch (error) {
console.error('[Parapharmacy] Search error:', error);
return { results: [], total: 0 };
}
}
export async function getParapharmacyProduct(id: string): Promise<Product | null> {
try {
const { data } = await api.get<Product>(`/products/parapharmacy/${id}`);
return data;
} catch (error) {
console.error('[Parapharmacy] Detail error:', error);
return null;
}
}
export async function getParapharmacyCategories(): Promise<string[]> {
try {
const { data } = await api.get<string[]>('/products/parapharmacy/categories');
return data || [];
} catch (error) {
console.error('[Parapharmacy] Categories error:', error);
return [];
}
}
export async function getParapharmacyBrands(): Promise<string[]> {
try {
const { data } = await api.get<string[]>('/products/parapharmacy/brands');
return data || [];
} catch (error) {
console.error('[Parapharmacy] Brands error:', error);
return [];
}
}
export async function getProduct(source: string, id: string): Promise<Product | null> {
try {
const { data } = await api.get<Product>(`/products/${source}/${id}`);
return data;
} catch (error) {
console.error('[Products] Detail error:', error);
return null;
}
}