Skip to content

Commit

Permalink
Set "Depart at" for transit
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelkirk committed Mar 25, 2023
1 parent 60346c5 commit 69a31fc
Show file tree
Hide file tree
Showing 7 changed files with 243 additions and 32 deletions.
88 changes: 87 additions & 1 deletion services/frontend/www-app/src/components/TripSearch.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<div class="top-card">
<div>
<div style="display: flex">
<search-box
:hint="$t('search.from')"
Expand Down Expand Up @@ -42,6 +42,33 @@
:to-place="toPlace"
:from-place="fromPlace"
/>
<div :hidden="!isTransit()" style="margin-top: 8px; margin-bottom: -8px">
<div v-if="searchTime || searchDate">
<q-btn
flat
:label="$t('trip_search_depart_at')"
size="sm"
@click="didClickDepartAt"
/>
<input
type="time"
:value="initialSearchTime"
@change="(event) => searchTime = (event.target as HTMLInputElement).value"
/>
<input
type="date"
:value="initialSearchDate"
@change="(event) => searchDate = (event.target as HTMLInputElement).value"
/>
</div>
<q-btn
v-else
flat
:label="$t('trip_search_depart_now')"
size="sm"
@click="didClickDepartNow"
/>
</div>
</div>
</template>
<script lang="ts">
Expand Down Expand Up @@ -80,9 +107,50 @@ export default defineComponent({
>,
required: true,
},
initialSearchTime: {
type: String,
},
initialSearchDate: {
type: String,
},
timeDidChange: {
type: Function as PropType<(newValue: string) => void>,
required: true,
},
dateDidChange: {
type: Function as PropType<(newValue: string) => void>,
required: true,
},
},
data(): { searchTime?: string; searchDate?: string } {
return {
searchTime: this.initialSearchTime,
searchDate: this.initialSearchDate,
};
},
watch: {
searchTime: function (newValue: string) {
this.timeDidChange(newValue);
},
searchDate: function (newValue: string) {
this.dateDidChange(newValue);
},
},
components: { SearchBox, TravelModeBar },
methods: {
isTransit(): boolean {
return this.currentMode == TravelMode.Transit;
},
didClickDepartAt() {
this.searchTime = undefined;
this.searchDate = undefined;
},
didClickDepartNow() {
// BRITTLE: search date needs to be set first
// beacuse OTP will error if a time is set without a date.
this.searchDate = dateToInput(new Date());
this.searchTime = timeToInput(new Date());
},
didClickSwap() {
this.didSwapPlaces(this.toPlace, this.fromPlace);
},
Expand Down Expand Up @@ -110,4 +178,22 @@ export default defineComponent({
placeDisplayName,
},
});
function dateToInput(date: Date) {
return (
date.getFullYear() +
'-' +
('0' + (date.getMonth() + 1)).slice(-2) +
'-' +
('0' + date.getDate()).slice(-2)
);
}
function timeToInput(date: Date) {
return (
('0' + date.getHours()).slice(-2) +
':' +
('0' + date.getMinutes()).slice(-2)
);
}
</script>
2 changes: 2 additions & 0 deletions services/frontend/www-app/src/i18n/en-US/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,6 @@ export default {
},
walk_distance: '{preformattedDistance} walk',
route_picker_show_route_details_btn: 'Details',
trip_search_depart_at: 'Leave at',
trip_search_depart_now: 'Leave now',
};
12 changes: 10 additions & 2 deletions services/frontend/www-app/src/models/Itinerary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,17 @@ export default class Itinerary implements Trip {
public static async fetchBest(
from: LngLat,
to: LngLat,
distanceUnits: DistanceUnits
distanceUnits: DistanceUnits,
departureTime?: string,
departureDate?: string
): Promise<Result<Itinerary[], ItineraryError>> {
const result = await OTPClient.fetchItineraries(from, to, 5);
const result = await OTPClient.fetchItineraries(
from,
to,
5,
departureTime,
departureDate
);
if (result.ok) {
return Ok(
result.value.map((otp) => Itinerary.fromOtp(otp, distanceUnits))
Expand Down
12 changes: 10 additions & 2 deletions services/frontend/www-app/src/models/Trip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ export async function fetchBestTrips(
from: LngLat,
to: LngLat,
mode: TravelMode,
distanceUnits: DistanceUnits
distanceUnits: DistanceUnits,
departureTime?: string,
departureDate?: string
): Promise<Result<Trip[], TripFetchError>> {
switch (mode) {
case TravelMode.Walk:
Expand All @@ -40,7 +42,13 @@ export async function fetchBestTrips(
}
}
case TravelMode.Transit: {
const result = await Itinerary.fetchBest(from, to, distanceUnits);
const result = await Itinerary.fetchBest(
from,
to,
distanceUnits,
departureTime,
departureDate
);
if (result.ok) {
return Ok(result.value);
} else {
Expand Down
87 changes: 68 additions & 19 deletions services/frontend/www-app/src/pages/AlternatesPage.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
<template>
<trip-search
:from-place="fromPlace"
:to-place="toPlace"
:current-mode="mode"
:did-select-from-place="searchBoxDidSelectFromPlace"
:did-select-to-place="searchBoxDidSelectToPlace"
:did-swap-places="clickedSwap"
/>
<div class="top-card">
<trip-search
:from-place="fromPlace"
:to-place="toPlace"
:current-mode="mode"
:initial-search-time="searchTime"
:initial-search-date="searchDate"
:did-select-from-place="searchBoxDidSelectFromPlace"
:did-select-to-place="searchBoxDidSelectToPlace"
:did-swap-places="clickedSwap"
:time-did-change="searchTimeDidChange"
:date-did-change="searchDateDidChange"
/>
</div>
<div class="bottom-card">
<div class="search-error" v-if="error">
<p>
Expand Down Expand Up @@ -72,6 +78,7 @@ import Itinerary, { ItineraryErrorCode } from 'src/models/Itinerary';
import { RouteErrorCode } from 'src/models/Route';
import Prefs from 'src/utils/Prefs';
import Markers from 'src/utils/Markers';
import { useRoute } from 'vue-router';
export default defineComponent({
name: 'AlternatesPage',
Expand Down Expand Up @@ -152,18 +159,40 @@ export default defineComponent({
showTripSteps(trip: Trip) {
let index = this.$data.trips.indexOf(trip);
if (index !== -1 && this.to && this.from) {
this.$router.push(
`/directions/${this.mode}/${encodeURIComponent(
this.to
)}/${encodeURIComponent(this.from)}/${index}`
);
let path = `/directions/${this.mode}/${encodeURIComponent(
this.to
)}/${encodeURIComponent(this.from)}/${index}`;
let query = this.dateTimeQuery();
this.$router.push({ path, query });
}
},
clickedSwap(newFromValue?: Place, newToValue?: Place) {
this.fromPlace = newFromValue;
this.toPlace = newToValue;
this.rewriteUrl();
},
searchTimeDidChange(newValue: string) {
this.searchTime = newValue;
this.rewriteUrl();
},
searchDateDidChange(newValue: string) {
this.searchDate = newValue;
this.rewriteUrl();
},
dateTimeQuery(): Record<string, string> {
let query: Record<string, string> = {};
if (this.searchDate) {
query['searchDate'] = this.searchDate;
}
if (this.searchTime) {
query['searchTime'] = this.searchTime;
}
return query;
},
dateTimeQueryString(): string {
let query = new URLSearchParams(this.dateTimeQuery());
return query.toString();
},
rewriteUrl: async function () {
if (!this.fromPlace && !this.toPlace) {
this.$router.push('/');
Expand All @@ -172,10 +201,17 @@ export default defineComponent({
const fromEncoded = this.fromPlace?.urlEncodedId() ?? '_';
const toEncoded = this.toPlace?.urlEncodedId() ?? '_';
this.$router.push(`/directions/${this.mode}/${toEncoded}/${fromEncoded}`);
let path = `/directions/${this.mode}/${toEncoded}/${fromEncoded}`;
let queryString = this.dateTimeQueryString();
if (queryString.length > 0) {
path += '?' + queryString;
}
this.$router.push(path);
await this.updateTrips();
},
async updateTrips(): Promise<void> {
let map = getBaseMap();
if (!map) {
Expand All @@ -196,7 +232,9 @@ export default defineComponent({
this.fromPlace.point,
this.toPlace.point,
this.mode,
Prefs.stored.distanceUnits(this.fromPlace, this.toPlace)
Prefs.stored.distanceUnits(this.fromPlace, this.toPlace),
this.searchTime,
this.searchDate
).finally(() => {
this.isLoading = false;
});
Expand Down Expand Up @@ -327,16 +365,27 @@ export default defineComponent({
this.from as string
);
}
await this.rewriteUrl();
},
setup: function () {
let toPlace: Ref<Place | undefined> = ref(undefined);
let fromPlace: Ref<Place | undefined> = ref(undefined);
const toPlace: Ref<Place | undefined> = ref(undefined);
const fromPlace: Ref<Place | undefined> = ref(undefined);
const searchTime: Ref<string | undefined> = ref(undefined);
const searchDate: Ref<string | undefined> = ref(undefined);
const route = useRoute();
if (typeof route.query.searchTime == 'string') {
searchTime.value = route.query.searchTime;
}
if (typeof route.query.searchDate == 'string') {
searchDate.value = route.query.searchDate;
}
return {
toPlace,
fromPlace,
searchTime,
searchDate,
};
},
});
Expand Down
32 changes: 28 additions & 4 deletions services/frontend/www-app/src/pages/StepsPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,9 @@ export default defineComponent({
goToAlternates() {
const fromEncoded = this.fromPlace?.urlEncodedId() ?? '_';
const toEncoded = this.toPlace?.urlEncodedId() ?? '_';
this.$router.push(`/directions/${this.mode}/${toEncoded}/${fromEncoded}`);
let path = `/directions/${this.mode}/${toEncoded}/${fromEncoded}`;
let query = this.dateTimeQuery();
this.$router.push({ path, query });
},
rewriteUrl: async function () {
Expand All @@ -109,7 +111,9 @@ export default defineComponent({
this.fromPlace.point,
this.toPlace.point,
this.mode,
this.fromPlace.preferredDistanceUnits() ?? DistanceUnits.Kilometers
this.fromPlace.preferredDistanceUnits() ?? DistanceUnits.Kilometers,
this.searchTime,
this.searchDate
);
if (!result.ok) {
console.error('fetchBestTrips.error', result.error);
Expand Down Expand Up @@ -153,6 +157,16 @@ export default defineComponent({
}
map.removeLayersExcept(layerIds);
},
dateTimeQuery(): Record<string, string> {
let query: Record<string, string> = {};
if (this.searchDate) {
query['searchDate'] = this.searchDate;
}
if (this.searchTime) {
query['searchTime'] = this.searchTime;
}
return query;
},
},
mounted: async function () {
this.toPlace = await PlaceStorage.fetchFromSerializedId(
Expand All @@ -161,6 +175,12 @@ export default defineComponent({
this.fromPlace = await PlaceStorage.fetchFromSerializedId(
this.$props.from as string
);
if (typeof this.$route.query.searchTime == 'string') {
this.searchTime = this.$route.query.searchTime;
}
if (typeof this.$route.query.searchDate == 'string') {
this.searchDate = this.$route.query.searchDate;
}
await this.rewriteUrl();
Expand Down Expand Up @@ -199,12 +219,16 @@ export default defineComponent({
}
},
setup: function () {
let toPlace: Ref<Place | undefined> = ref(undefined);
let fromPlace: Ref<Place | undefined> = ref(undefined);
const toPlace: Ref<Place | undefined> = ref(undefined);
const fromPlace: Ref<Place | undefined> = ref(undefined);
const searchTime: Ref<string | undefined> = ref(undefined);
const searchDate: Ref<string | undefined> = ref(undefined);
return {
toPlace,
fromPlace,
searchTime,
searchDate,
};
},
});
Expand Down
Loading

0 comments on commit 69a31fc

Please sign in to comment.