239 lines
6.6 KiB
TypeScript
239 lines
6.6 KiB
TypeScript
import React, { useEffect, useState } from 'react';
|
|
import { View, Text, ScrollView, StyleSheet, TouchableOpacity, Linking } from 'react-native';
|
|
import { useLocalSearchParams, useRouter } from 'expo-router';
|
|
import { Ionicons } from '@expo/vector-icons';
|
|
import { getMedicine, getMedicinePharmacies } from '../../services/medicines';
|
|
import { StockBadge } from '../../components/StockBadge';
|
|
import { LoadingSpinner } from '../../components/LoadingSpinner';
|
|
import { colors, spacing, borderRadius } from '../../constants/theme';
|
|
import { Medicine, PharmacyMedicine } from '../../types';
|
|
|
|
export default function MedicineDetailScreen() {
|
|
const { id } = useLocalSearchParams<{ id: string }>();
|
|
const router = useRouter();
|
|
const [medicine, setMedicine] = useState<Medicine | null>(null);
|
|
const [pharmacies, setPharmacies] = useState<PharmacyMedicine[]>([]);
|
|
const [isLoading, setIsLoading] = useState(true);
|
|
|
|
useEffect(() => {
|
|
if (!id) return;
|
|
|
|
const fetchMedicine = async () => {
|
|
try {
|
|
const [medData, pharmData] = await Promise.all([
|
|
getMedicine(id),
|
|
getMedicinePharmacies(id),
|
|
]);
|
|
setMedicine(medData);
|
|
setPharmacies(pharmData);
|
|
} catch (error) {
|
|
console.error('Error fetching medicine:', error);
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
};
|
|
|
|
fetchMedicine();
|
|
}, [id]);
|
|
|
|
const handleDirections = (latitude: number, longitude: number) => {
|
|
const url = `https://www.google.com/maps/dir/?api=1&destination=${latitude},${longitude}`;
|
|
Linking.openURL(url);
|
|
};
|
|
|
|
if (isLoading) {
|
|
return <LoadingSpinner message="Cargando medicamento..." />;
|
|
}
|
|
|
|
if (!medicine) {
|
|
return (
|
|
<View style={styles.errorContainer}>
|
|
<Text style={styles.errorText}>Medicamento no encontrado</Text>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<ScrollView style={styles.container}>
|
|
<View style={styles.header}>
|
|
<Text style={styles.name}>{medicine.nombre}</Text>
|
|
<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="Precio"
|
|
value={medicine.precio ? `${medicine.precio.toFixed(2)} €` : 'No disponible'}
|
|
/>
|
|
<InfoRow label="Registro" value={medicine.nregistro} />
|
|
</View>
|
|
|
|
<View style={styles.pharmaciesSection}>
|
|
<Text style={styles.sectionTitle}>
|
|
Farmacias ({pharmacies.length})
|
|
</Text>
|
|
|
|
{pharmacies.length === 0 ? (
|
|
<Text style={styles.noPharmacies}>No hay farmacias con este medicamento</Text>
|
|
) : (
|
|
pharmacies.map((pharm) => (
|
|
<View key={pharm.id} style={styles.pharmacyCard}>
|
|
<TouchableOpacity
|
|
style={styles.pharmacyCardContent}
|
|
onPress={() => router.push(`/pharmacy/${pharm.pharmacy_id}`)}
|
|
>
|
|
<View style={styles.pharmacyInfo}>
|
|
<Text style={styles.pharmacyName}>{pharm.pharmacy?.name}</Text>
|
|
<Text style={styles.pharmacyAddress}>{pharm.pharmacy?.address}</Text>
|
|
</View>
|
|
<View style={styles.pharmacyStock}>
|
|
<Text style={styles.price}>{pharm.price.toFixed(2)} €</Text>
|
|
<Text style={styles.stock}>Stock: {pharm.stock}</Text>
|
|
</View>
|
|
</TouchableOpacity>
|
|
{pharm.pharmacy?.latitude != null && pharm.pharmacy?.longitude != null && (
|
|
<TouchableOpacity
|
|
style={styles.directionsButton}
|
|
onPress={() => handleDirections(pharm.pharmacy.latitude, pharm.pharmacy.longitude)}
|
|
>
|
|
<Ionicons name="navigate" size={16} color={colors.primary} />
|
|
<Text style={styles.directionsText}>Cómo llegar</Text>
|
|
</TouchableOpacity>
|
|
)}
|
|
</View>
|
|
))
|
|
)}
|
|
</View>
|
|
</ScrollView>
|
|
);
|
|
}
|
|
|
|
function InfoRow({ label, value }: { label: string; value: string }) {
|
|
return (
|
|
<View style={styles.infoRow}>
|
|
<Text style={styles.infoLabel}>{label}</Text>
|
|
<Text style={styles.infoValue}>{value}</Text>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
flex: 1,
|
|
backgroundColor: colors.background,
|
|
},
|
|
header: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
alignItems: 'flex-start',
|
|
padding: spacing.md,
|
|
backgroundColor: colors.card,
|
|
},
|
|
name: {
|
|
flex: 1,
|
|
fontSize: 22,
|
|
fontWeight: 'bold',
|
|
color: colors.text,
|
|
marginRight: spacing.sm,
|
|
},
|
|
infoSection: {
|
|
backgroundColor: colors.card,
|
|
marginTop: spacing.sm,
|
|
padding: spacing.md,
|
|
},
|
|
infoRow: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
paddingVertical: spacing.sm,
|
|
borderBottomWidth: 1,
|
|
borderBottomColor: colors.separator,
|
|
},
|
|
infoLabel: {
|
|
fontSize: 14,
|
|
color: colors.textSecondary,
|
|
},
|
|
infoValue: {
|
|
fontSize: 14,
|
|
color: colors.text,
|
|
fontWeight: '500',
|
|
},
|
|
pharmaciesSection: {
|
|
marginTop: spacing.sm,
|
|
padding: spacing.md,
|
|
},
|
|
sectionTitle: {
|
|
fontSize: 18,
|
|
fontWeight: '600',
|
|
color: colors.text,
|
|
marginBottom: spacing.md,
|
|
},
|
|
noPharmacies: {
|
|
color: colors.textSecondary,
|
|
textAlign: 'center',
|
|
padding: spacing.xl,
|
|
},
|
|
pharmacyCard: {
|
|
backgroundColor: colors.card,
|
|
borderRadius: borderRadius.md,
|
|
marginBottom: spacing.sm,
|
|
overflow: 'hidden',
|
|
},
|
|
pharmacyCardContent: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
padding: spacing.md,
|
|
},
|
|
pharmacyInfo: {
|
|
flex: 1,
|
|
},
|
|
pharmacyName: {
|
|
fontSize: 16,
|
|
fontWeight: '600',
|
|
color: colors.text,
|
|
},
|
|
pharmacyAddress: {
|
|
fontSize: 14,
|
|
color: colors.textSecondary,
|
|
marginTop: spacing.xs,
|
|
},
|
|
pharmacyStock: {
|
|
alignItems: 'flex-end',
|
|
},
|
|
price: {
|
|
fontSize: 16,
|
|
fontWeight: '600',
|
|
color: colors.primary,
|
|
},
|
|
stock: {
|
|
fontSize: 12,
|
|
color: colors.textSecondary,
|
|
marginTop: spacing.xs,
|
|
},
|
|
directionsButton: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
gap: spacing.xs,
|
|
paddingVertical: spacing.sm,
|
|
borderTopWidth: 1,
|
|
borderTopColor: colors.separator,
|
|
},
|
|
directionsText: {
|
|
color: colors.primary,
|
|
fontSize: 14,
|
|
fontWeight: '600',
|
|
},
|
|
errorContainer: {
|
|
flex: 1,
|
|
justifyContent: 'center',
|
|
alignItems: 'center',
|
|
},
|
|
errorText: {
|
|
fontSize: 16,
|
|
color: colors.textSecondary,
|
|
},
|
|
});
|