The SuburbanStationSwitch
component is a sophisticated React Native component designed to display a visual timeline of a multi-leg journey involving train transfers and walking segments. It provides users with a clear, step-by-step visualization of their station switching plan, complete with real-time status tracking and animated progress indicators.
- Component Purpose
- Features
- Props Interface
- Types and Interfaces
- Component Architecture
- Implementation Details
- Styling and Layout
- Animation and Interactions
- Usage Examples
- Error Handling
- Performance Considerations
- Accessibility
- Testing Considerations
- Future Enhancements
The SuburbanStationSwitch
component serves as a critical UI element in multimodal journey planning applications, specifically designed for scenarios where users need to:
- Transfer between different train lines or modes of transport
- Navigate complex station layouts with walking segments
- Understand the sequence and timing of their journey
- Track their current progress along the planned route
This component is particularly valuable in urban transportation contexts where direct routes are not available and transfers are necessary.
- Multi-step Journey Visualization: Displays up to 4 distinct journey segments
- Real-time Progress Tracking: Shows current user position along the timeline
- Dynamic Status Updates: Responds to journey status changes with visual feedback
- Responsive Layout: Adapts to different screen sizes and orientations
- Animated Elements: Smooth transitions and visual feedback using React Native Reanimated
- Timeline Bar: Vertical progress indicator with custom styling
- Station Steps: Individual journey segments with icons, labels, and station names
- User Position Indicator: Animated blue user icon that moves along the timeline
- Transport Icons: Contextual icons for trains, walking, and transfers
- Status-based Positioning: Dynamic positioning based on current journey status
- Status-driven Updates: Component automatically updates based on journey status
- Visual Feedback: Clear indication of current position and next steps
- Progress Visualization: Intuitive understanding of journey completion
interface SuburbanStationSwitchProps {
viaStations: string[]; // Array of intermediate stations
sourceStation: string; // Starting station name
destinationStation: string; // Final destination station
status: JourneyStatus; // Current journey status
}
Prop | Type | Required | Description |
---|---|---|---|
viaStations |
string[] |
✅ | Array of intermediate stations where transfers occur. Must contain at least 2 stations. |
sourceStation |
string |
✅ | Name of the starting station where the journey begins. |
destinationStation |
string |
✅ | Name of the final destination station. |
status |
JourneyStatus |
✅ | Current status of the user's journey, determines icon position. |
type JourneyStatus =
| 'AT_SOURCE' // User is at the starting station
| 'IN_FIRST_TRAIN' // User is traveling in the first train
| 'AT_FIRST_VIA' // User has arrived at the first transfer station
| 'WALKING' // User is walking between stations
| 'IN_NEXT_STATION' // User has reached the next station
interface StationStepProps {
icon: JSX.Element; // Icon to display for this step
iconColor?: string; // Optional color override for the icon
label: string; // Descriptive text for the action
station: string; // Station name for this step
isLastItem?: boolean; // Whether this is the final step
isFirstItem?: boolean; // Whether this is the first step
}
-
SuburbanStationSwitch (Root Component)
- Manages overall layout and state
- Handles prop validation and error checking
- Orchestrates the rendering of sub-components
-
StationStep (Individual Step Component)
- Renders individual journey segments
- Handles icon rendering and text display
- Applies conditional styling based on position
-
ArrowIcon (Transfer Indicator)
- Custom SVG icon for transfer points
- Consistent visual language for transitions
SuburbanStationSwitch
├── Header Section
│ ├── Title: "Your Station Switch Plan"
│ └── Subtitle: "You will reach in 10 mins"
├── Timeline Section
│ ├── Vertical Timeline Bar
│ │ └── User Position Indicator
│ └── Station Steps List
│ ├── StationStep 1: Source Station
│ ├── StationStep 2: First Transfer
│ ├── StationStep 3: Walking Segment
│ └── StationStep 4: Destination
The component uses a sophisticated positioning algorithm to determine the user icon's location along the timeline:
const calculateUserIconPosition = (status: JourneyStatus): number => {
const TIMELINE_HEIGHT = 300; // Base timeline height in pixels
switch (status) {
case 'AT_SOURCE':
return 0; // Top of timeline
case 'IN_FIRST_TRAIN':
return TIMELINE_HEIGHT * 0.33 - 22; // 33% down, adjusted for icon height
case 'AT_FIRST_VIA':
return TIMELINE_HEIGHT * 0.5; // Middle of timeline
case 'WALKING':
return TIMELINE_HEIGHT * 0.9; // 90% down timeline
case 'IN_NEXT_STATION':
return TIMELINE_HEIGHT + 44; // Below timeline (completed)
default:
return 0;
}
};
The component dynamically generates station steps based on the provided props:
const stationSteps: StationStepProps[] = [
{
icon: <TrainIcon />,
iconColor: '#09941E',
label: 'Take train at',
station: sourceStation,
},
{
icon: <ArrowIcon />,
label: 'Get Down at',
station: firstViaStation,
},
{
icon: <WalkIcon />,
iconColor: '#656565',
label: 'Walk to',
station: secondViaStation,
},
{
icon: <TrainIcon />,
iconColor: '#09941E',
label: 'Take Train towards',
station: destinationStation,
},
];
The component includes robust error handling for invalid configurations:
if (viaStations.length < 2) {
throw new Error('SuburbanStationSwitch requires at least 2 via stations');
}
The component uses a comprehensive design system with:
- Tailwind CSS: Consistent spacing, colors, and typography
- Custom Color Palette: Brand-specific colors for different transport modes
- Typography Scale: Hierarchical text sizing and font weights
- Spacing System: Consistent padding, margins, and component spacing
Element | Color | Hex Code | Usage |
---|---|---|---|
Primary Text | Dark Gray | #313131 |
Main headings and titles |
Secondary Text | Medium Gray | #969696 |
Subtitles and descriptions |
Body Text | Dark Gray | #3B3A3C |
Station names and labels |
Train Icon | Green | #09941E |
Train-related actions |
Walk Icon | Gray | #656565 |
Walking segments |
User Icon | Blue | #047AEA |
Current position indicator |
Timeline | Light Gray | #EFEFEF |
Background and borders |
Arrow Icon | Yellow | #FFE688 |
Transfer indicators |
- Container Padding: 24px (px-6) horizontal, 30px top
- Timeline Width: 20px (w-5) with rounded corners
- User Icon Size: 30px × 28px (w-7.5 h-[28px])
- Step Spacing: 24px top padding, 20px bottom padding
- Border Separators: 1px light gray lines between steps
The component leverages React Native Reanimated for smooth animations:
import Animated from 'react-native-reanimated';
// All view elements use Animated.View for potential animations
<Animated.View style={tailwind.style('pt-[30px]')}>
While the current implementation focuses on positioning, the component structure supports:
- Smooth Transitions: Status changes can be animated
- Progress Animations: Timeline filling animations
- Icon Animations: Bouncing or pulsing effects for active states
- Entrance Animations: Staggered appearance of station steps
import { SuburbanStationSwitch } from './SuburbanStationSwitch';
const MyJourneyScreen = () => {
const journeyData = {
viaStations: ['Central Station', 'Interchange Hub'],
sourceStation: 'Home Station',
destinationStation: 'Work Station',
status: 'IN_FIRST_TRAIN' as const
};
return (
<SuburbanStationSwitch
viaStations={journeyData.viaStations}
sourceStation={journeyData.sourceStation}
destinationStation={journeyData.destinationStation}
status={journeyData.status}
/>
);
};
const [journeyStatus, setJourneyStatus] = useState<JourneyStatus>('AT_SOURCE');
// Update status based on user's actual journey progress
useEffect(() => {
const updateJourneyStatus = (newStatus: JourneyStatus) => {
setJourneyStatus(newStatus);
};
// Listen to journey updates from your navigation system
navigationListener.on('statusChange', updateJourneyStatus);
return () => navigationListener.off('statusChange', updateJourneyStatus);
}, []);
return (
<SuburbanStationSwitch
viaStations={['Station A', 'Station B']}
sourceStation="Start"
destinationStation="End"
status={journeyStatus}
/>
);
const customJourney = {
viaStations: ['Transfer Point 1', 'Transfer Point 2', 'Transfer Point 3'],
sourceStation: 'Origin Station',
destinationStation: 'Final Destination',
status: 'WALKING' as const
};
// Note: This will throw an error as the component requires exactly 2 via stations
// The component is designed for simple 2-transfer journeys
The component enforces strict validation rules:
- Via Stations Count: Must have exactly 2 intermediate stations
- Required Props: All props are mandatory
- Status Values: Must be valid JourneyStatus enum values
// ❌ Will throw error: Insufficient via stations
<SuburbanStationSwitch
viaStations={['Only One Station']}
sourceStation="Start"
destinationStation="End"
status="AT_SOURCE"
/>
// ❌ Will throw error: Missing required props
<SuburbanStationSwitch
viaStations={['Station A', 'Station B']}
// Missing other required props
/>
// ✅ Valid configuration
<SuburbanStationSwitch
viaStations={['Station A', 'Station B']}
sourceStation="Start"
destinationStation="End"
status="AT_SOURCE"
/>
- Memoization: Consider wrapping StationStep components with React.memo
- Icon Caching: SVG icons are lightweight and efficient
- Conditional Rendering: Only renders necessary elements based on status
- FlatList Optimization: Station steps could be optimized with FlatList for large numbers
- Icon Components: Lightweight SVG implementations
- Animation Objects: Minimal state objects for positioning
- Style Objects: Efficient Tailwind style generation
The component provides semantic information for screen readers:
- Station Names: Clear labeling of each station
- Action Descriptions: Descriptive text for each journey step
- Progress Indication: Current status and position information
- High Contrast: Clear color differentiation between elements
- Icon Recognition: Universal transport icons for easy understanding
- Text Hierarchy: Clear visual hierarchy with different font sizes and weights
While primarily designed for touch interfaces, the component structure supports:
- Focus Management: Logical tab order through station steps
- Status Updates: Programmatic status changes for testing and automation
describe('SuburbanStationSwitch', () => {
it('should render with valid props', () => {
const { getByText } = render(
<SuburbanStationSwitch
viaStations={['Station A', 'Station B']}
sourceStation="Start"
destinationStation="End"
status="AT_SOURCE"
/>
);
expect(getByText('Your Station Switch Plan')).toBeTruthy();
expect(getByText('Start')).toBeTruthy();
expect(getByText('End')).toBeTruthy();
});
it('should throw error with insufficient via stations', () => {
expect(() => render(
<SuburbanStationSwitch
viaStations={['Only One']}
sourceStation="Start"
destinationStation="End"
status="AT_SOURCE"
/>
)).toThrow('SuburbanStationSwitch requires at least 2 via stations');
});
it('should position user icon correctly for different statuses', () => {
const { getByTestId } = render(
<SuburbanStationSwitch
viaStations={['Station A', 'Station B']}
sourceStation="Start"
destinationStation="End"
status="WALKING"
/>
);
const userIcon = getByTestId('user-position-indicator');
expect(userIcon).toHaveStyle({ top: 270 }); // 300 * 0.9
});
});
- Status Updates: Test status changes and icon positioning
- Responsive Layout: Test on different screen sizes
- Animation Performance: Test smooth transitions between states
- Layout Consistency: Ensure consistent rendering across devices
- Icon Positioning: Verify accurate positioning for all status values
- Color Consistency: Validate brand color usage
- Multi-leg Support: Extend beyond 2-transfer journeys
- Real-time Updates: Live journey progress tracking
- Custom Icons: User-configurable transport mode icons
- Accessibility Improvements: Enhanced screen reader support
- Internationalization: Multi-language support for station names
- Performance Optimization: Implement React.memo and useMemo
- Animation Library: Enhanced animation capabilities
- Theme Support: Dark mode and custom theme support
- Responsive Design: Better adaptation to different screen sizes
- Type Safety: Enhanced TypeScript strict mode compliance
- Flexible Configuration: Support for custom journey patterns
- Event Callbacks: Journey status change notifications
- Custom Styling: Override default styles and colors
- Accessibility Props: Enhanced accessibility configuration options
The SuburbanStationSwitch
component represents a sophisticated solution for visualizing complex multi-leg journeys in transportation applications. Its combination of clear visual design, robust error handling, and flexible configuration makes it an essential component for modern mobility applications.
The component's architecture supports future enhancements while maintaining current performance and accessibility standards. Its integration with React Native Reanimated and Tailwind CSS ensures smooth animations and consistent styling across different platforms and devices.
For developers integrating this component, careful attention should be paid to the validation requirements and the specific journey structure it supports. The component is designed for journeys with exactly two transfer points, making it ideal for suburban rail networks and similar transportation systems.