feat: optimize routes around accommodation, confirm note deletions (#1123)

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.
This commit is contained in:
Maurice
2026-06-07 12:52:06 +02:00
committed by GitHub
parent 093e069ccc
commit 49b3af8b0d
72 changed files with 504 additions and 26 deletions
+2
View File
@@ -39,6 +39,8 @@ const collab: TranslationStrings = {
'collab.notes.cancel': '취소',
'collab.notes.edit': '편집',
'collab.notes.delete': '삭제',
'collab.notes.confirmDeleteTitle': '메모를 삭제할까요?',
'collab.notes.confirmDeleteBody': '이 메모가 영구적으로 삭제됩니다.',
'collab.notes.pin': '고정',
'collab.notes.unpin': '고정 해제',
'collab.notes.daysAgo': '{n}일 전',
+3
View File
@@ -9,6 +9,8 @@ const dayplan: TranslationStrings = {
'dayplan.confirmRemoveTimeBody':
'이 장소에 고정된 시간 ({time})이 있습니다. 이동하면 시간이 제거되고 자유 정렬이 허용됩니다.',
'dayplan.confirmRemoveTimeAction': '시간 제거 및 이동',
'dayplan.confirmDeleteNoteTitle': '메모를 삭제할까요?',
'dayplan.confirmDeleteNoteBody': '이 메모가 영구적으로 삭제됩니다.',
'dayplan.cannotDropOnTimed': '시간이 고정된 항목 사이에 배치할 수 없습니다',
'dayplan.cannotBreakChronology':
'이 작업은 시간 고정 항목과 예약의 시간 순서를 깨뜨립니다',
@@ -31,6 +33,7 @@ const dayplan: TranslationStrings = {
'dayplan.toast.needTwoPlaces':
'경로 최적화에는 최소 두 개의 장소가 필요합니다',
'dayplan.toast.routeOptimized': '경로가 최적화되었습니다',
'dayplan.toast.routeOptimizedFromHotel': '숙소를 기준으로 경로가 최적화되었습니다',
'dayplan.toast.noGeoPlaces': '경로 계산을 위한 좌표가 있는 장소가 없습니다',
'dayplan.confirmed': '확정됨',
'dayplan.pendingRes': '대기 중',
+3
View File
@@ -65,6 +65,9 @@ const settings: TranslationStrings = {
'settings.bookingLabelsHint':
'지도에 역 / 공항 이름을 표시합니다. 끄면 아이콘만 표시됩니다.',
'settings.blurBookingCodes': '예약 코드 흐리게',
'settings.optimizeFromAccommodation': '숙소 기준으로 경로 최적화',
'settings.optimizeFromAccommodationHint':
'하루 일정을 최적화할 때, 아침에 머무는 숙소에서 경로를 시작하고 그날 저녁에 체크인하는 숙소에서 경로를 끝냅니다.',
'settings.notifications': '알림',
'settings.notifyTripInvite': '여행 초대',
'settings.notifyBookingChange': '예약 변경',