Skip to content

Commit

Permalink
Foundational work for trip planner integration
Browse files Browse the repository at this point in the history
  • Loading branch information
aaronbrethorst committed Nov 6, 2024
1 parent a2d4027 commit 2dc3b7e
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 55 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ PRIVATE_OBA_GEOCODER_PROVIDER="google"
PUBLIC_OBA_LOGO_URL="https://onebusaway.org/wp-content/uploads/oba_logo-1.png"
PUBLIC_OBA_MAP_PROVIDER="osm"
PUBLIC_NAV_BAR_LINKS={"Home": "/","About": "/about","Contact": "/contact","Fares & Tolls": "/fares-and-tolls"}
PUBLIC_OTP_SERVER_URL=""
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ See `.env.example` for an example of the required keys and values.
- `PRIVATE_OBA_GEOCODER_API_KEY` - string: Your Geocoder service's API key. Leave this blank if you don't have one.
- `PRIVATE_OBA_GEOCODER_PROVIDER` - string: Your Geocoder service. We currently only support the Google Places SDK (value: "google").


### Trip Planner

- `PUBLIC_OTP_SERVER_URL` - string: Your OpenTripPlanner 1.x-compatible trip planner server URL. Leave this blank if you don't have one.

## Building

To create a production version of your app:
Expand Down
116 changes: 61 additions & 55 deletions src/components/search/SearchPane.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import { t } from 'svelte-i18n';
import { clearVehicleMarkersMap, fetchAndUpdateVehicles } from '$lib/vehicleUtils';
import { calculateMidpoint } from '$lib/mathUtils';
import { Tabs, TabItem } from 'flowbite-svelte';
const dispatch = createEventDispatcher();
Expand Down Expand Up @@ -107,63 +108,68 @@
});
</script>

<div class={`modal-pane flex justify-between md:w-96 ${cssClasses}`}>
<div class="flex w-full flex-col gap-y-2 py-4">
<SearchField value={query} on:searchResults={handleSearchResults} />

{#if query}
<p class="text-sm text-gray-700 dark:text-gray-400">
{$t('search.results_for')} "{query}".
<button type="button" on:click={clearResults} class="text-blue-600 hover:underline">
{$t('search.clear_results')}
</button>
</p>
{/if}

<div class="max-h-96 overflow-y-auto">
{#if location}
<SearchResultItem
on:click={() => handleLocationClick(location)}
title={location.formatted_address}
icon={faMapPin}
subtitle={location.types.join(', ')}
/>
{/if}

{#if routes?.length > 0}
{#each routes as route}
<SearchResultItem
on:click={() => handleRouteClick(route)}
icon={prioritizedRouteTypeForDisplay(route.type)}
title={`${$t('route')} ${route.nullSafeShortName || route.id}`}
subtitle={route.description}
/>
{/each}
<div class={`modal-pane flex flex-col justify-between md:w-96 ${cssClasses}`}>
<Tabs tabStyle="underline">
<TabItem open title="Stops and Stations">
<SearchField value={query} on:searchResults={handleSearchResults} />

{#if query}
<p class="text-sm text-gray-700 dark:text-gray-400">
{$t('search.results_for')} "{query}".
<button type="button" on:click={clearResults} class="text-blue-600 hover:underline">
{$t('search.clear_results')}
</button>
</p>
{/if}

{#if stops?.length > 0}
{#each stops as stop}
<div class="max-h-96 overflow-y-auto">
{#if location}
<SearchResultItem
on:click={() => handleStopClick(stop)}
icon={faSignsPost}
title={stop.name}
subtitle={`${compassDirection(stop.direction)}; Code: ${stop.code}`}
on:click={() => handleLocationClick(location)}
title={location.formatted_address}
icon={faMapPin}
subtitle={location.types.join(', ')}
/>
{/each}
{/if}
</div>

<div class="mt-0 sm:mt-0">
<button
type="button"
class="text-sm font-medium text-green-600 underline hover:text-green-400 focus:outline-none"
on:click={handleViewAllRoutes}
>
{$t('search.click_here')}
</button>
<span class="text-sm font-medium text-black dark:text-white">
{$t('search.for_a_list_of_available_routes')}</span
>
</div>
</div>
{/if}

{#if routes?.length > 0}
{#each routes as route}
<SearchResultItem
on:click={() => handleRouteClick(route)}
icon={prioritizedRouteTypeForDisplay(route.type)}
title={`${$t('route')} ${route.nullSafeShortName || route.id}`}
subtitle={route.description}
/>
{/each}
{/if}

{#if stops?.length > 0}
{#each stops as stop}
<SearchResultItem
on:click={() => handleStopClick(stop)}
icon={faSignsPost}
title={stop.name}
subtitle={`${compassDirection(stop.direction)}; Code: ${stop.code}`}
/>
{/each}
{/if}
</div>

<div class="mt-0 sm:mt-0">
<button
type="button"
class="text-sm font-medium text-green-600 underline hover:text-green-400 focus:outline-none"
on:click={handleViewAllRoutes}
>
{$t('search.click_here')}
</button>
<span class="text-sm font-medium text-black dark:text-white">
{$t('search.for_a_list_of_available_routes')}</span
>
</div>
</TabItem>
<TabItem title="Plan a Trip">
plan a trip UI goes here!
</TabItem>
</Tabs>
</div>
31 changes: 31 additions & 0 deletions src/routes/api/otp/plan/+server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { error, json } from '@sveltejs/kit';

export async function GET() {
try {
const response = await fetch(
'https://otp.prod.sound.obaweb.org/otp/routers/default/plan?fromPlace=47.5423055%2C-122.38677&toPlace=47.639376%2C-122.128238',
{
headers: {
'Accept': 'application/json'
}
}
);

if (!response.ok) {
throw error(response.status, `OpenTripPlanner API returned status ${response.status}`);
}

const data = await response.json();
return json(data);

} catch (err) {
// If it's already a SvelteKit error, rethrow it
if (err.status) throw err;

// Otherwise wrap it in a 500 error
throw error(500, {
message: 'Failed to fetch trip planning data',
error: err.message
});
}
}

0 comments on commit 2dc3b7e

Please sign in to comment.