73 lines
3.1 KiB
TypeScript
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' },
|
|
});
|