fix: add directions links and stabilize connector metrics after drag
This commit is contained in:
@@ -576,6 +576,9 @@
|
|||||||
): ResolvedItineraryItem | null {
|
): ResolvedItineraryItem | null {
|
||||||
for (let index = currentIndex + 1; index < items.length; index += 1) {
|
for (let index = currentIndex + 1; index < items.length; index += 1) {
|
||||||
const candidate = items[index];
|
const candidate = items[index];
|
||||||
|
if (candidate?.[SHADOW_ITEM_MARKER_PROPERTY_NAME]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if ((candidate?.item?.type || '') === 'location') {
|
if ((candidate?.item?.type || '') === 'location') {
|
||||||
return candidate;
|
return candidate;
|
||||||
}
|
}
|
||||||
@@ -590,6 +593,9 @@
|
|||||||
for (const dayGroup of dayGroups) {
|
for (const dayGroup of dayGroups) {
|
||||||
for (let index = 0; index < dayGroup.items.length - 1; index += 1) {
|
for (let index = 0; index < dayGroup.items.length - 1; index += 1) {
|
||||||
const currentItem = dayGroup.items[index];
|
const currentItem = dayGroup.items[index];
|
||||||
|
if (currentItem?.[SHADOW_ITEM_MARKER_PROPERTY_NAME]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
const nextLocationItem = findNextLocationItem(dayGroup.items, index);
|
const nextLocationItem = findNextLocationItem(dayGroup.items, index);
|
||||||
const pair = getConnectorPair(currentItem, nextLocationItem);
|
const pair = getConnectorPair(currentItem, nextLocationItem);
|
||||||
if (pair) pairs.push(pair);
|
if (pair) pairs.push(pair);
|
||||||
@@ -696,9 +702,11 @@
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (fetchVersion !== activeConnectorFetchVersion) return;
|
if (fetchVersion !== activeConnectorFetchVersion) return;
|
||||||
console.error('Failed to fetch connector route metrics:', error);
|
console.error('Failed to fetch connector route metrics:', error);
|
||||||
|
if (connectorPairs.length === 0) {
|
||||||
connectorMetricsMap = {};
|
connectorMetricsMap = {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
const connectorPairs = getConnectorPairs(days);
|
const connectorPairs = getConnectorPairs(days);
|
||||||
@@ -754,6 +762,41 @@
|
|||||||
return getFallbackLocationConnector(currentItem, nextItem);
|
return getFallbackLocationConnector(currentItem, nextItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildDirectionsUrl(
|
||||||
|
currentItem: ResolvedItineraryItem,
|
||||||
|
nextItem: ResolvedItineraryItem | null,
|
||||||
|
mode: 'walking' | 'driving' = 'walking'
|
||||||
|
): string | null {
|
||||||
|
if (!nextItem) return null;
|
||||||
|
|
||||||
|
const currentType = currentItem.item?.type || '';
|
||||||
|
const nextType = nextItem.item?.type || '';
|
||||||
|
if (currentType !== 'location' || nextType !== 'location') return null;
|
||||||
|
|
||||||
|
const currentLocation = currentItem.resolvedObject as Location | null;
|
||||||
|
const nextLocation = nextItem.resolvedObject as Location | null;
|
||||||
|
if (!currentLocation || !nextLocation) return null;
|
||||||
|
|
||||||
|
const fromLatitude = normalizeCoordinate(currentLocation.latitude);
|
||||||
|
const fromLongitude = normalizeCoordinate(currentLocation.longitude);
|
||||||
|
const toLatitude = normalizeCoordinate(nextLocation.latitude);
|
||||||
|
const toLongitude = normalizeCoordinate(nextLocation.longitude);
|
||||||
|
|
||||||
|
if (
|
||||||
|
fromLatitude === null ||
|
||||||
|
fromLongitude === null ||
|
||||||
|
toLatitude === null ||
|
||||||
|
toLongitude === null
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const engine = mode === 'driving' ? 'car' : 'foot';
|
||||||
|
const route = `${fromLatitude},${fromLongitude};${toLatitude},${toLongitude}`;
|
||||||
|
|
||||||
|
return `https://www.openstreetmap.org/directions?engine=fossgis_osrm_${engine}&route=${encodeURIComponent(route)}`;
|
||||||
|
}
|
||||||
|
|
||||||
function getI18nText(key: string, fallback: string): string {
|
function getI18nText(key: string, fallback: string): string {
|
||||||
const translated = $t(key);
|
const translated = $t(key);
|
||||||
return translated && translated !== key ? translated : fallback;
|
return translated && translated !== key ? translated : fallback;
|
||||||
@@ -1413,6 +1456,13 @@
|
|||||||
return it;
|
return it;
|
||||||
});
|
});
|
||||||
collection.itinerary = updatedItinerary;
|
collection.itinerary = updatedItinerary;
|
||||||
|
|
||||||
|
// Rebuild canonical local state immediately after persisting reorder
|
||||||
|
days = groupItemsByDay(collection);
|
||||||
|
globalItems = (collection.itinerary || [])
|
||||||
|
.filter((it) => it.is_global)
|
||||||
|
.map((it) => resolveItineraryItem(it, collection))
|
||||||
|
.sort((a, b) => a.order - b.order);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error saving itinerary order:', error);
|
console.error('Error saving itinerary order:', error);
|
||||||
// Optionally show error notification to user
|
// Optionally show error notification to user
|
||||||
@@ -2406,6 +2456,11 @@
|
|||||||
{@const multiDay = isMultiDay(item)}
|
{@const multiDay = isMultiDay(item)}
|
||||||
{@const nextLocationItem = findNextLocationItem(day.items, index)}
|
{@const nextLocationItem = findNextLocationItem(day.items, index)}
|
||||||
{@const locationConnector = getLocationConnector(item, nextLocationItem)}
|
{@const locationConnector = getLocationConnector(item, nextLocationItem)}
|
||||||
|
{@const directionsUrl = buildDirectionsUrl(
|
||||||
|
item,
|
||||||
|
nextLocationItem,
|
||||||
|
locationConnector?.mode || 'walking'
|
||||||
|
)}
|
||||||
{@const isDraggingShadow = item[SHADOW_ITEM_MARKER_PROPERTY_NAME]}
|
{@const isDraggingShadow = item[SHADOW_ITEM_MARKER_PROPERTY_NAME]}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
@@ -2638,10 +2693,22 @@
|
|||||||
{locationConnector.durationLabel}
|
{locationConnector.durationLabel}
|
||||||
</span>
|
</span>
|
||||||
<span class="text-base-content/40">•</span>
|
<span class="text-base-content/40">•</span>
|
||||||
|
{#if directionsUrl}
|
||||||
|
<a
|
||||||
|
href={directionsUrl}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
class="inline-flex items-center gap-1 text-primary/80 font-medium underline underline-offset-2"
|
||||||
|
>
|
||||||
|
<LocationMarker class="w-3.5 h-3.5" />
|
||||||
|
{getI18nText('itinerary.directions', 'Directions')}
|
||||||
|
</a>
|
||||||
|
{:else}
|
||||||
<span class="inline-flex items-center gap-1 text-primary/80 font-medium underline underline-offset-2">
|
<span class="inline-flex items-center gap-1 text-primary/80 font-medium underline underline-offset-2">
|
||||||
<LocationMarker class="w-3.5 h-3.5" />
|
<LocationMarker class="w-3.5 h-3.5" />
|
||||||
{getI18nText('itinerary.directions', 'Directions')}
|
{getI18nText('itinerary.directions', 'Directions')}
|
||||||
</span>
|
</span>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="flex items-center gap-2 flex-wrap text-base-content">
|
<div class="flex items-center gap-2 flex-wrap text-base-content">
|
||||||
@@ -2656,10 +2723,22 @@
|
|||||||
<span class="text-base-content/50">•</span>
|
<span class="text-base-content/50">•</span>
|
||||||
<span class="font-medium">{locationConnector.distanceLabel}</span>
|
<span class="font-medium">{locationConnector.distanceLabel}</span>
|
||||||
<span class="text-base-content/50">•</span>
|
<span class="text-base-content/50">•</span>
|
||||||
|
{#if directionsUrl}
|
||||||
|
<a
|
||||||
|
href={directionsUrl}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
class="inline-flex items-center gap-1 text-primary font-medium underline underline-offset-2"
|
||||||
|
>
|
||||||
|
<LocationMarker class="w-3.5 h-3.5" />
|
||||||
|
{getI18nText('itinerary.directions', 'Directions')}
|
||||||
|
</a>
|
||||||
|
{:else}
|
||||||
<span class="inline-flex items-center gap-1 text-primary font-medium underline underline-offset-2">
|
<span class="inline-flex items-center gap-1 text-primary font-medium underline underline-offset-2">
|
||||||
<LocationMarker class="w-3.5 h-3.5" />
|
<LocationMarker class="w-3.5 h-3.5" />
|
||||||
{getI18nText('itinerary.directions', 'Directions')}
|
{getI18nText('itinerary.directions', 'Directions')}
|
||||||
</span>
|
</span>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user