First commit of the new app
This commit is contained in:
158
assets/components/reserva/VooCard.tsx
Normal file
158
assets/components/reserva/VooCard.tsx
Normal file
@@ -0,0 +1,158 @@
|
||||
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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user