Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

arrival and departure experience overhaul #137

Merged
merged 5 commits into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 21 additions & 44 deletions src/components/ArrivalDeparture.svelte
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
<script>
export let routeShortName;
export let tripHeadsign;
export let scheduledArrivalTime;
export let predictedArrivalTime;
export let tripId;
export let vehicleId;
export let serviceDate;
import { createEventDispatcher } from 'svelte';
export let arrivalDeparture;
let routeShortName = arrivalDeparture.routeShortName;
let tripHeadsign = arrivalDeparture.tripHeadsign;
let scheduledArrivalTime = arrivalDeparture.scheduledArrivalTime;
let predictedArrivalTime = arrivalDeparture.predictedArrivalTime;
import { t } from 'svelte-i18n';

const dispatch = createEventDispatcher();

function formatTime(time) {
const date = new Date(time);
return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
Expand Down Expand Up @@ -62,39 +57,21 @@

return `${Math.floor((chosenTime - now) / 60000)}m`;
}

function handleTripDetail() {
dispatch('showTripDetails', {
tripId,
vehicleId,
serviceDate,
routeShortName,
tripHeadsign,
scheduledArrivalTime,
timeToReach: calculateTimeToReach(predictedArrivalTime, scheduledArrivalTime),
arrivalStatus: getArrivalStatus(predictedArrivalTime, scheduledArrivalTime)
});
}
</script>

<button
on:click={handleTripDetail}
class="flex h-auto w-full items-center justify-between border-b-[1px] border-[#C6C6C8] bg-[#ffffff] p-4 hover:cursor-pointer hover:bg-[#e3e3e3] dark:border-[#313135] dark:bg-[#1c1c1c] hover:dark:bg-[#363636]"
>
<div class="flex flex-col gap-1">
<p class="text-left text-xl font-semibold text-black dark:text-white">
{routeShortName} - {tripHeadsign}
</p>
<p class="text-left font-semibold text-black dark:text-white">
<span class="text-md">{formatTime(scheduledArrivalTime)}</span> -
<span class={getArrivalStatus(predictedArrivalTime, scheduledArrivalTime).color}>
{getArrivalStatus(predictedArrivalTime, scheduledArrivalTime).text}
</span>
</p>
</div>
<div>
<p class="text-lg font-semibold text-black dark:text-white">
{calculateTimeToReach(predictedArrivalTime, scheduledArrivalTime)}
</p>
</div>
</button>
<div class="flex flex-col gap-1">
<p class="text-left text-xl font-semibold text-black dark:text-white">
{routeShortName} - {tripHeadsign}
</p>
<p class="text-left font-semibold text-black dark:text-white">
<span class="text-md">{formatTime(scheduledArrivalTime)}</span> -
<span class={getArrivalStatus(predictedArrivalTime, scheduledArrivalTime).color}>
{getArrivalStatus(predictedArrivalTime, scheduledArrivalTime).text}
</span>
</p>
</div>
<div>
<p class="text-lg font-semibold text-black dark:text-white">
{calculateTimeToReach(predictedArrivalTime, scheduledArrivalTime)}
</p>
</div>
7 changes: 5 additions & 2 deletions src/components/containers/AccordionItem.svelte
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
<script>
import { getContext } from 'svelte';
import { slide } from 'svelte/transition';

export let data = null;

const id = crypto.randomUUID();
const { registerItem } = getContext('accordion');
const { isActive, skipAnimation, activate } = registerItem(id);
function toggle() {
activate();
activate(data);
}
</script>

<div class="relative">
<div class="sticky top-0 z-0 bg-white dark:bg-gray-800">
<div class="sticky top-0 z-10 bg-white dark:bg-gray-800">
<button
type="button"
class="flex w-full items-center justify-between py-3 text-left text-base font-medium text-gray-500 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white"
Expand Down
41 changes: 41 additions & 0 deletions src/components/containers/SingleSelectAccordion.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<script>
import { setContext } from 'svelte';
import { writable, derived } from 'svelte/store';

// Create a store to track the active item and data.
const activeItem = writable(null);
const activeData = writable(null);

// Create dispatch for activeChanged event
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();

// Watch for changes to activeItem and dispatch event
$: {
dispatch('activeChanged', {
activeItem: $activeItem,
activeData: $activeData
});
}

// Provide context for child AccordionItems
setContext('accordion', {
registerItem: (id) => {
const isActive = derived(activeItem, ($activeItem) => $activeItem === id);
return {
isActive,
activate: (data) => {
const newId = $activeItem === id ? null : id;
activeItem.set(newId);
activeData.set(newId ? data : null);
}
};
}
});
</script>

<div
class="divide-y divide-gray-200 border-y border-gray-200 dark:divide-gray-700 dark:border-gray-700"
>
<slot />
</div>
57 changes: 0 additions & 57 deletions src/components/navigation/TripDetailsModal.svelte

