diff --git a/src/components/DeliveryMap.tsx b/src/components/DeliveryMap.tsx index 5ba7b4d..2ce4eee 100644 --- a/src/components/DeliveryMap.tsx +++ b/src/components/DeliveryMap.tsx @@ -3,6 +3,9 @@ import MapView, { Marker, Polyline } from 'react-native-maps'; import { StyleSheet, View, ActivityIndicator, ViewStyle } from 'react-native'; import { Config } from '../config'; import { Colors } from '../styles/theme'; +import PoppinsText from '../components/PoppinsText'; +import { MapPinIcon, UserIcon } from 'react-native-heroicons/solid'; +import { FontAwesome5 } from '@expo/vector-icons'; interface DeliveryMapProps { deliveryState: number; @@ -25,7 +28,7 @@ const DeliveryMap: React.FC = ({ const [customerRouteCoordinates, setCustomerRouteCoordinates] = useState< { latitude: number; longitude: number }[] >([]); - const [isLoading, setIsLoading] = useState(true); // Estado de carga + const [, setIsLoading] = useState(true); // Estado de carga // Obtener la ruta desde Google Maps Directions API const fetchRoute = async ( @@ -144,8 +147,13 @@ const DeliveryMap: React.FC = ({ return points; }; - if (isLoading) { - // Mostrar un indicador de carga mientras se obtienen los datos + if ( + // Solo espera si faltan datos críticos + branchLocation.latitude === 0 || + branchLocation.longitude === 0 || + customerLocation.latitude === 0 || + customerLocation.longitude === 0 + ) { return ( @@ -153,10 +161,11 @@ const DeliveryMap: React.FC = ({ ); } + // Mostrar el mapa aunque deliveryLocation sea null return ( = ({ longitudeDelta: 0.05, }} > - {/* Mostrar la ubicación del delivery */} + {/* Mostrar la ubicación del delivery si existe */} {deliveryLocation && ( - + + + )} {/* Mostrar la ubicación de la sucursal */} {branchLocation.latitude !== 0 && branchLocation.longitude !== 0 && ( - + + + )} {/* Mostrar la ubicación del cliente */} {customerLocation.latitude !== 0 && customerLocation.longitude !== 0 && ( - + + + )} {/* Mostrar la ruta hacia la sucursal */} @@ -210,6 +213,30 @@ const DeliveryMap: React.FC = ({ /> )} + {!deliveryLocation && ( + + + Esperando ubicación del repartidor... + + + )} ); }; diff --git a/src/components/HistoryMap.tsx b/src/components/HistoryMap.tsx index ba62402..0f0d229 100644 --- a/src/components/HistoryMap.tsx +++ b/src/components/HistoryMap.tsx @@ -2,6 +2,10 @@ import React, { useEffect, useState } from 'react'; import MapView, { Marker, Polyline } from 'react-native-maps'; import { StyleSheet, View, Alert, ViewStyle } from 'react-native'; import { Config } from '../config'; +import { Colors } from '../styles/theme'; + +import { MapPinIcon, UserIcon } from 'react-native-heroicons/solid'; +import { FontAwesome5 } from '@expo/vector-icons'; interface HistoryMapProps { deliveryLocation: { latitude: number; longitude: number }; @@ -131,25 +135,19 @@ const HistoryMap: React.FC = ({ }} > {/* Mostrar la ubicación del delivery */} - + + + {/* Mostrar la ubicación de la sucursal */} - + + + {/* Mostrar la ubicación del cliente */} - + + + {/* Mostrar la ruta hacia la sucursal */} {routeToBranch.length > 0 && ( diff --git a/src/components/OrderBadge.tsx b/src/components/OrderBadge.tsx index 553eb94..e6caedc 100644 --- a/src/components/OrderBadge.tsx +++ b/src/components/OrderBadge.tsx @@ -20,7 +20,7 @@ const STATUS_COLORS: Record = { const STATUS_LABELS: Record = { requested: 'Pendiente', - ready_for_pickup: 'A Enviar', + ready_for_pickup: 'A Retirar', completed: 'Entregado', canceled: 'Cancelado', in_progress: 'En Proceso', diff --git a/src/components/VerticalStepper.tsx b/src/components/VerticalStepper.tsx new file mode 100644 index 0000000..b770eb7 --- /dev/null +++ b/src/components/VerticalStepper.tsx @@ -0,0 +1,134 @@ +import React from 'react'; +import { View, StyleSheet } from 'react-native'; +import { Colors, FontSizes } from '../styles/theme'; +import PoppinsText from './PoppinsText'; + +interface VerticalStepperProps { + steps: { + title: string; + description: string; + }[]; + currentStep: number; +} + +const VerticalStepper: React.FC = ({ + steps, + currentStep, +}) => { + return ( + + {steps.map((step, index) => { + const isCompleted = index < currentStep - 1; + const isActive = index === currentStep - 1; + + return ( + + + {/* Línea superior (excepto para el primer paso) */} + {index > 0 && ( + + )} + + {/* Círculo del paso */} + + + {/* Línea inferior (excepto para el último paso) */} + {index < steps.length - 1 && ( + + )} + + + + {step.title} + + {step.description && ( + + {step.description} + + )} + + + ); + })} + + ); +}; + +const styles = StyleSheet.create({ + container: { + padding: 0, + }, + stepContainer: { + flexDirection: 'row', + }, + stepIndicatorContainer: { + width: 24, + alignItems: 'center', + marginRight: 8, + }, + stepIndicator: { + width: 13, + height: 13, + borderRadius: 12, + justifyContent: 'center', + alignItems: 'center', + backgroundColor: Colors.gray_500, + zIndex: 1, + }, + completedStep: { + backgroundColor: Colors.semanticSuccess, + borderColor: Colors.semanticSuccess, + }, + activeStep: { + backgroundColor: Colors.semanticSuccess, + }, + connector: { + position: 'absolute', + width: 2, + }, + completedConnector: { + backgroundColor: Colors.semanticSuccess, + }, + pendingConnector: { + backgroundColor: Colors.gray_100, + }, + stepContent: { + flex: 1, + marginBottom: 13, + }, + activeStepTitle: { + color: Colors.semanticSuccess, + }, + stepDescription: { + color: Colors.secondaryGray, + fontSize: FontSizes.c3.size, + }, +}); + +export default VerticalStepper; diff --git a/src/lib/socketUrl.ts b/src/lib/socketUrl.ts index 77fccb4..7788574 100644 --- a/src/lib/socketUrl.ts +++ b/src/lib/socketUrl.ts @@ -1,5 +1,4 @@ const devModeFlag = process.env.PHARMATECH_DEV_MODE === 'true'; - const devUrl = 'https://api-dev-8jfx.onrender.com'; const prodUrl = 'https://api-d8h5.onrender.com'; diff --git a/src/screens/ActiveOrdersScreen.tsx b/src/screens/ActiveOrdersScreen.tsx index a5fc103..8b14053 100644 --- a/src/screens/ActiveOrdersScreen.tsx +++ b/src/screens/ActiveOrdersScreen.tsx @@ -1,17 +1,23 @@ import React, { useEffect, useState } from 'react'; -import { View, StyleSheet, ScrollView, TouchableOpacity } from 'react-native'; +import { + View, + StyleSheet, + ScrollView, + TouchableOpacity, + RefreshControl, +} from 'react-native'; import { Colors, FontSizes } from '../styles/theme'; import PoppinsText from '../components/PoppinsText'; import { useRouter } from 'expo-router'; import Alert from '../components/Alerts'; -import Button from '../components/Button'; import { OrderResponse } from '@pharmatech/sdk'; import { UserService } from '../services/user'; import { truncateString } from '../utils/commons'; +import { formatPrice } from '../utils/formatPrice'; const STATUS_LABELS: Record = { requested: 'Pendiente', - ready_for_pickup: 'A Enviar', + ready_for_pickup: 'A Retirar', in_progress: 'En Proceso', approved: 'Aprobado', }; @@ -31,37 +37,52 @@ const ActiveOrdersScreen = () => { const [showInfoAlert, setShowInfoAlert] = useState(false); const [errorMessage, setErrorMessage] = useState(''); const router = useRouter(); + const [refreshing, setRefreshing] = useState(false); - useEffect(() => { - const fetchActiveOrders = async () => { - try { - const order = await UserService.getUserOrders(); - if (order.success) { - const activeOrders = order.data.results.filter( - (o) => - o.status === 'requested' || - o.status === 'approved' || - o.status === 'ready_for_pickup' || - o.status === 'in_progress', - ); - if (activeOrders.length > 0) { - setActiveOrdersList(activeOrders); - } else { - setShowInfoAlert(true); - } + const fetchActiveOrders = async () => { + try { + const order = await UserService.getUserOrders(); + if (order.success) { + const activeOrders = order.data.results.filter( + (o) => + o.status === 'requested' || + o.status === 'approved' || + o.status === 'ready_for_pickup' || + o.status === 'in_progress', + ); + if (activeOrders.length > 0) { + setActiveOrdersList(activeOrders); + } else { + setShowInfoAlert(true); } - } catch (error) { - console.log(error); - setErrorMessage('Ha ocurrido un error'); - setShowErrorAlert(true); } - }; + } catch (error) { + console.log(error); + setErrorMessage('Ha ocurrido un error'); + setShowErrorAlert(true); + } + }; + useEffect(() => { fetchActiveOrders(); }, []); + const onRefresh = async () => { + setRefreshing(true); + await fetchActiveOrders(); + }; + return ( - + + } + > {showErrorAlert && ( { {new Date(order.createdAt).toLocaleDateString()} - ${order.totalPrice.toFixed(2)} + ${formatPrice(order.totalPrice)} { Ver detalles -