Files
time_to_leave/apps/mobile/src/components/BikeSection.tsx
T

73 lines
3.1 KiB
TypeScript

import { ActivityIndicator, StyleSheet, Text, View } from 'react-native';
import { FontAwesomeIcon } from '@fortawesome/react-native-fontawesome';
import { faClock, faRuler } from '@fortawesome/free-solid-svg-icons';
import { formatDuration, formatDistance } from '@timetoleave/core';
import type { BikeRoute, Station } from '@timetoleave/core';
import type { AppColors } from '../hooks/useColors';
import { RouteMap } from './RouteMap';
/** Props for the bike route information section shown on event detail. */
interface Props {
bikeRoute: BikeRoute | null;
loading: boolean;
origin: Station | null;
colors: AppColors;
}
/**
* Displays cycling route duration, distance, and an interactive map for the
* event's origin → destination leg. Shows contextual empty states when no
* origin is set or no route is available.
*/
export function BikeSection({ bikeRoute, loading, origin, colors }: Props) {
return (
<View style={[styles.container, { backgroundColor: colors.background }]}>
<Text style={[styles.sectionTitle, { color: colors.text }]}>Bike route</Text>
{loading ? (
<View style={styles.centered}>
<ActivityIndicator size="small" color={colors.accent} />
<Text style={[styles.hint, { color: colors.subtext }]}>Loading bike route</Text>
</View>
) : bikeRoute ? (
<View style={[styles.card, { backgroundColor: colors.card, borderColor: colors.border }]}>
<View style={styles.row}>
<View style={styles.labelRow}>
<FontAwesomeIcon icon={faClock} size={13} color={colors.text} />
<Text style={[styles.label, { color: colors.text }]}>Dauer</Text>
</View>
<Text style={[styles.value, { color: colors.accent }]}>{formatDuration(bikeRoute.duration)}</Text>
</View>
<View style={styles.row}>
<View style={styles.labelRow}>
<FontAwesomeIcon icon={faRuler} size={13} color={colors.text} />
<Text style={[styles.label, { color: colors.text }]}>Distanz</Text>
</View>
<Text style={[styles.value, { color: colors.accent }]}>{formatDistance(bikeRoute.distance)}</Text>
</View>
{bikeRoute.geometry && (
<RouteMap geometry={bikeRoute.geometry} colors={colors} mode="bike" />
)}
</View>
) : (
<Text style={[styles.empty, { color: colors.subtext }]}>
{origin ? 'No bike route available' : 'Set origin station'}
</Text>
)}
</View>
);
}
const styles = StyleSheet.create({
container: { padding: 20 },
sectionTitle: { fontSize: 18, fontWeight: '600', marginBottom: 12 },
centered: { alignItems: 'center', gap: 8 },
hint: { fontSize: 15, marginTop: 12 },
empty: { fontSize: 14 },
card: { borderRadius: 10, padding: 14, borderWidth: 1 },
row: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingVertical: 6 },
labelRow: { flexDirection: 'row', alignItems: 'center', gap: 6 },
label: { fontSize: 15, fontWeight: '500' },
value: { fontSize: 15, fontWeight: '600' },
});