Frontend Hotfixes & Backend improvements
Run Tests on Branches / Detect Changes (push) Successful in 9s
Run Tests on Branches / Backend Tests (push) Successful in 1m51s
Run Tests on Branches / Frontend Tests (push) Has been skipped
Run Tests on Branches / Frontend Mobile Tests (push) Successful in 1m44s

This commit is contained in:
Ichitux
2026-07-09 00:58:31 +02:00
parent 16fea2de8f
commit 5f604b11ba
8 changed files with 73 additions and 31 deletions
+39 -9
View File
@@ -151,19 +151,52 @@ export async function getMedicineDetails(nregistro) {
return JSON.parse(cachedData);
}
// Consultar la API de CIMA
// Intentar obtener de la API de CIMA (endpoint individual puede no existir)
console.log(`🌐 Fetching medicine details from CIMA: ${nregistro}`);
const response = await axios.get(`${CIMA_API_BASE_URL}/medicamento/${nregistro}`, {
try {
const response = await axios.get(`${CIMA_API_BASE_URL}/medicamento/${nregistro}`, {
timeout: 5000
});
if (response.data) {
const med = response.data;
const medicineDetails = {
id: med.nregistro,
nregistro: med.nregistro,
name: med.nombre,
active_ingredient: med.principiosActivos?.[0]?.nombre || med.vtm?.nombre || null,
dosage: med.dosis || null,
form: med.formaFarmaceutica?.nombre || null,
formSimplified: med.formaFarmaceuticaSimplificada?.nombre || null,
laboratory: med.labtitular,
prescription: med.cpresc,
commercialized: med.comerc,
generic: med.generico,
photos: med.fotos || [],
docs: med.docs || [],
presentations: med.presentaciones || []
};
await redisClient.setEx(cacheKey, CACHE_TTL * 24, JSON.stringify(medicineDetails));
return medicineDetails;
}
} catch (apiError) {
console.log(`⚠️ Individual medicine endpoint failed, trying search fallback`);
}
// Fallback: buscar por nregistro usando el endpoint de búsqueda
const searchResponse = await axios.get(`${CIMA_API_BASE_URL}/medicamentos`, {
params: { nregistro },
timeout: 5000
});
if (response.data) {
const med = response.data;
if (searchResponse.data?.resultados?.length > 0) {
const med = searchResponse.data.resultados[0];
const medicineDetails = {
id: med.nregistro,
nregistro: med.nregistro,
name: med.nombre,
active_ingredient: med.principiosActivos?.[0]?.nombre || med.vtm?.nombre || null,
active_ingredient: med.vtm?.nombre || null,
dosage: med.dosis || null,
form: med.formaFarmaceutica?.nombre || null,
formSimplified: med.formaFarmaceuticaSimplificada?.nombre || null,
@@ -172,13 +205,10 @@ export async function getMedicineDetails(nregistro) {
commercialized: med.comerc,
generic: med.generico,
photos: med.fotos || [],
docs: med.docs || [],
presentations: med.presentaciones || []
docs: med.docs || []
};
// Guardar en caché (TTL más largo para detalles específicos)
await redisClient.setEx(cacheKey, CACHE_TTL * 24, JSON.stringify(medicineDetails));
return medicineDetails;
}
+1 -1
View File
@@ -4,7 +4,7 @@ import MapView, { Marker } from 'react-native-maps';
import { useRouter } from 'expo-router';
import { getPharmacies } from '../../services/pharmacies';
import { LoadingSpinner } from '../../components/LoadingSpinner';
import { colors, spacing } from '../../constants/theme';
import { colors, spacing, borderRadius } from '../../constants/theme';
import { Pharmacy } from '../../types';
export default function MapScreen() {
+2 -2
View File
@@ -97,10 +97,10 @@ const bgStyles = StyleSheet.create({
flex: 1,
},
backgroundImage: {
opacity: 0.5,
opacity: 0.8,
},
overlay: {
...StyleSheet.absoluteFillObject,
backgroundColor: 'rgba(255, 252, 245, 0.48)',
backgroundColor: 'rgba(255, 252, 245, 0.2)',
},
});
+7 -6
View File
@@ -56,17 +56,18 @@ export default function MedicineDetailScreen() {
return (
<ScrollView style={styles.container}>
<View style={styles.header}>
<Text style={styles.name}>{medicine.nombre}</Text>
<StockBadge stock={medicine.stock} />
<Text style={styles.name}>{medicine.name}</Text>
{medicine.stock != null && <StockBadge stock={medicine.stock} />}
</View>
<View style={styles.infoSection}>
<InfoRow label="Principio activo" value={medicine.principioActivo} />
<InfoRow label="Laboratorio" value={medicine.laboratorio} />
<InfoRow label="Forma farmacéutica" value={medicine.formaFarmaceutica} />
<InfoRow label="Principio activo" value={medicine.active_ingredient} />
<InfoRow label="Laboratorio" value={medicine.laboratory} />
<InfoRow label="Forma farmacéutica" value={medicine.form} />
<InfoRow label="Dosificación" value={medicine.dosage} />
<InfoRow
label="Precio"
value={medicine.precio ? `${medicine.precio.toFixed(2)}` : 'No disponible'}
value={medicine.precio != null ? `${medicine.precio.toFixed(2)}` : 'No disponible'}
/>
<InfoRow label="Registro" value={medicine.nregistro} />
</View>
@@ -29,27 +29,27 @@ export function MedicineCard({ medicine }: MedicineCardProps) {
>
<View style={styles.header}>
<Text style={[styles.name, isTablet && styles.nameTablet]} numberOfLines={2}>
{medicine.nombre}
{medicine.name}
</Text>
<StockBadge stock={medicine.stock} />
{medicine.stock != null && <StockBadge stock={medicine.stock} />}
</View>
<Text style={styles.principioActivo} numberOfLines={1}>
{medicine.principioActivo}
{medicine.active_ingredient}{medicine.dosage ? ` - ${medicine.dosage}` : ''}
</Text>
<View style={styles.footer}>
<View style={styles.priceContainer}>
<Ionicons name="pricetag" size={14} color={colors.textSecondary} />
<Text style={[styles.price, isTablet && styles.priceTablet]}>
{medicine.precio ? `${medicine.precio.toFixed(2)}` : 'Sin precio'}
{medicine.precio != null ? `${medicine.precio.toFixed(2)}` : 'Sin precio'}
</Text>
</View>
<View style={styles.labContainer}>
<Ionicons name="business" size={14} color={colors.textSecondary} />
<Text style={[styles.laboratorio, isTablet && styles.laboratorioTablet]} numberOfLines={1}>
{medicine.laboratorio}
{medicine.laboratory}
</Text>
</View>
</View>
+3 -1
View File
@@ -11,8 +11,10 @@ const ENV = {
const environment = Constants.expoConfig?.extra?.environment || (__DEV__ ? 'development' : 'production');
const envBaseUrl = process.env.EXPO_PUBLIC_API_URL;
export const config = {
API_BASE_URL: ENV[environment as keyof typeof ENV]?.API_BASE_URL || ENV.development.API_BASE_URL,
API_BASE_URL: envBaseUrl || ENV[environment as keyof typeof ENV]?.API_BASE_URL || ENV.development.API_BASE_URL,
SEARCH_DEBOUNCE_MS: 300,
CACHE_STALE_TIME: 5 * 60 * 1000, // 5 minutes
CACHE_CACHE_TIME: 30 * 60 * 1000, // 30 minutes
+15 -7
View File
@@ -1,12 +1,20 @@
export interface Medicine {
id: string;
nregistro: string;
nombre: string;
principioActivo: string;
laboratorio: string;
formaFarmaceutica: string;
precio: number | null;
stock: number;
disponibilidad: 'disponible' | 'sin_stock' | 'bajo_stock';
name: string;
active_ingredient: string;
dosage: string;
form: string;
formSimplified: string;
laboratory: string;
prescription: string;
commercialized: boolean;
generic: boolean;
photos: string[];
docs: { tipo: number; url: string; urlHtml?: string; secc: boolean; fecha: number }[];
// Optional pharmacy-specific fields (only present in pharmacy_medicines joins)
precio?: number | null;
stock?: number;
}
export interface Pharmacy {