This file was deleted.

4 changes: 2 additions & 2 deletions src/components/oba/TripDetailsPane.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,9 @@
<div class="absolute bottom-0 left-3.5 top-0 w-[1px] bg-neutral-400"></div>

{#each tripDetails.schedule.stopTimes as tripStop, index}
<div class="relative mb-4 flex items-center">
<div class="mb-4 flex items-center">
<div
class="relative z-10 flex size-8 items-center justify-center rounded-md border border-neutral-400 bg-white dark:bg-neutral-800"
class="relative flex size-8 items-center justify-center rounded-md border border-neutral-400 bg-white dark:bg-neutral-800"
>
{#if index === busPosition}
<FontAwesomeIcon
Expand Down
63 changes: 20 additions & 43 deletions src/components/stops/StopPane.svelte
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<script>
import ArrivalDeparture from '../ArrivalDeparture.svelte';
import TripDetailsModal from '../navigation/TripDetailsModal.svelte';
import ArrivalDeparture from '$components/ArrivalDeparture.svelte';
import TripDetailsPane from '$components/oba/TripDetailsPane.svelte';
import LoadingSpinner from '$components/LoadingSpinner.svelte';
import Accordion from '$components/containers/SingleSelectAccordion.svelte';
import AccordionItem from '$components/containers/AccordionItem.svelte';
import { onDestroy, onMount } from 'svelte';
import { createEventDispatcher } from 'svelte';

import '$lib/i18n.js';
import { t } from 'svelte-i18n';

import { isLoading } from 'svelte-i18n';
import { isLoading, t } from 'svelte-i18n';

export let stop;
export let arrivalsAndDeparturesResponse = null;
Expand All @@ -17,8 +17,6 @@
let loading = false;
let error;

let showTripDetails = false;
let selectedTripDetails = null;
let interval = null;
let initialDataLoaded = false;

Expand Down Expand Up @@ -72,22 +70,11 @@
return _routeShortNames;
}

function handleShowTripDetails(event) {
selectedTripDetails = {
...event.detail,
routeShortName: event.detail.routeShortName,
tripHeadsign: event.detail.tripHeadsign,
scheduledArrivalTime: event.detail.scheduledArrivalTime
};
showTripDetails = true;
dispatch('tripSelected', selectedTripDetails);
dispatch('updateRouteMap', { show: true });
}

function handleCloseTripDetailModal() {
showTripDetails = false;
dispatch('tripSelected', null);
dispatch('updateRouteMap', { show: false });
function handleAccordionSelectionChanged(event) {
const data = event.detail.activeData; // this is the ArrivalDeparture object plumbed into the AccordionItem
const show = !!data;
dispatch('tripSelected', data);
dispatch('updateRouteMap', { show });
}
</script>

Expand Down Expand Up @@ -128,28 +115,18 @@
<p>{$t('no_arrivals_or_departures_in_next_30_minutes')}</p>
</div>
{:else}
<div class="space-y-2 overflow-y-scroll rounded-lg">
<div>
{#each arrivalsAndDepartures.arrivalsAndDepartures as arrival}
<ArrivalDeparture
routeShortName={arrival.routeShortName}
tripHeadsign={arrival.tripHeadsign}
scheduledArrivalTime={arrival.scheduledArrivalTime}
predictedArrivalTime={arrival.predictedArrivalTime}
tripId={arrival.tripId}
vehicleId={arrival.vehicleId}
serviceDate={arrival.serviceDate}
on:showTripDetails={handleShowTripDetails}
/>
{/each}
</div>
</div>
<Accordion on:activeChanged={handleAccordionSelectionChanged}>
{#each arrivalsAndDepartures.arrivalsAndDepartures as arrival}
<AccordionItem data={arrival}>
<span slot="header">
<ArrivalDeparture arrivalDeparture={arrival} />
</span>
<TripDetailsPane {stop} tripId={arrival.tripId} serviceDate={arrival.serviceDate} />
</AccordionItem>
{/each}
</Accordion>
{/if}
</div>
{/if}

{#if showTripDetails}
<TripDetailsModal {stop} {selectedTripDetails} onClose={handleCloseTripDetailModal} />
{/if}
</div>
{/if}
6 changes: 5 additions & 1 deletion src/routes/stops/[stopID]/schedule/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@
$: if (selectedDate && selectedDate !== prevSelectedDate) {
const formattedDate = selectedDate.toISOString().split('T')[0];
prevSelectedDate = selectedDate;
fetchScheduleForStop(stopId, formattedDate);

// we get an error if we try to fetch data on the server
if (typeof window !== 'undefined') {
fetchScheduleForStop(stopId, formattedDate);
}
}

async function fetchScheduleForStop(stopId, date) {
Expand Down
Loading