mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-19 13:21:46 +00:00
49b3af8b0d
Optimize day routes around the accommodation
When a day has an accommodation set, the route optimizer now treats it as
the day's home base: it optimizes a loop that leaves the hotel and returns
to it, so the stop nearest the hotel comes first. On a transfer day -
checking out of one hotel and into another - the route runs from the first
hotel to the second instead.
The optimizer also gained a 2-opt pass on top of the nearest-neighbor
ordering, which removes the crossings the greedy pass used to leave behind.
A new display setting ("optimize route from accommodation", on by default)
lets you turn the anchoring off.
Confirm before deleting notes
Deleting a plan note or a collab note now asks for confirmation first. On
phones and tablets the edit and delete icons sit close together and were
easy to mis-tap, which deleted notes with no way back.
74 lines
3.1 KiB
TypeScript
74 lines
3.1 KiB
TypeScript
import { describe, it, expect } from 'vitest'
|
|
import type { Day, Accommodation } from '../types'
|
|
import { getDayOrder, isDayInAccommodationRange, getAccommodationAnchors } from './dayOrder'
|
|
|
|
const days = [
|
|
{ id: 10, day_number: 1 },
|
|
{ id: 20, day_number: 2 },
|
|
{ id: 30, day_number: 3 },
|
|
] as unknown as Day[]
|
|
|
|
const hotel = (over: Partial<Accommodation>): Accommodation =>
|
|
({ place_lat: 48.1, place_lng: 11.5, start_day_id: 10, end_day_id: 30, ...over }) as Accommodation
|
|
|
|
describe('getDayOrder', () => {
|
|
it('prefers day_number when present', () => {
|
|
expect(getDayOrder(days[1], days)).toBe(2)
|
|
})
|
|
it('falls back to array index when day_number is missing', () => {
|
|
const noNumber = [{ id: 5 }, { id: 6 }] as unknown as Day[]
|
|
expect(getDayOrder(noNumber[1], noNumber)).toBe(1)
|
|
})
|
|
})
|
|
|
|
describe('isDayInAccommodationRange', () => {
|
|
it('is inclusive of both the check-in and check-out day', () => {
|
|
expect(isDayInAccommodationRange(days[0], 10, 30, days)).toBe(true) // check-in morning
|
|
expect(isDayInAccommodationRange(days[1], 10, 30, days)).toBe(true) // mid-stay
|
|
expect(isDayInAccommodationRange(days[2], 10, 30, days)).toBe(true) // check-out day
|
|
})
|
|
it('excludes days outside the stay', () => {
|
|
expect(isDayInAccommodationRange(days[0], 20, 30, days)).toBe(false)
|
|
})
|
|
})
|
|
|
|
describe('getAccommodationAnchors', () => {
|
|
it('returns no anchors when the day has no accommodation', () => {
|
|
expect(getAccommodationAnchors(days[1], days, [])).toEqual({})
|
|
})
|
|
|
|
it('anchors both ends to the same hotel on a mid-stay day (round trip)', () => {
|
|
const accs = [hotel({ start_day_id: 10, end_day_id: 30, place_lat: 48.1, place_lng: 11.5 })]
|
|
expect(getAccommodationAnchors(days[1], days, accs)).toEqual({
|
|
start: { lat: 48.1, lng: 11.5 },
|
|
end: { lat: 48.1, lng: 11.5 },
|
|
})
|
|
})
|
|
|
|
it('loops a single hotel on its check-out day (home base for the day)', () => {
|
|
const accs = [hotel({ start_day_id: 10, end_day_id: 20, place_lat: 1, place_lng: 2 })]
|
|
expect(getAccommodationAnchors(days[1], days, accs)).toEqual({ start: { lat: 1, lng: 2 }, end: { lat: 1, lng: 2 } })
|
|
})
|
|
|
|
it('loops a single hotel on its check-in day (home base for the day)', () => {
|
|
const accs = [hotel({ start_day_id: 20, end_day_id: 30, place_lat: 3, place_lng: 4 })]
|
|
expect(getAccommodationAnchors(days[1], days, accs)).toEqual({ start: { lat: 3, lng: 4 }, end: { lat: 3, lng: 4 } })
|
|
})
|
|
|
|
it('uses the checked-out hotel as start and the checked-in hotel as end on a transfer day', () => {
|
|
const accs = [
|
|
hotel({ start_day_id: 10, end_day_id: 20, place_lat: 1, place_lng: 1 }), // checkout today
|
|
hotel({ start_day_id: 20, end_day_id: 30, place_lat: 9, place_lng: 9 }), // check-in today
|
|
]
|
|
expect(getAccommodationAnchors(days[1], days, accs)).toEqual({
|
|
start: { lat: 1, lng: 1 },
|
|
end: { lat: 9, lng: 9 },
|
|
})
|
|
})
|
|
|
|
it('ignores accommodations that have no coordinates', () => {
|
|
const accs = [hotel({ start_day_id: 10, end_day_id: 30, place_lat: null, place_lng: null })]
|
|
expect(getAccommodationAnchors(days[1], days, accs)).toEqual({})
|
|
})
|
|
})
|