UNPKG

ws-dottie

Version:

Your friendly TypeScript companion for Washington State transportation APIs - WSDOT and WSF data with smart caching and React Query integration

865 lines (750 loc) 33.9 kB
# Infrastructure APIs This guide covers all infrastructure-related APIs in WS-Dottie, providing comprehensive access to Washington State transportation infrastructure information. > **📚 Documentation Navigation**: [Documentation Index](../../INDEX.md) • [Getting Started](../../getting-started.md) • [API Guide](../api-guide.md) ## 🏗️ Overview WS-Dottie provides access to three infrastructure APIs that cover physical transportation infrastructure throughout Washington State: | API | Description | Key Features | Update Frequency | |------|-------------|---------------|------------------| | **WSDOT Border Crossings** | Wait times and conditions at border crossings | Border planning, wait time monitoring, crossing status | Frequent (5-15m) | | **WSDOT Bridge Clearances** | Height restrictions for bridges and overpasses | Clearance data, route planning for tall vehicles | Daily | | **WSDOT Commercial Vehicle Restrictions** | Weight limits and vehicle restrictions | Truck routing, restriction information, compliance data | Weekly | ## 🛃 WSDOT Border Crossings API ### API Overview The WSDOT Border Crossings API provides real-time information about border crossing wait times and conditions at Washington State crossings into Canada, including lane status and crossing type information. ### Endpoint Groups | Endpoint Group | Description | Cache Strategy | |----------------|-------------|----------------| | **border-crossing-data** | Real-time wait times for US-Canada border crossings | FREQUENT | ### Key Endpoints #### Border Crossings - **getBorderCrossings**: Returns current wait times for all border crossings - **Input**: No parameters required - **Output**: Array of border crossing information - **Key Fields**: - `BorderCrossingLocation`: Roadway location information (route, milepost, coordinates, direction), or null - `Direction`: Traffic direction (N, S, B, NB, SB), or null - `RoadName`: Highway designation (e.g., '005' for I-5), or null - `Description`: Human-readable location description, or null - `Latitude`: Latitude in decimal degrees - `Longitude`: Longitude in decimal degrees - `MilePost`: Milepost marker along the highway - `CrossingName`: Display code for the border crossing or lane (e.g., I5, I5Nexus, SR543TrucksFast), or null - `Time`: UTC datetime when the wait time observation was recorded (Date object) - `WaitTime`: Current estimated wait time in minutes (-1 if unavailable) ### Common Use Cases #### Border Crossing Monitor ```javascript import { useBorderCrossings } from 'ws-dottie/wsdot-border-crossings'; function BorderCrossingMonitor() { const { data: crossings, isLoading, error } = useBorderCrossings({ fetchMode: 'native', validate: false, }); // Group crossings by CrossingName prefix // Note: The API doesn't provide CrossingType, so we'll filter by CrossingName patterns const passengerCrossings = crossings?.filter(c => c.CrossingName && !c.CrossingName.includes('Truck') ); const commercialCrossings = crossings?.filter(c => c.CrossingName && c.CrossingName.includes('Truck') ); const nexusCrossings = crossings?.filter(c => c.CrossingName && c.CrossingName.includes('Nexus') ); // Find optimal crossing for each type (lowest wait time) const findOptimalCrossing = (crossings) => { if (!crossings || crossings.length === 0) return null; return crossings.reduce((best, current) => { // Skip crossings with invalid wait times if (current.WaitTime < 0) return best; if (best.WaitTime < 0) return current; return (best.WaitTime < current.WaitTime) ? best : current; }, crossings[0]); }; const optimalPassenger = findOptimalCrossing(passengerCrossings); const optimalCommercial = findOptimalCrossing(commercialCrossings); const optimalNexus = findOptimalCrossing(nexusCrossings); return ( <div> <h1>Washington Border Crossings</h1> {isLoading && <div>Loading border crossing data...</div>} {error && <div>Error loading border crossing data: {error.message}</div>} <div className="crossing-summary"> <div className="crossing-type"> <h2>Passenger Crossings</h2> {optimalPassenger ? ( <p>Optimal: {optimalPassenger.CrossingName} ({optimalPassenger.WaitTime >= 0 ? `${optimalPassenger.WaitTime} min` : 'N/A'})</p> ) : ( <p>No passenger crossings available</p> )} </div> <div className="crossing-type"> <h2>Commercial Crossings</h2> {optimalCommercial ? ( <p>Optimal: {optimalCommercial.CrossingName} ({optimalCommercial.WaitTime >= 0 ? `${optimalCommercial.WaitTime} min` : 'N/A'})</p> ) : ( <p>No commercial crossings available</p> )} </div> <div className="crossing-type"> <h2>NEXUS Crossings</h2> {optimalNexus ? ( <p>Optimal: {optimalNexus.CrossingName} ({optimalNexus.WaitTime >= 0 ? `${optimalNexus.WaitTime} min` : 'N/A'})</p> ) : ( <p>No NEXUS crossings available</p> )} </div> </div> <div className="crossing-sections"> <div className="crossing-section"> <h2>Passenger Crossings</h2> {passengerCrossings?.map((crossing, index) => ( <div key={crossing.CrossingName || index} className={`crossing-item ${crossing === optimalPassenger ? 'optimal' : ''}`}> <h3>{crossing.CrossingName || 'Unknown Crossing'}</h3> {crossing.BorderCrossingLocation?.Direction && ( <p>Direction: {crossing.BorderCrossingLocation.Direction}</p> )} {crossing.BorderCrossingLocation?.RoadName && ( <p>Route: {crossing.BorderCrossingLocation.RoadName}</p> )} <p>Current Wait: {crossing.WaitTime >= 0 ? `${crossing.WaitTime} minutes` : 'Not available'}</p> {/* Time is already a Date object (converted from .NET format) */} <p>Last Updated: {crossing.Time.toLocaleString()}</p> </div> ))} </div> <div className="crossing-section"> <h2>Commercial Crossings</h2> {commercialCrossings?.map((crossing, index) => ( <div key={crossing.CrossingName || index} className={`crossing-item ${crossing === optimalCommercial ? 'optimal' : ''}`}> <h3>{crossing.CrossingName || 'Unknown Crossing'}</h3> {crossing.BorderCrossingLocation?.Direction && ( <p>Direction: {crossing.BorderCrossingLocation.Direction}</p> )} {crossing.BorderCrossingLocation?.RoadName && ( <p>Route: {crossing.BorderCrossingLocation.RoadName}</p> )} <p>Current Wait: {crossing.WaitTime >= 0 ? `${crossing.WaitTime} minutes` : 'Not available'}</p> {/* Time is already a Date object (converted from .NET format) */} <p>Last Updated: {crossing.Time.toLocaleString()}</p> </div> ))} </div> {nexusCrossings && nexusCrossings.length > 0 && ( <div className="crossing-section"> <h2>NEXUS Crossings</h2> {nexusCrossings.map((crossing, index) => ( <div key={crossing.CrossingName || index} className={`crossing-item ${crossing === optimalNexus ? 'optimal' : ''}`}> <h3>{crossing.CrossingName || 'Unknown Crossing'}</h3> {crossing.BorderCrossingLocation?.Direction && ( <p>Direction: {crossing.BorderCrossingLocation.Direction}</p> )} <p>Current Wait: {crossing.WaitTime >= 0 ? `${crossing.WaitTime} minutes` : 'Not available'}</p> <p>Last Updated: {crossing.Time.toLocaleString()}</p> </div> ))} </div> )} </div> </div> ); } ``` #### Border Crossing Route Planner ```javascript import { useBorderCrossings } from 'ws-dottie/wsdot-border-crossings'; function BorderCrossingRoutePlanner() { const { data: crossings, isLoading, error } = useBorderCrossings({ fetchMode: 'native', validate: false, }); const [selectedCrossing, setSelectedCrossing] = useState(null); const [vehicleType, setVehicleType] = useState('Passenger'); // Filter crossings by vehicle type based on CrossingName patterns // Note: The API doesn't provide CrossingType, so we'll filter by CrossingName const filteredCrossings = crossings?.filter(c => { if (!c.CrossingName) return false; if (vehicleType === 'Passenger') return !c.CrossingName.includes('Truck'); if (vehicleType === 'Commercial') return c.CrossingName.includes('Truck'); if (vehicleType === 'NEXUS') return c.CrossingName.includes('Nexus'); return true; }) || []; // Find optimal crossing based on wait times (excluding invalid wait times) const optimalCrossing = filteredCrossings.length > 0 ? filteredCrossings.reduce((best, current) => { if (current.WaitTime < 0) return best; if (best.WaitTime < 0) return current; return (best.WaitTime < current.WaitTime) ? best : current; }, filteredCrossings[0]) : null; // Calculate estimated crossing time including wait const calculateTotalTime = (crossing, baseTime = 30) => { if (crossing.WaitTime < 0) return baseTime; // Unknown wait time return baseTime + crossing.WaitTime; }; return ( <div> <h1>Border Crossing Route Planner</h1> {isLoading && <div>Loading border crossing data...</div>} {error && <div>Error loading border crossing data: {error.message}</div>} <div className="crossing-controls"> <div> <label>Vehicle Type: <select value={vehicleType} onChange={e => setVehicleType(e.target.value)} > <option value="Passenger">Passenger</option> <option value="Commercial">Commercial</option> <option value="NEXUS">NEXUS</option> </select> </label> </div> </div> <div className="crossing-recommendation"> <h2>Recommended Crossing</h2> {optimalCrossing ? ( <div className="optimal-crossing"> <h3>{optimalCrossing.CrossingName || 'Unknown Crossing'}</h3> {optimalCrossing.BorderCrossingLocation?.Direction && ( <p>Direction: {optimalCrossing.BorderCrossingLocation.Direction}</p> )} {optimalCrossing.BorderCrossingLocation?.RoadName && ( <p>Route: {optimalCrossing.BorderCrossingLocation.RoadName}</p> )} <p>Current Wait: {optimalCrossing.WaitTime >= 0 ? `${optimalCrossing.WaitTime} minutes` : 'Not available'}</p> <p>Estimated Total Time: {calculateTotalTime(optimalCrossing)} minutes</p> <p>Last Updated: {optimalCrossing.Time.toLocaleString()}</p> </div> ) : ( <p>No crossings available for selected vehicle type</p> )} </div> <div className="crossing-list"> <h2>All Crossings</h2> {filteredCrossings.map((crossing, index) => ( <div key={crossing.CrossingName || index} className={`crossing-option ${selectedCrossing?.CrossingName === crossing.CrossingName ? 'selected' : ''}`} onClick={() => setSelectedCrossing(crossing)} > <h3>{crossing.CrossingName || 'Unknown Crossing'}</h3> {crossing.BorderCrossingLocation?.Direction && ( <p>Direction: {crossing.BorderCrossingLocation.Direction}</p> )} <p>Current Wait: {crossing.WaitTime >= 0 ? `${crossing.WaitTime} minutes` : 'Not available'}</p> <p>Estimated Total Time: {calculateTotalTime(crossing)} minutes</p> <p>Last Updated: {crossing.Time.toLocaleString()}</p> </div> ))} </div> </div> ); } ``` ## 🌉 WSDOT Bridge Clearances API ### API Overview The WSDOT Bridge Clearances API provides comprehensive information about bridge height restrictions throughout Washington State, including vertical clearance measurements, location data, and route information. ### Endpoint Groups | Endpoint Group | Description | Cache Strategy | |----------------|-------------|----------------| | **bridge-clearances** | Vertical clearance measurements for all state bridges | STATIC | ### Key Endpoints #### Bridge Clearances - **getBridgeClearances**: Returns clearance data for all bridges in Washington State - **Input**: No parameters required - **Output**: Array of bridge clearance information - **Key Fields**: - `BridgeDataGISID`: Unique bridge identifier - `StructureName`: Human-readable bridge name - `Route`: State route number (e.g., "005" for I-5) - `Landmark`: Location description or landmark - `Latitude`, `Longitude`: GPS coordinates - `VerticalClearance`: Maximum clearance height in feet - `LocationDescription`: Detailed location description - `StructureType`: Bridge or overpass type - **getBridgeClearancesByRoute**: Returns clearance data for bridges on a specific route - **Input**: `Route` (string) - State route number (e.g., "005" for I-5) - **Output**: Array of bridge clearance information for specified route - **Key Fields**: Same as getBridgeClearances, filtered by route ### Common Use Cases #### Route Planning for Tall Vehicles ```javascript import { useBridgeClearances } from 'ws-dottie/wsdot-bridge-clearances'; function TallVehicleRoutePlanner() { const [vehicleHeight, setVehicleHeight] = useState(12); // feet const [selectedRoute, setSelectedRoute] = useState('005'); // I-5 const { data: clearances, isLoading, error } = useBridgeClearances(); // Filter clearances for selected route const routeClearances = clearances?.filter(clearance => clearance.Route === selectedRoute ) || []; // Check if vehicle can safely traverse route const canTraverseRoute = (clearances, height) => { return clearances?.every(clearance => clearance.VerticalClearance > height); }; const routeSafe = canTraverseRoute(routeClearances, vehicleHeight); // Find problematic bridges if any const problemBridges = routeClearances?.filter(clearance => clearance.VerticalClearance <= vehicleHeight ) || []; return ( <div> <h1>Bridge Clearance Route Planner</h1> {isLoading && <div>Loading bridge data...</div>} {error && <div>Error loading bridge data: {error.message}</div>} <div className="vehicle-input"> <label>Vehicle Height (feet): <input type="number" value={vehicleHeight} onChange={e => setVehicleHeight(Number(e.target.value))} /> </label> </div> <div className="route-selection"> <label>Route: <select value={selectedRoute} onChange={e => setSelectedRoute(e.target.value)}> <option value="005">I-5</option> <option value="090">I-90</option> <option value="405">I-405</option> <option value="005">SR-5</option> </select> </label> </div> <div className="route-status"> <h2>Route {selectedRoute} Status</h2> <p>Vehicle Height: {vehicleHeight} feet</p> <p>Route {routeSafe ? 'Safe' : 'Not Safe'} for this vehicle</p> {problemBridges.length > 0 && ( <div className="problem-bridges"> <h3>Problematic Bridges:</h3> {problemBridges.map(bridge => ( <div key={bridge.BridgeDataGISID} className="bridge-issue"> <h4>{bridge.StructureName}</h4> <p>Location: {bridge.Landmark}</p> <p>Clearance: {bridge.VerticalClearance} feet</p> <p>Issue: {vehicleHeight - bridge.VerticalClearance} feet too tall</p> </div> ))} </div> )} {routeClearances?.map(clearance => ( <div key={clearance.BridgeDataGISID} className="clearance-item"> <h3>{clearance.StructureName}</h3> <p>Location: {clearance.Landmark}</p> <p>Vertical Clearance: {clearance.VerticalClearance} feet</p> <p>Status: {clearance.VerticalClearance > vehicleHeight ? '✅ Safe' : '⚠️ Too Low'}</p> </div> ))} </div> </div> ); } ``` #### Bridge Clearance Map ```javascript import { useBridgeClearances } from 'ws-dottie/wsdot-bridge-clearances'; function BridgeClearanceMap() { const { data: clearances, isLoading, error } = useBridgeClearances(); // Process data for map visualization const bridgeData = clearances?.map(clearance => ({ id: clearance.BridgeDataGISID, name: clearance.StructureName, location: [clearance.Latitude, clearance.Longitude], clearance: clearance.VerticalClearance, route: clearance.Route })) || []; // Group bridges by clearance height for visualization const clearanceGroups = bridgeData.reduce((acc, bridge) => { const height = bridge.clearance; if (height < 14) acc.low = [...(acc.low || []), bridge]; else if (height < 16) acc.medium = [...(acc.medium || []), bridge]; else acc.high = [...(acc.high || []), bridge]; return acc; }, {}); return ( <div> <h1>Washington Bridge Clearances</h1> {isLoading && <div>Loading bridge data...</div>} {error && <div>Error loading bridge data: {error.message}</div>} <div className="clearance-summary"> <div className="clearance-group"> <h3>Low Clearance (&lt; 14ft)</h3> <p>{clearanceGroups.low?.length || 0} bridges</p> </div> <div className="clearance-group"> <h3>Medium Clearance (14-16ft)</h3> <p>{clearanceGroups.medium?.length || 0} bridges</p> </div> <div className="clearance-group"> <h3>High Clearance (&gt; 16ft)</h3> <p>{clearanceGroups.high?.length || 0} bridges</p> </div> </div> <div className="bridge-map"> {/* Render map with bridge clearance indicators */} {bridgeData.map(bridge => ( <div key={bridge.id} className="bridge-marker"> <h3>{bridge.name}</h3> <p>Route: {bridge.route}</p> <p>Clearance: {bridge.clearance} feet</p> </div> ))} </div> </div> ); } ``` ## 🚚 WSDOT Commercial Vehicle Restrictions API ### API Overview The WSDOT Commercial Vehicle Restrictions API provides comprehensive information about weight limits, vehicle restrictions, and regulatory requirements for commercial vehicles throughout Washington State. ### Endpoint Groups | Endpoint Group | Description | Cache Strategy | |----------------|-------------|----------------| | **cv-restriction-data** | Weight limits and vehicle restrictions for state highways | STATIC | | **cv-restriction-data-with-id** | Specific restriction data by restriction ID | STATIC | ### Key Endpoints #### Commercial Vehicle Restrictions - **getCommercialVehicleRestrictions**: Returns all commercial vehicle restrictions in Washington State - **Input**: No parameters required - **Output**: Array of commercial vehicle restriction information - **Key Fields**: - `CommercialVehicleRestrictionID`: Unique restriction identifier - `LocationDescription`: Description of restriction location - `RouteName`: Highway or route name - `StateRoute`: State route number - `MaxWeight`: Maximum weight limit in pounds - `RestrictedVehicleTypes`: Array of restricted vehicle types - `RestrictionReason`: Explanation of restriction - `StartDate`, `EndDate`: Validity dates for restriction - `Latitude`, `Longitude`: GPS coordinates - **getCommercialVehicleRestrictionsById**: Returns specific restriction by ID - **Input**: `CommercialVehicleRestrictionID` (integer) - Unique restriction identifier - **Output**: Single commercial vehicle restriction object with all fields above ### Common Use Cases #### Commercial Vehicle Route Planner ```javascript import { useCommercialVehicleRestrictions } from 'ws-dottie/wsdot-commercial-vehicle-restrictions'; function CommercialVehicleRoutePlanner() { const [vehicleWeight, setVehicleWeight] = useState(80000); // pounds const [vehicleType, setVehicleType] = useState('TRUCK'); const [selectedRoute, setSelectedRoute] = useState('I-5'); const { data: restrictions, isLoading, error } = useCommercialVehicleRestrictions(); // Filter restrictions for selected route const routeRestrictions = restrictions?.filter(r => r.RouteName.includes(selectedRoute) || r.StateRoute.includes(selectedRoute.replace('I-', '')) ) || []; // Check if vehicle can traverse route const canTraverseRoute = (restrictions, weight, type) => { return routeRestrictions?.every(restriction => { const weightOk = !restriction.MaxWeight || weight <= restriction.MaxWeight; const typeOk = !restriction.RestrictedVehicleTypes || !restriction.RestrictedVehicleTypes.includes(type); return weightOk && typeOk; }); }; const routeSafe = canTraverseRoute(routeRestrictions, vehicleWeight, vehicleType); // Find problematic restrictions if any const problemRestrictions = routeRestrictions?.filter(restriction => { const weightIssue = restriction.MaxWeight && vehicleWeight > restriction.MaxWeight; const typeIssue = restriction.RestrictedVehicleTypes && restriction.RestrictedVehicleTypes.includes(vehicleType); return weightIssue || typeIssue; }) || []; return ( <div> <h1>Commercial Vehicle Route Planner</h1> {isLoading && <div>Loading restriction data...</div>} {error && <div>Error loading restriction data: {error.message}</div>} <div className="vehicle-input"> <div> <label>Vehicle Weight (lbs): <input type="number" value={vehicleWeight} onChange={e => setVehicleWeight(Number(e.target.value))} /> </label> </div> <div> <label>Vehicle Type: <select value={vehicleType} onChange={e => setVehicleType(e.target.value)}> <option value="TRUCK">Truck</option> <option value="BUS">Bus</option> <option value="COMBINATION">Combination Vehicle</option> </select> </label> </div> <div> <label>Route: <select value={selectedRoute} onChange={e => setSelectedRoute(e.target.value)}> <option value="I-5">I-5</option> <option value="I-90">I-90</option> <option value="I-405">I-405</option> <option value="SR-5">SR-5</option> </select> </label> </div> </div> <div className="route-status"> <h2>Route {selectedRoute} Status</h2> <p>Vehicle Weight: {vehicleWeight.toLocaleString()} lbs</p> <p>Vehicle Type: {vehicleType}</p> <p>Route {routeSafe ? 'Safe' : 'Not Safe'} for this vehicle</p> {problemRestrictions.length > 0 && ( <div className="problem-restrictions"> <h3>Restriction Issues:</h3> {problemRestrictions.map(restriction => ( <div key={restriction.CommercialVehicleRestrictionID} className="restriction-issue"> <h4>{restriction.LocationDescription}</h4> <p>Route: {restriction.RouteName}</p> {restriction.MaxWeight && ( <p>Weight Limit: {restriction.MaxWeight.toLocaleString()} lbs (exceeded by {(vehicleWeight - restriction.MaxWeight).toLocaleString()} lbs)</p> )} {restriction.RestrictedVehicleTypes && ( <p>Vehicle Type Restriction: {vehicleType} not allowed</p> )} <p>Reason: {restriction.RestrictionReason}</p> </div> ))} </div> )} </div> </div> ); } ``` #### Vehicle Compliance Checker ```javascript import { useCommercialVehicleRestrictions } from 'ws-dottie/wsdot-commercial-vehicle-restrictions'; function VehicleComplianceChecker() { const [vehicleSpecs, setVehicleSpecs] = useState({ weight: 80000, type: 'TRUCK', height: 13.5, width: 8.5, length: 65 }); const { data: restrictions, isLoading, error } = useCommercialVehicleRestrictions(); // Check compliance across all restrictions const complianceIssues = restrictions?.map(restriction => { const issues = []; if (restriction.MaxWeight && vehicleSpecs.weight > restriction.MaxWeight) { issues.push(`Weight exceeds limit by ${vehicleSpecs.weight - restriction.MaxWeight} lbs`); } if (restriction.RestrictedVehicleTypes && restriction.RestrictedVehicleTypes.includes(vehicleSpecs.type)) { issues.push(`Vehicle type ${vehicleSpecs.type} not allowed`); } return { ...restriction, issues, isCompliant: issues.length === 0 }; }).filter(r => !r.isCompliant) || []; return ( <div> <h1>Vehicle Compliance Checker</h1> {isLoading && <div>Loading restriction data...</div>} {error && <div>Error loading restriction data: {error.message}</div>} <div className="vehicle-specs"> <h2>Vehicle Specifications</h2> <div className="spec-inputs"> <div> <label>Weight (lbs): <input type="number" value={vehicleSpecs.weight} onChange={e => setVehicleSpecs({...vehicleSpecs, weight: Number(e.target.value)})} /> </label> </div> <div> <label>Vehicle Type: <select value={vehicleSpecs.type} onChange={e => setVehicleSpecs({...vehicleSpecs, type: e.target.value})} > <option value="TRUCK">Truck</option> <option value="BUS">Bus</option> <option value="COMBINATION">Combination Vehicle</option> </select> </label> </div> <div> <label>Height (ft): <input type="number" value={vehicleSpecs.height} onChange={e => setVehicleSpecs({...vehicleSpecs, height: Number(e.target.value)})} /> </label> </div> <div> <label>Width (ft): <input type="number" value={vehicleSpecs.width} onChange={e => setVehicleSpecs({...vehicleSpecs, width: Number(e.target.value)})} /> </label> </div> <div> <label>Length (ft): <input type="number" value={vehicleSpecs.length} onChange={e => setVehicleSpecs({...vehicleSpecs, length: Number(e.target.value)})} /> </label> </div> </div> </div> <div className="compliance-results"> <h2>Compliance Issues ({complianceIssues.length || 0})</h2> {complianceIssues.map(issue => ( <div key={issue.CommercialVehicleRestrictionID} className="compliance-issue"> <h3>{issue.LocationDescription}</h3> <p>Route: {issue.RouteName}</p> <ul> {issue.issues.map((problem, index) => ( <li key={index}>{problem}</li> ))} </ul> </div> ))} {complianceIssues.length === 0 && ( <div className="compliant"> <p>✅ Vehicle is compliant with all restrictions</p> </div> )} </div> </div> ); } ``` ## 🔗 API Relationships Infrastructure APIs work together to provide comprehensive transportation infrastructure information: ### Bridge Clearances + Commercial Vehicle Restrictions Integration ```javascript import { useBridgeClearances } from 'ws-dottie/wsdot-bridge-clearances'; import { useCommercialVehicleRestrictions } from 'ws-dottie/wsdot-commercial-vehicle-restrictions'; function ComprehensiveRoutePlanner() { const { data: clearances } = useBridgeClearances(); const { data: restrictions } = useCommercialVehicleRestrictions(); const [vehicleSpecs, setVehicleSpecs] = useState({ weight: 80000, height: 13.5, type: 'TRUCK' }); // Check route compatibility with both clearances and restrictions const checkRouteCompatibility = (route) => { const routeClearances = clearances?.filter(c => c.Route === route); const routeRestrictions = restrictions?.filter(r => r.RouteName.includes(route) || r.StateRoute.includes(route.replace('I-', '')) ); const clearanceIssues = routeClearances?.filter(c => c.VerticalClearance < vehicleSpecs.height ); const restrictionIssues = routeRestrictions?.filter(r => (r.MaxWeight && vehicleSpecs.weight > r.MaxWeight) || (r.RestrictedVehicleTypes && r.RestrictedVehicleTypes.includes(vehicleSpecs.type)) ); return { route, clearanceIssues, restrictionIssues, isCompatible: clearanceIssues.length === 0 && restrictionIssues.length === 0 }; }; const routeCompatibility = ['I-5', 'I-90', 'I-405'].map(checkRouteCompatibility); return ( <div> <h1>Comprehensive Route Planner</h1> <div className="vehicle-specs"> <h2>Vehicle Specifications</h2> <div> <label>Weight (lbs): <input type="number" value={vehicleSpecs.weight} onChange={e => setVehicleSpecs({...vehicleSpecs, weight: Number(e.target.value)})} /> </label> </div> <div> <label>Height (ft): <input type="number" value={vehicleSpecs.height} onChange={e => setVehicleSpecs({...vehicleSpecs, height: Number(e.target.value)})} /> </label> </div> <div> <label>Vehicle Type: <select value={vehicleSpecs.type} onChange={e => setVehicleSpecs({...vehicleSpecs, type: e.target.value})} > <option value="TRUCK">Truck</option> <option value="BUS">Bus</option> <option value="COMBINATION">Combination Vehicle</option> </select> </label> </div> </div> <div className="route-analysis"> <h2>Route Analysis</h2> {routeCompatibility.map(({ route, isCompatible, clearanceIssues, restrictionIssues }) => ( <div key={route} className={`route-analysis ${isCompatible ? 'compatible' : 'incompatible'}`}> <h3>Route {route}</h3> <p>Status: {isCompatible ? '✅ Compatible' : '⚠️ Issues Found'}</p> {clearanceIssues.length > 0 && ( <div className="issues"> <h4>Clearance Issues:</h4> {clearanceIssues.map(issue => ( <p key={issue.BridgeDataGISID}> {issue.StructureName}: {issue.VerticalClearance}ft (need {vehicleSpecs.height}ft) </p> ))} </div> )} {restrictionIssues.length > 0 && ( <div className="issues"> <h4>Restriction Issues:</h4> {restrictionIssues.map(issue => ( <p key={issue.CommercialVehicleRestrictionID}> {issue.LocationDescription}: {issue.RestrictedVehicleTypes || 'Weight limit exceeded'} </p> ))} </div> )} </div> ))} </div> </div> ); } ``` ## 📊 Performance Considerations ### Caching Strategies - **Border Crossings**: `MINUTE_UPDATES` (5-15 minute refresh) - **Bridge Clearances**: `DAILY_UPDATES` (daily refresh) - **Commercial Vehicle Restrictions**: `STATIC` (daily refresh) ### Optimization Tips - **Route Planning**: Pre-filter routes based on vehicle specifications - **Weight Calculations**: Cache common vehicle type calculations - **Border Crossings**: Use historical data to predict optimal crossing times - **Combined Analysis**: Store frequently accessed route combinations locally ## 🔗 Detailed Documentation For detailed endpoint documentation, interactive examples, and schema definitions, see our generated documentation: - **[WSDOT Border Crossings HTML](../../../redoc/wsdot-border-crossings.html)** - Interactive border crossing documentation - **[WSDOT Bridge Clearances HTML](../../../redoc/wsdot-bridge-clearances.html)** - Interactive bridge documentation - **[WSDOT Commercial Vehicle Restrictions HTML](../../../redoc/wsdot-commercial-vehicle-restrictions.html)** - Interactive restriction 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