155 lines
4.2 KiB
TypeScript
155 lines
4.2 KiB
TypeScript
import React, { useState, useEffect } from 'react';
|
|
import { View, FlatList, StyleSheet, Text, TouchableOpacity, useWindowDimensions } from 'react-native';
|
|
import { Ionicons } from '@expo/vector-icons';
|
|
import { useRouter } from 'expo-router';
|
|
import { SearchBar } from '../../components/SearchBar';
|
|
import { MedicineCard } from '../../components/MedicineCard';
|
|
import { LoadingSpinner } from '../../components/LoadingSpinner';
|
|
import { useDebounce } from '../../hooks/useDebounce';
|
|
import { searchMedicines } from '../../services/medicines';
|
|
import { colors, spacing, borderRadius } from '../../constants/theme';
|
|
import { Medicine } from '../../types';
|
|
import { config } from '../../constants/config';
|
|
|
|
const TABLET_MIN_WIDTH = 768;
|
|
|
|
export default function HomeScreen() {
|
|
const router = useRouter();
|
|
const { width } = useWindowDimensions();
|
|
const isTablet = width >= TABLET_MIN_WIDTH;
|
|
const [query, setQuery] = useState('');
|
|
const [results, setResults] = useState<Medicine[]>([]);
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
const debouncedQuery = useDebounce(query, config.SEARCH_DEBOUNCE_MS);
|
|
|
|
useEffect(() => {
|
|
if (debouncedQuery.length < 2) {
|
|
setResults([]);
|
|
return;
|
|
}
|
|
|
|
const fetchResults = async () => {
|
|
setIsLoading(true);
|
|
setError(null);
|
|
try {
|
|
const data = await searchMedicines(debouncedQuery);
|
|
setResults(data);
|
|
} catch (err) {
|
|
setError('Error al buscar medicamentos');
|
|
console.error(err);
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
};
|
|
|
|
fetchResults();
|
|
}, [debouncedQuery]);
|
|
|
|
const handleSearch = (searchQuery: string) => {
|
|
setQuery(searchQuery);
|
|
};
|
|
|
|
return (
|
|
<View style={styles.container}>
|
|
<View style={[styles.searchContainer, isTablet && styles.searchContainerTablet]}>
|
|
<SearchBar
|
|
onSearch={handleSearch}
|
|
value={query}
|
|
onChangeText={setQuery}
|
|
/>
|
|
<TouchableOpacity
|
|
style={styles.scannerButton}
|
|
onPress={() => router.push('/scanner')}
|
|
>
|
|
<Ionicons name="scan" size={22} color="#ffffff" />
|
|
</TouchableOpacity>
|
|
</View>
|
|
|
|
{isLoading && <LoadingSpinner message="Buscando medicamentos..." />}
|
|
|
|
{error && (
|
|
<View style={[styles.errorContainer, isTablet && styles.errorContainerTablet]}>
|
|
<Text style={styles.errorText}>{error}</Text>
|
|
</View>
|
|
)}
|
|
|
|
{!isLoading && !error && results.length === 0 && query.length >= 2 && (
|
|
<View style={styles.emptyContainer}>
|
|
<Text style={styles.emptyText}>No se encontraron medicamentos</Text>
|
|
</View>
|
|
)}
|
|
|
|
<FlatList
|
|
data={results}
|
|
keyExtractor={(item) => item.nregistro}
|
|
renderItem={({ item }) => <MedicineCard medicine={item} />}
|
|
contentContainerStyle={[styles.list, isTablet && styles.listTablet]}
|
|
showsVerticalScrollIndicator={false}
|
|
/>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
flex: 1,
|
|
backgroundColor: colors.background,
|
|
},
|
|
searchContainer: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
paddingRight: spacing.lg,
|
|
},
|
|
searchContainerTablet: {
|
|
maxWidth: 700,
|
|
alignSelf: 'center',
|
|
width: '100%',
|
|
},
|
|
scannerButton: {
|
|
width: 44,
|
|
height: 44,
|
|
borderRadius: 22,
|
|
backgroundColor: colors.scanButton,
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
shadowColor: '#2b5bb5',
|
|
shadowOffset: { width: 0, height: 4 },
|
|
shadowOpacity: 0.3,
|
|
shadowRadius: 12,
|
|
elevation: 6,
|
|
},
|
|
list: {
|
|
paddingBottom: spacing.xl,
|
|
},
|
|
listTablet: {
|
|
maxWidth: 700,
|
|
alignSelf: 'center',
|
|
width: '100%',
|
|
},
|
|
errorContainer: {
|
|
padding: spacing.md,
|
|
marginHorizontal: spacing.lg,
|
|
backgroundColor: colors.dangerContainer,
|
|
borderRadius: borderRadius.lg,
|
|
},
|
|
errorContainerTablet: {
|
|
maxWidth: 700,
|
|
alignSelf: 'center',
|
|
},
|
|
errorText: {
|
|
color: colors.danger,
|
|
textAlign: 'center',
|
|
fontSize: 14,
|
|
},
|
|
emptyContainer: {
|
|
padding: spacing.xl,
|
|
alignItems: 'center',
|
|
},
|
|
emptyText: {
|
|
color: colors.textSecondary,
|
|
fontSize: 16,
|
|
},
|
|
});
|