ws-dottie
Version:
Your friendly TypeScript companion for Washington State transportation APIs - WSDOT and WSF data with smart caching and React Query integration
850 lines (741 loc) • 32.2 kB
Markdown
# Ferry APIs
This guide covers all ferry-related APIs in WS-Dottie, providing comprehensive access to Washington State Ferries operations, schedules, and real-time data.
> **📚 Documentation Navigation**: [Documentation Index](../../INDEX.md) • [Getting Started](../../getting-started.md) • [API Guide](../api-guide.md)
## 🚢 Overview
WS-Dottie provides access to four ferry APIs that cover all aspects of Washington State Ferries operations:
| API | Description | Key Features | Update Frequency |
|------|-------------|---------------|------------------|
| **WSF Fares** | Fare information, pricing, and terminal combinations | Cost calculation, fare planning, price comparison | Weekly |
| **WSF Schedule** | Ferry schedules, routes, and sailing times | Trip planning, route information, time tables | Daily |
| **WSF Terminals** | Terminal wait times, sailing space, and locations | Wait monitoring, terminal capacity, location data | Frequent (1-5m) |
| **WSF Vessels** | Real-time vessel locations, specifications, and history | Real-time tracking, vessel details, historical data | Real-time (5s) |
## 💰 WSF Fares API
### API Overview
The WSF Fares API provides comprehensive fare information for ferry routes, including detailed pricing for different passenger types, vehicle categories, and route combinations.
### Endpoint Groups
| Endpoint Group | Description | Cache Strategy |
|----------------|-------------|----------------|
| **fare-line-items** | Detailed fare breakdowns by passenger and vehicle type | STATIC |
| **fare-totals** | Total fare calculations for common scenarios | STATIC |
| **terminals** | Terminal information specific to fare system | STATIC |
| **terminal-combo** | Valid terminal combinations for fare calculations | STATIC |
| **valid-date-range** | Valid date range for fare queries | WEEKLY |
| **cache-flush-date** | Timestamp of last fare data refresh | STATIC |
### Key Endpoints
#### Fare Line Items
- **getFareLineItemsByTripDateAndTerminals**: Returns detailed fare breakdown for a specific trip
- **Input**:
- `TripDate` (date) - Date of travel
- `DepartingTerminalID` (integer) - Origin terminal identifier
- `ArrivingTerminalID` (integer) - Destination terminal identifier
- `RoundTrip` (boolean) - Whether this is a round trip
- **Output**: Array of fare line items
- **Key Fields**:
- `FareDescription`: Description of fare type
- `PassengerType`: Passenger category (Adult, Senior, Youth, etc.)
- `VehicleType`: Vehicle category (Standard, Oversize, etc.)
- `FareAmount`: Cost for this fare component
- `Currency`: Currency code (USD)
#### Fare Totals
- **getFareTotalsByTripDateAndTerminals**: Returns total fare for common scenarios
- **Input**: Same parameters as fare line items
- **Output**: Total fare information
- **Key Fields**:
- `PassengerFare`: Total passenger fare
- `VehicleFare`: Total vehicle fare
- `TotalFare`: Combined total fare
- `Currency`: Currency code (USD)
### Common Use Cases
#### Fare Calculator
```javascript
import { useFareLineItemsByTripDateAndTerminals } from 'ws-dottie/wsf-fares';
import { useTerminals } from 'ws-dottie/wsf-schedule';
function FareCalculator() {
const [tripDate, setTripDate] = useState(new Date());
const [departingTerminal, setDepartingTerminal] = useState(3);
const [arrivingTerminal, setArrivingTerminal] = useState(7);
const [isRoundTrip, setIsRoundTrip] = useState(false);
const [passengers, setPassengers] = useState({ adult: 1, senior: 0, youth: 0 });
const [vehicleType, setVehicleType] = useState('standard');
const { data: terminals } = useTerminals();
const { data: fares, isLoading } = useFareLineItemsByTripDateAndTerminals({
TripDate: tripDate,
DepartingTerminalID: departingTerminal,
ArrivingTerminalID: arrivingTerminal,
RoundTrip: isRoundTrip
});
// Calculate total fare based on passenger and vehicle selection
const calculateTotalFare = () => {
if (!fares) return 0;
let total = 0;
// Add passenger fares
total += (fares.find(f => f.PassengerType === 'Adult')?.FareAmount || 0) * passengers.adult;
total += (fares.find(f => f.PassengerType === 'Senior')?.FareAmount || 0) * passengers.senior;
total += (fares.find(f => f.PassengerType === 'Youth')?.FareAmount || 0) * passengers.youth;
// Add vehicle fare
const vehicleFare = fares.find(f =>
f.VehicleType === vehicleType && f.FareDescription.includes('Vehicle')
)?.FareAmount || 0;
total += vehicleFare;
// Double for round trip
return isRoundTrip ? total * 2 : total;
};
const totalFare = calculateTotalFare();
return (
<div>
<h1>Fare Calculator</h1>
<div className="trip-form">
<div className="form-row">
<label>
Date of Travel:
<input
type="date"
value={tripDate.toISOString().split('T')[0]}
onChange={(e) => setTripDate(new Date(e.target.value))}
/>
</label>
</div>
<div className="form-row">
<label>
From:
<select
value={departingTerminal}
onChange={(e) => setDepartingTerminal(Number(e.target.value))}
>
{terminals?.map(terminal => (
<option key={terminal.TerminalID} value={terminal.TerminalID}>
{terminal.TerminalName}
</option>
))}
</select>
</label>
<label>
To:
<select
value={arrivingTerminal}
onChange={(e) => setArrivingTerminal(Number(e.target.value))}
>
{terminals?.map(terminal => (
<option key={terminal.TerminalID} value={terminal.TerminalID}>
{terminal.TerminalName}
</option>
))}
</select>
</label>
</div>
<div className="form-row">
<label>
<input
type="checkbox"
checked={isRoundTrip}
onChange={(e) => setIsRoundTrip(e.target.checked)}
/>
Round Trip
</label>
</div>
<div className="form-row">
<h3>Passengers</h3>
<label>
Adults:
<input
type="number"
min="0"
value={passengers.adult}
onChange={(e) => setPassengers({...passengers, adult: Number(e.target.value)})}
/>
</label>
<label>
Seniors:
<input
type="number"
min="0"
value={passengers.senior}
onChange={(e) => setPassengers({...passengers, senior: Number(e.target.value)})}
/>
</label>
<label>
Youth:
<input
type="number"
min="0"
value={passengers.youth}
onChange={(e) => setPassengers({...passengers, youth: Number(e.target.value)})}
/>
</label>
</div>
<div className="form-row">
<label>
Vehicle Type:
<select
value={vehicleType}
onChange={(e) => setVehicleType(e.target.value)}
>
<option value="standard">Standard Vehicle</option>
<option value="oversize">Oversize Vehicle</option>
<option value="motorcycle">Motorcycle</option>
</select>
</label>
</div>
</div>
<div className="fare-result">
<h2>Total Fare: ${totalFare.toFixed(2)}</h2>
{isLoading && <div>Calculating fare...</div>}
</div>
</div>
);
}
```
## 📅 WSF Schedule API
### API Overview
The WSF Schedule API provides comprehensive schedule information for ferry routes, including sailing times, route details, and service alerts.
### Endpoint Groups
| Endpoint Group | Description | Cache Strategy |
|----------------|-------------|----------------|
| **schedules** | Complete schedule information for all routes | DAILY |
| **routes** | Basic route information between terminal pairs | DAILY |
| **route-details** | Detailed route information with terminal details | DAILY |
| **sailings** | Individual sailing times and vessel assignments | FREQUENT |
| **terminals** | Terminal information specific to schedule system | DAILY |
| **terminal-mates** | Terminal pairings and route connections | DAILY |
| **schedule-alerts** | Service disruptions and schedule changes | FREQUENT |
| **service-disruptions** | Current service disruptions and alternative arrangements | FREQUENT |
| **active-seasons** | Schedule season dates and validity periods | WEEKLY |
| **time-adjustments** | Schedule adjustments and time changes | DAILY |
| **cache-flush-date** | Timestamp of last schedule data refresh | STATIC |
| **valid-date-range** | Valid date range for schedule queries | WEEKLY |
### Key Endpoints
#### Sailings
- **getSailingsBySchedRouteID**: Returns sailing times for a specific route
- **Input**: `SchedRouteID` (integer) - Unique route identifier
- **Output**: Array of sailing information
- **Key Fields**:
- `SailingID`: Unique sailing identifier
- `DepartingTerminalID`: Origin terminal identifier
- `ArrivingTerminalID`: Destination terminal identifier
- `DepartTime`: Scheduled departure time
- `ArriveTime`: Scheduled arrival time
- `VesselID`: Assigned vessel identifier
- `VesselName`: Human-readable vessel name
#### Routes
- **getRoutes**: Returns basic information for all ferry routes
- **Input**: No parameters required
- **Output**: Array of route information
- **Key Fields**:
- `RouteID`: Unique route identifier
- `RouteDescription`: Human-readable route description
- `DepartingTerminalID`: Origin terminal identifier
- `DepartingTerminalName`: Origin terminal name
- `ArrivingTerminalID`: Destination terminal identifier
- `ArrivingTerminalName`: Destination terminal name
- `CrossingTime`: Typical crossing time in minutes
### Common Use Cases
#### Schedule Display
```javascript
import { useSailingsBySchedRouteID, useRoutes } from 'ws-dottie/wsf-schedule';
function FerrySchedule() {
const [selectedRoute, setSelectedRoute] = useState(null);
const { data: routes } = useRoutes();
const { data: sailings, isLoading } = useSailingsBySchedRouteID(
selectedRoute ? { SchedRouteID: selectedRoute } : null
);
return (
<div>
<h1>Ferry Schedule</h1>
<div className="route-selector">
<h2>Select Route</h2>
<select
value={selectedRoute || ''}
onChange={(e) => setSelectedRoute(Number(e.target.value))}
>
<option value="">Choose a route...</option>
{routes?.map(route => (
<option key={route.RouteID} value={route.RouteID}>
{route.RouteDescription}
</option>
))}
</select>
</div>
{selectedRoute && (
<div className="schedule-display">
<h2>Schedule</h2>
{isLoading ? (
<div>Loading schedule...</div>
) : (
<div className="sailings-list">
{sailings?.map(sailing => (
<div key={sailing.SailingID} className="sailing-item">
<div className="sailing-times">
<span className="depart-time">
Departs: {new Date(sailing.DepartTime).toLocaleTimeString()}
</span>
<span className="arrive-time">
Arrives: {new Date(sailing.ArriveTime).toLocaleTimeString()}
</span>
</div>
<div className="sailing-vessel">
Vessel: {sailing.VesselName}
</div>
</div>
))}
</div>
)}
</div>
)}
</div>
);
}
```
## 🏗️ WSF Terminals API
### API Overview
The WSF Terminals API provides comprehensive information about ferry terminals, including locations, amenities, wait times, and sailing space availability.
### Endpoint Groups
| Endpoint Group | Description | Cache Strategy |
|----------------|-------------|----------------|
| **terminal-basics** | Basic terminal information including names and identifiers | STATIC |
| **terminal-locations** | Geographic coordinates and address information for terminals | STATIC |
| **terminal-wait-times** | Current wait times for vehicles and passengers | FREQUENT |
| **terminal-sailing-space** | Real-time sailing space availability for current departures | FREQUENT |
| **terminal-bulletins** | Terminal alerts and service notifications | FREQUENT |
| **terminal-transports** | Public transportation connections to terminals | STATIC |
| **terminal-verbose** | Comprehensive terminal details combining all other data | STATIC |
| **cache-flush-date** | Timestamp of last data refresh for terminal information | STATIC |
### Key Endpoints
#### Terminal Wait Times
- **getTerminalWaitTimes**: Returns current wait times for all terminals
- **Input**: No parameters required
- **Output**: Array of terminal wait time information
- **Key Fields**:
- `TerminalID`: Unique terminal identifier
- `TerminalName`: Human-readable terminal name
- `VehicleWaitTime`: Current wait time for vehicles in minutes
- `PassengerWaitTime`: Current wait time for passengers in minutes
- `MaxVehicleWaitTime`: Maximum vehicle wait time today
- `SailingSpaceAvailable`: Boolean indicating if space is available
- `LastUpdated`: Timestamp of last wait time update
- **getTerminalWaitTimesByTerminalId**: Returns wait time information for a specific terminal
- **Input**: `TerminalID` (integer) - Unique terminal identifier
- **Output**: Single terminal wait time object with all fields above
#### Terminal Locations
- **getTerminalLocations**: Returns geographic information for all terminals
- **Input**: No parameters required
- **Output**: Array of terminal location information
- **Key Fields**:
- `TerminalID`: Unique terminal identifier
- `TerminalName`: Human-readable terminal name
- `Latitude`, `Longitude`: GPS coordinates
- `Address`: Street address
- `City`: City name
- `State`: State abbreviation
- `ZipCode`: Postal code
- `DrivingDirections`: Text directions to terminal
### Common Use Cases
#### Terminal Wait Times Display
```javascript
import { useTerminalWaitTimes } from 'ws-dottie/wsf-terminals';
function TerminalWaitTimes() {
const { data: terminals, isLoading, error } = useTerminalWaitTimes();
if (isLoading) return <div>Loading wait times...</div>;
if (error) return <div>Error loading terminal data: {error.message}</div>;
// Sort terminals by wait time (longest first)
const sortedTerminals = [...(terminals || [])].sort((a, b) =>
(b.VehicleWaitTime || 0) - (a.VehicleWaitTime || 0)
);
return (
<div>
<h1>Terminal Wait Times</h1>
<div className="terminal-grid">
{sortedTerminals.map(terminal => (
<div key={terminal.TerminalID} className="terminal-card">
<h3>{terminal.TerminalName}</h3>
<div className="wait-times">
<div className="wait-time">
<span className="label">Vehicles:</span>
<span className={`time ${terminal.VehicleWaitTime > 30 ? 'long' : 'normal'}`}>
{terminal.VehicleWaitTime || 0} min
</span>
</div>
<div className="wait-time">
<span className="label">Passengers:</span>
<span className={`time ${terminal.PassengerWaitTime > 15 ? 'long' : 'normal'}`}>
{terminal.PassengerWaitTime || 0} min
</span>
</div>
</div>
<div className="space-status">
<span className={`status ${terminal.SailingSpaceAvailable ? 'available' : 'full'}`}>
{terminal.SailingSpaceAvailable ? 'Space Available' : 'Full'}
</span>
</div>
<div className="last-updated">
Last updated: {new Date(terminal.LastUpdated).toLocaleTimeString()}
</div>
</div>
))}
</div>
</div>
);
}
```
#### Terminal Information Display
```javascript
import { useTerminalBasics, useTerminalLocations } from 'ws-dottie/wsf-terminals';
function TerminalInfo() {
const { data: terminals, isLoading: terminalsLoading } = useTerminalBasics();
const { data: locations, isLoading: locationsLoading } = useTerminalLocations();
if (terminalsLoading || locationsLoading) return <div>Loading terminal information...</div>;
// Combine terminal basic info with locations
const terminalsWithDetails = terminals?.map(terminal => {
const location = locations?.find(l => l.TerminalID === terminal.TerminalID);
return {
...terminal,
...location
};
}) || [];
return (
<div>
<h1>Terminal Information</h1>
<div className="terminal-list">
{terminalsWithDetails.map(terminal => (
<div key={terminal.TerminalID} className="terminal-detail-card">
<h3>{terminal.TerminalName}</h3>
<div className="terminal-address">
<p>{terminal.Address}</p>
<p>{terminal.City}, {terminal.State} {terminal.ZipCode}</p>
</div>
<div className="terminal-coords">
<p>Location: {terminal.Latitude.toFixed(4)}, {terminal.Longitude.toFixed(4)}</p>
</div>
<div className="terminal-amenities">
<p>Restrooms: {terminal.Restrooms ? 'Available' : 'Not Available'}</p>
<p>Food Service: {terminal.FoodService ? 'Available' : 'Not Available'}</p>
<p>Parking: {terminal.Parking ? 'Available' : 'Not Available'}</p>
</div>
</div>
))}
</div>
</div>
);
}
```
## 🚢 WSF Vessels API
### API Overview
The WSF Vessels API provides comprehensive information about Washington State Ferries fleet, including real-time vessel tracking, specifications, accommodations, and historical data.
### Endpoint Groups
| Endpoint Group | Description | Cache Strategy |
|----------------|-------------|----------------|
| **vessel-locations** | Real-time vessel GPS positions, speed, heading, and ETA information | REALTIME |
| **vessel-basics** | Basic vessel information including names, classes, and identifiers | STATIC |
| **vessel-accommodations** | Passenger amenities and accessibility features for each vessel | STATIC |
| **vessel-histories** | Historical vessel position and status data | STATIC |
| **vessel-stats** | Performance statistics and operational metrics for vessels | STATIC |
| **vessel-verbose** | Comprehensive vessel details combining all other endpoint data | STATIC |
| **cache-flush-date** | Timestamp of last data refresh for vessel information | STATIC |
### Key Endpoints
#### Vessel Locations
- **getVesselLocations**: Returns real-time position data for all vessels in the fleet
- **Input**: No parameters required
- **Output**: Array of vessel locations with GPS coordinates, speed, heading, terminal assignments, and ETA
- **Key Fields**:
- `VesselID`: Unique vessel identifier
- `VesselName`: Human-readable vessel name
- `Latitude`, `Longitude`: GPS coordinates
- `Speed`: Current speed in knots
- `Heading`: Direction in degrees (0-359)
- `DepartingTerminalID/Name`: Origin terminal information
- `ArrivingTerminalID/Name`: Destination terminal information
- `Eta`: Estimated arrival time at destination
- `AtDock`: Boolean indicating if vessel is currently docked
- **getVesselLocationsByVesselId**: Returns real-time position data for a specific vessel
- **Input**: `VesselID` (integer) - Unique vessel identifier
- **Output**: Single vessel location object with all fields above
#### Vessel Basics
- **getVesselBasics**: Returns basic information for all vessels
- **Input**: No parameters required
- **Output**: Array of vessel basic information
- **Key Fields**:
- `VesselID`: Unique vessel identifier
- `VesselName`: Human-readable vessel name
- `VesselClass`: Vessel class categorization
- `YearBuilt`: Year vessel was constructed
- `Length`: Vessel length in feet
- `Tonage`: Vessel tonnage
#### Vessel Accommodations
- **getVesselAccommodations**: Returns amenity and accessibility information for all vessels
- **Input**: No parameters required
- **Output**: Array of vessel accommodation details
- **Key Fields**:
- `VesselID`: Unique vessel identifier
- `PassengerCapacity`: Maximum passenger capacity
- `VehicleCapacity`: Maximum vehicle capacity
- `ADACompliant`: ADA accessibility compliance status
- `FoodService`: Food service availability
- `Restrooms`: Restroom facilities information
### Common Use Cases
#### Real-time Vessel Tracking
```javascript
import { useVesselLocations } from 'ws-dottie/wsf-vessels';
function VesselMap() {
const { data: vessels, isLoading, error } = useVesselLocations();
if (isLoading) return <div>Loading vessels...</div>;
if (error) return <div>Error loading vessel data: {error.message}</div>;
return (
<div>
<h1>Washington State Ferries</h1>
<div className="vessel-count">
Active Vessels: {vessels?.filter(v => v.InService).length || 0}
</div>
{vessels?.map(vessel => (
<div key={vessel.VesselID} className="vessel-card">
<h3>{vessel.VesselName}</h3>
<div className="vessel-status">
<span className={`status ${vessel.AtDock ? 'docked' : 'underway'}`}>
{vessel.AtDock ? 'At Dock' : 'Underway'}
</span>
<span className="service-status">
{vessel.InService ? 'In Service' : 'Out of Service'}
</span>
</div>
<div className="vessel-location">
<p>Position: {vessel.Latitude.toFixed(4)}, {vessel.Longitude.toFixed(4)}</p>
<p>Speed: {vessel.Speed} knots</p>
<p>Heading: {vessel.Heading}°</p>
</div>
<div className="vessel-route">
<p>From: {vessel.DepartingTerminalName}</p>
<p>To: {vessel.ArrivingTerminalName}</p>
{vessel.Eta && (
<p>ETA: {new Date(vessel.Eta).toLocaleTimeString()}</p>
)}
</div>
</div>
))}
</div>
);
}
```
#### Vessel Information Display
```javascript
import { useVesselBasics, useVesselAccommodations } from 'ws-dottie/wsf-vessels';
function VesselInfo() {
const { data: vessels, isLoading: vesselsLoading } = useVesselBasics();
const { data: accommodations, isLoading: accommodationsLoading } = useVesselAccommodations();
if (vesselsLoading || accommodationsLoading) return <div>Loading vessel information...</div>;
// Combine vessel basic info with accommodations
const vesselsWithDetails = vessels?.map(vessel => {
const vesselAccommodations = accommodations?.find(a => a.VesselID === vessel.VesselID);
return {
...vessel,
...vesselAccommodations
};
}) || [];
return (
<div>
<h1>Fleet Information</h1>
<div className="vessel-grid">
{vesselsWithDetails.map(vessel => (
<div key={vessel.VesselID} className="vessel-detail-card">
<h3>{vessel.VesselName}</h3>
<div className="vessel-specs">
<p>Class: {vessel.VesselClass}</p>
<p>Year Built: {vessel.YearBuilt}</p>
<p>Length: {vessel.Length} feet</p>
<p>Tonnage: {vessel.Tonage}</p>
</div>
<div className="vessel-capacities">
<p>Passengers: {vessel.PassengerCapacity}</p>
<p>Vehicles: {vessel.VehicleCapacity}</p>
</div>
<div className="vessel-features">
<p>ADA Compliant: {vessel.ADACompliant ? 'Yes' : 'No'}</p>
<p>Food Service: {vessel.FoodService ? 'Available' : 'Not Available'}</p>
</div>
</div>
))}
</div>
</div>
);
}
```
## 🔗 API Relationships
Ferry APIs work together to provide comprehensive ferry information:
### Vessel + Terminal Integration
```javascript
import { useVesselLocations } from 'ws-dottie/wsf-vessels';
import { useTerminalWaitTimes } from 'ws-dottie/wsf-terminals';
function FerryDashboard() {
const { data: vessels } = useVesselLocations();
const { data: waitTimes } = useTerminalWaitTimes();
// Combine vessel locations with terminal wait times
const vesselsWithWaitTimes = vessels?.map(vessel => {
const terminalWaitTime = waitTimes?.find(t => t.TerminalID === vessel.ArrivingTerminalID);
return {
...vessel,
destinationWaitTime: terminalWaitTime?.VehicleWaitTime || 0
};
}) || [];
return (
<div>
<h1>Ferry Dashboard</h1>
<div className="vessel-status-grid">
{vesselsWithWaitTimes.map(vessel => (
<div key={vessel.VesselID} className="vessel-status-card">
<h3>{vessel.VesselName}</h3>
<div className="vessel-position">
<p>Position: {vessel.Latitude.toFixed(4)}, {vessel.Longitude.toFixed(4)}</p>
<p>Speed: {vessel.Speed} knots</p>
<p>Heading: {vessel.Heading}°</p>
</div>
<div className="vessel-route">
<p>From: {vessel.DepartingTerminalName}</p>
<p>To: {vessel.ArrivingTerminalName}</p>
{vessel.Eta && (
<p>ETA: {new Date(vessel.Eta).toLocaleTimeString()}</p>
)}
</div>
<div className="terminal-wait">
<p>Terminal Wait: {vessel.destinationWaitTime} minutes</p>
</div>
</div>
))}
</div>
</div>
);
}
```
### Schedule + Fare Integration
```javascript
import { useSailingsBySchedRouteID, useRoutes } from 'ws-dottie/wsf-schedule';
import { useFareLineItemsByTripDateAndTerminals } from 'ws-dottie/wsf-fares';
function TripPlanner() {
const [selectedRoute, setSelectedRoute] = useState(null);
const [tripDate, setTripDate] = useState(new Date());
const [passengers, setPassengers] = useState({ adult: 1, senior: 0 });
// Get route information
const { data: routes } = useRoutes();
const selectedRouteInfo = routes?.find(r => r.RouteID === selectedRoute);
// Get sailings for selected route
const { data: sailings } = useSailingsBySchedRouteID(
selectedRoute ? { SchedRouteID: selectedRoute } : null
);
// Get fare information for selected route
const { data: fares } = useFareLineItemsByTripDateAndTerminals(
selectedRouteInfo ? {
TripDate: tripDate,
DepartingTerminalID: selectedRouteInfo.DepartingTerminalID,
ArrivingTerminalID: selectedRouteInfo.ArrivingTerminalID,
RoundTrip: false
} : null
);
// Calculate fare for selected passenger count
const calculateFare = () => {
if (!fares) return 0;
const adultFare = fares.find(f => f.PassengerType === 'Adult')?.FareAmount || 0;
const seniorFare = fares.find(f => f.PassengerType === 'Senior')?.FareAmount || 0;
return (adultFare * passengers.adult) + (seniorFare * passengers.senior);
};
return (
<div>
<h1>Trip Planner</h1>
<div className="trip-planner">
<div className="route-selection">
<h2>Select Route</h2>
<select
value={selectedRoute || ''}
onChange={(e) => setSelectedRoute(Number(e.target.value))}
>
<option value="">Choose a route...</option>
{routes?.map(route => (
<option key={route.RouteID} value={route.RouteID}>
{route.RouteDescription}
</option>
))}
</select>
</div>
<div className="trip-details">
<div className="date-selection">
<label>
Date:
<input
type="date"
value={tripDate.toISOString().split('T')[0]}
onChange={(e) => setTripDate(new Date(e.target.value))}
/>
</label>
</div>
<div className="passenger-selection">
<h3>Passengers</h3>
<label>
Adults:
<input
type="number"
min="0"
value={passengers.adult}
onChange={(e) => setPassengers({...passengers, adult: Number(e.target.value)})}
/>
</label>
<label>
Seniors:
<input
type="number"
min="0"
value={passengers.senior}
onChange={(e) => setPassengers({...passengers, senior: Number(e.target.value)})}
/>
</label>
</div>
</div>
{selectedRouteInfo && (
<div className="route-info">
<h2>Route Information</h2>
<p>From: {selectedRouteInfo.DepartingTerminalName}</p>
<p>To: {selectedRouteInfo.ArrivingTerminalName}</p>
<p>Crossing Time: {selectedRouteInfo.CrossingTime} minutes</p>
<p>Fare: ${calculateFare().toFixed(2)}</p>
</div>
)}
{sailings && (
<div className="schedule-display">
<h2>Available Sailings</h2>
<div className="sailings-list">
{sailings.map(sailing => (
<div key={sailing.SailingID} className="sailing-option">
<div className="sailing-times">
<span>Departs: {new Date(sailing.DepartTime).toLocaleTimeString()}</span>
<span>Arrives: {new Date(sailing.ArriveTime).toLocaleTimeString()}</span>
</div>
<div className="sailing-vessel">
Vessel: {sailing.VesselName}
</div>
</div>
))}
</div>
</div>
)}
</div>
</div>
);
}
```
## 📊 Performance Considerations
### Caching Strategies
- **Vessel Locations**: `REALTIME_UPDATES` (5-second refresh)
- **Terminal Wait Times**: `MINUTE_UPDATES` (1-5 minute refresh)
- **Schedules**: `DAILY_UPDATES` (daily refresh)
- **Fares**: `STATIC` (daily refresh)
- **Vessel/Terminal Information**: `STATIC` (daily refresh)
### Optimization Tips
- **Vessel Tracking**: Use selective updates for vessels in view
- **Schedule Data**: Cache schedule data for specific routes
- **Fare Calculations**: Pre-calculate common fare combinations
- **Terminal Information**: Store terminal details locally to reduce API calls
## 🔗 Detailed Documentation
For detailed endpoint documentation, interactive examples, and schema definitions, see our generated documentation:
- **[WSF Fares HTML](../../../redoc/wsf-fares.html)** - Interactive fare documentation
- **[WSF Schedule HTML](../../../redoc/wsf-schedule.html)** - Interactive schedule documentation
- **[WSF Terminals HTML](../../../redoc/wsf-terminals.html)** - Interactive terminal documentation
- **[WSF Vessels HTML](../../../redoc/wsf-vessels.html)** - Interactive vessel documentation
## 📚 Next Steps
- **[TanStack Query Guide](../advanced/tanstack-query.md)** - React patterns with TanStack Query
- **[Fetching Data Guide](../advanced/fetching-data.md)** - Server-side and client-side usage patterns
- **[Performance Guide](../advanced/performance-guide.md)** - Performance optimization strategies
- **[Error Handling Guide](../advanced/error-handling.md)** - Error recovery patterns