159 lines
5.5 KiB
TypeScript
159 lines
5.5 KiB
TypeScript
import PlaneArrivalIcon from '@/assets/icons/plane-arrival-solid-full.svg';
|
|
import PlaneDepartureIcon from '@/assets/icons/plane-departure-solid-full.svg';
|
|
import { colors } from '@/assets/styles/colors';
|
|
import { Escala, VooSegment } from '@/assets/types';
|
|
import styles from '@/styles/screens/reserva/detail.styles';
|
|
import { FontAwesome } from '@expo/vector-icons';
|
|
import { Alert, Image, Linking, Platform, Pressable, Text, View } from 'react-native';
|
|
import { formatDateLong } from './formatters';
|
|
|
|
type SegmentProps = {
|
|
voo: Escala | VooSegment;
|
|
tipo: 'ida' | 'volta';
|
|
isLast: boolean;
|
|
onMapaPress?: () => void;
|
|
};
|
|
|
|
const planeIconProps = { width: 16, height: 16, fill: colors.vermelho } as const;
|
|
|
|
function abrirMapaAeroporto(lat: number, lng: number, nome: string) {
|
|
const url = Platform.OS === 'ios'
|
|
? `maps://?ll=${lat},${lng}&q=${encodeURIComponent(nome)}`
|
|
: `geo:${lat},${lng}?q=${encodeURIComponent(nome)}`;
|
|
|
|
Linking.openURL(url).catch(() =>
|
|
Alert.alert('Erro', 'Não foi possível abrir a aplicação de mapas.'),
|
|
);
|
|
}
|
|
|
|
function VooSegmentCard({ voo, tipo }: Omit<SegmentProps, 'onMapaPress' | 'isLast'>) {
|
|
const legLabel = tipo === 'ida' ? 'DATA DE IDA' : 'DATA DE REGRESSO';
|
|
const LegPlaneIcon = tipo === 'ida' ? PlaneDepartureIcon : PlaneArrivalIcon;
|
|
|
|
const escala = voo as Escala;
|
|
const gps = escala.infoAeroportoDeparture?.gps;
|
|
const nomeAeroporto = escala.infoAeroportoDeparture?.name ?? voo.departureAirport ?? voo.departureAirportCode;
|
|
|
|
const handleMapaPress = () => {
|
|
if (gps?.lat != null && gps?.lng != null) {
|
|
abrirMapaAeroporto(Number(gps.lat), Number(gps.lng), nomeAeroporto);
|
|
} else {
|
|
Alert.alert('Sem coordenadas', 'Não há informação de localização para este aeroporto.');
|
|
}
|
|
};
|
|
|
|
return (
|
|
<View>
|
|
<View style={styles.vooRouteRow}>
|
|
<View style={styles.vooSideCol}>
|
|
<Text style={styles.vooCode}>{voo.departureAirportCode}</Text>
|
|
<Text style={styles.vooTime}>{voo.departureTime}</Text>
|
|
<Text style={styles.vooAirport}>
|
|
{voo.departureAirportCode}-{voo.departureAirport}
|
|
</Text>
|
|
</View>
|
|
|
|
<View style={styles.vooMidCol}>
|
|
<Text style={styles.vooDuration}>{voo.flightTime}</Text>
|
|
<View style={styles.vooPathWrap}>
|
|
<View style={styles.vooPathLine} />
|
|
<View style={styles.vooPathIcon}>
|
|
<FontAwesome
|
|
name="plane"
|
|
size={16}
|
|
color={colors.cinza}
|
|
style={{ transform: [{ rotate: '45deg' }] }}
|
|
/>
|
|
</View>
|
|
</View>
|
|
</View>
|
|
|
|
<View style={[styles.vooSideCol, styles.vooSideColRight]}>
|
|
<Text style={[styles.vooCode, styles.vooCodeRight]}>{voo.arrivalAirportCode}</Text>
|
|
<Text style={[styles.vooTime, styles.vooTimeRight]}>{voo.arrivalTime}</Text>
|
|
<Text style={[styles.vooAirport, styles.vooAirportRight]}>
|
|
{voo.arrivalAirportCode}-{voo.arrivalAirport}
|
|
</Text>
|
|
</View>
|
|
</View>
|
|
|
|
<View style={styles.vooInfoBox}>
|
|
<View style={styles.vooInfoColLeft}>
|
|
<Text style={styles.vooInfoDate}>{formatDateLong(voo.departureDate)}</Text>
|
|
<View style={styles.vooLegRow}>
|
|
<LegPlaneIcon {...planeIconProps} />
|
|
<Text style={styles.vooLegLabel}>{legLabel}</Text>
|
|
</View>
|
|
</View>
|
|
|
|
<View style={styles.vooInfoColRight}>
|
|
{!!voo.malaLabel && (
|
|
<Text style={styles.vooMetaLine}>
|
|
<Text style={styles.vooMetaLabel}>Bagagem: </Text>
|
|
<Text style={styles.vooMetaValue}>{voo.malaLabel}</Text>
|
|
</Text>
|
|
)}
|
|
{!!voo.class && (
|
|
<Text style={styles.vooMetaLine}>
|
|
<Text style={styles.vooMetaLabel}>Classe: </Text>
|
|
<Text style={styles.vooMetaValue}>{voo.class}</Text>
|
|
</Text>
|
|
)}
|
|
</View>
|
|
</View>
|
|
|
|
<Pressable style={styles.mapaBtn} onPress={handleMapaPress}>
|
|
<Text style={styles.mapaBtnText}>
|
|
Mapa {voo.departureAirportCode}
|
|
</Text>
|
|
<Image source={require('@/assets/icons/seta-up.png')} style={styles.mapaBtnIcon} />
|
|
</Pressable>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
type GroupProps = {
|
|
segmentos: (Escala | VooSegment)[];
|
|
tipo: 'ida' | 'volta';
|
|
};
|
|
|
|
export function VooCard({ segmentos, tipo }: GroupProps) {
|
|
if (!segmentos.length) return null;
|
|
const temEscalas = segmentos.length > 1;
|
|
|
|
return (
|
|
<View style={styles.vooCard}>
|
|
{temEscalas && (
|
|
<View style={styles.vooEscalasBadge}>
|
|
<FontAwesome name="random" size={14} color={colors.azul} />
|
|
<Text style={styles.vooEscalasBadgeText}>
|
|
{segmentos.length - 1} {segmentos.length - 1 === 1 ? 'escala' : 'escalas'}
|
|
</Text>
|
|
</View>
|
|
)}
|
|
|
|
{segmentos.map((voo, idx) => (
|
|
<View key={`seg-${idx}`}>
|
|
<VooSegmentCard
|
|
voo={voo}
|
|
tipo={tipo}
|
|
/>
|
|
|
|
{idx < segmentos.length - 1 && (
|
|
<View style={styles.vooEscalaDivider}>
|
|
<View style={styles.vooEscalaLine} />
|
|
<View style={styles.vooEscalaChip}>
|
|
<FontAwesome name="clock-o" size={10} color="#4A6592" />
|
|
<Text style={styles.vooEscalaChipText}>
|
|
Escala em {voo.arrivalAirportCode}
|
|
</Text>
|
|
</View>
|
|
<View style={styles.vooEscalaLine} />
|
|
</View>
|
|
)}
|
|
</View>
|
|
))}
|
|
</View>
|
|
);
|
|
}
|