Commit Graph

708 Commits

Author SHA1 Message Date
Maurice eb4e74b5c3 fix(forms): keep password managers out of a place's contact fields and the admin user forms
1Password filled the signed-in user's login into a place's e-mail field, and
offered the admin's own credentials for an account being created. The fields
now carry each manager's opt-out; autocomplete=off alone is ignored.
2026-10-14 13:24:27 +02:00
Maurice db531d2bef test(tours): the wiring test reads the map stage, the phone timeline test hands the planner its tours 2026-10-14 12:05:49 +02:00
Maurice 7795061630 refactor(tours): move the planner additions out of the map, sidebar and page files that grew past their size baseline 2026-10-14 10:00:08 +02:00
Maurice 09227ec0d1 fix(tours): the map search sits between the panels without a physical side, and the day row facts use the caption tier 2026-10-14 09:22:38 +02:00
Maurice dbee1664af fix(tours): hold the client warning ratchet and the server format baseline flat after the rebase onto dev 2026-10-14 09:11:47 +02:00
elmocito 57ea219a43 feat(tours): complete planner follow-up scope
This commit completes the reviewed Tours follow-up scope after the Tours MVP was merged into dev.

Included feature blocks:

- RC-01: identify Tours in PLAN day rows and show compact Tour facts;
- RC-06: search for a city or address in TOUR-PLANNER without hidden writes;
- RC-07: reorder Tour waypoints in the left sidebar;
- RC-08: drag Tour waypoints on Leaflet, MapLibre and Mapbox with stable viewport, history and routing behavior;
- RS-01: persist Tour descriptions and HTTPS information links with local provider classification;
- RS-02: persist breaks/additional time and calculated or manually adjusted planned Tour duration without changing scheduling semantics.
The implementation preserves:

- ordinary Place and Legacy Track behavior;
- Tours-off fallback behavior;
- existing GPX/import behavior;
- Tour assignment and deletion behavior;
- calculated routing duration as a separate value;
- existing Tour provenance fields;
- keyboard/list alternatives for waypoint editing.
Not included:

- PR1-09 trip-wide Tour summary;
- Wanderer integration;
- GPX import changes;
- new Tour types;
- Tour-to-Day drag-and-drop;
- further roadmap or Post-Release features.
Validation:

- focused RC-01/RC-06/RC-07/RC-08/RS-01/RS-02 tests passed;
- affected shared/server/client typechecks passed;
- migration and generated DB type checks passed;
- scoped ESLint passed;
- staged diff checks passed;
- owner manual tests passed for all six feature blocks.
2026-10-14 08:39:31 +02:00
Maurice 5d6dc6129c test(planner): the booking cases read stays through the repo and link a hotel made offline by its temp id 2026-10-12 22:18:50 +00:00
Maurice 6fa51c638f test(journey): the journey page cases find the settings delete in its dialog and confirm a gallery delete first 2026-10-12 22:18:50 +00:00
Maurice dd8d6a0b7d chore(knip): drop the exports nothing outside their module reads 2026-10-12 21:14:28 +00:00
Maurice 00fca4952f test(roadtrip): the road trip suite writes stays through the real repo and seeds the searched day once 2026-10-12 21:14:28 +00:00
Maurice 645b893e92 test(planner): the tours tab cases render the page through one helper 2026-10-12 21:14:28 +00:00
Maurice 7b023c6b54 refactor(map): the road trip via helpers move to utils, so the route hook imports no component 2026-10-12 21:14:05 +00:00
Maurice 4a6ee6819c style(client): prettier on the files this branch touched 2026-10-12 20:01:22 +00:00
Maurice 93cce57306 fix(dashboard): trip counters and upcoming bookings refresh after a trip is created, copied, redated, archived or deleted
The travel stats and the upcoming bookings were only fetched when the
dashboard mounted, so "Trips" and "Days" kept their old values after a new
or duplicated trip and the sidebar still listed booking dates from before a
date change until the page was left. Every successful trip mutation now
reloads both, on desktop and mobile alike since they share the hook.

Refs #2604
2026-10-12 20:29:29 +02:00
Maurice bdd8c08dd4 fix(planner): places put on a day, day names, day notes and trip details changed offline wait in the queue and sync once the connection is back
The day plan wrote straight to the API, so offline a place dropped on a day
snapped back with "Error assigning place", a renamed day or a new day note
failed, and a moved stop, a leg's travel mode or who joins a visit were lost.
Visits (put on a day, taken off, reordered, moved, travellers, leg mode), the
day's name, notes text and travel mode, and the day notes (add, edit, delete,
move) now go through assignmentRepo, dayRepo and dayNoteRepo and the mutation
queue: the cached day changes at once, a visit or note made offline gets a
temporary id that the edits after it wait for, and an online write held behind
an older queued one joins the queue, since none of these carry a version
token. A new order of a day that names a visit made offline is sent with its
real id, or without it when its create failed. Desktop, the phone timeline and
note sheet all write through the store, so both are covered.

The replay reads each answer for what it names: the day answer keeps the
cached notes and visits, the participants answer lands on its visit, and a
visit the server refuses with 409 (a Tour already on that day) fails instead
of waiting as a conflict no retry can solve.

The trip's name, description, reminder and the archive flag wait in the queue
too, from the planner, the phone and the dashboard. What only the server can
do says so instead of failing: new dates, a day count, a currency or a cover,
a new trip, a copy or a delete, members, guests, share and invite links, and
a new order of the days, which moves the dates of the bookings.

Refs #2601
2026-10-12 20:17:57 +02:00
Maurice 92c48fba22 fix(files): file notes, links, stars and the trash changed offline wait in the queue and sync once the connection is back
Every file write went straight to the API, so offline a star snapped back
without a word and moving a file to the trash failed with "Failed to delete
file". Notes, the place or booking of a file, a further link, the star, the
trash move, restore, delete for good and emptying the trash now go through
fileRepo and the mutation queue like the other trip data: the local copy
changes at once, and an online write to a file that still has an older one
queued joins the queue behind it, since file writes carry no version token.
The desktop file manager, its assign dialog and the phone's files tab,
menu, link and trash sheets all write through it.

The single file answers carry no ids of further links, so a replayed edit,
star or restore keeps the ones the local copy holds, and the link answer
({ success, links }) writes no row.

What only works online says so instead of failing: an upload shows that it
needs a connection, a place saved with newly picked files is stopped with a
hint, and removing a further link (its row id is known only to the server)
asks to try again once online.

Refs #2601
2026-10-12 19:32:16 +02:00
Maurice 64ceecefb3 fix(bookings): bookings, transports and stays saved offline wait in the queue and sync once the connection is back
Every booking and stay write went straight to the API, so offline a new
booking failed with "Network Error" and was lost, and a status tick, the
travellers or a moved transport snapped back. Bookings (add, edit, status,
travellers, delete, day order) and stays (add, edit, delete) now go through
reservationRepo and accommodationRepo and the mutation queue like places and
costs: a temporary row offline, held behind an older queued write online,
since neither carries a version token. Desktop, the phone sheets, the day
plan, the road trip nights and the PDF all write and read through them.

The replay reads the booking from `reservation` only, so the travellers
answer ({ travelers, reservation }) lands on the booking it names. A booking
or its stay that names a place or stay created offline is sent with the real
id once that one has synced, inside create_accommodation too, so an imported
hotel reviewed offline can be linked to a place made for it.

What only works online says so instead of failing: an AirTrail import, a
booking file import, the AI retry and an attachment on a saved booking show
that they need a connection, and a save with newly picked files is stopped
with a hint, since an upload cannot wait in the queue.

Refs #2601
2026-10-12 19:07:33 +02:00
Maurice fbba8f96b7 fix(planner): road trip mode, the dawarich trail and the route overview follow the account to another browser
The three planner view switches lived in sessionStorage only, so a new tab,
another browser or another device opened every trip on the plain view again.
They are now kept per trip in one user setting, planner_trip_views, validated
against a contract in @trek/shared. The server keeps only switches that are on
and only trips the user can still open, so a deleted trip or one the user left
drops out on the next write. The tab copy in sessionStorage stays and answers
until the settings have loaded.

Refs #2639
2026-10-12 17:41:56 +02:00
Maurice adb88142ab fix(places): the place search looks where the plan map is looking
Autocomplete and the full search took their location hint only from the
open day or the whole trip, and dropped a trip spread over several cities
as too wide. Zoomed in on one city of such a trip, the search went global.

The plan map now hands its viewport to the trip store on desktop and on
the phone, and useLocationBias tries it first. A viewport wider than the
same 60 km radius, one across the antimeridian or one from another trip
is ignored, and the day and the trip follow as before. The viewport is
cleared when the plan map leaves the screen and on a trip switch.

Refs #2620
2026-10-12 17:18:17 +02:00
Maurice 3d7e8be9aa fix(oidc): a sign-in links to an account by email only when the address was not set by the account itself
An SSO login that matched no account by its subject took the account with the
same email address and linked the provider identity to it. That address proves
nothing when the account typed it in itself: anyone could sign up with, or
switch their profile to, a colleague's address and receive the colleague's
first SSO login. The provider switch branch (#2110) relinked a row on any email
match without even asking for email_verified, and also for another subject of
the same provider.

users.email_self_asserted remembers an address the account set itself: signup
(not the first account) and an email change in the profile settings set it, an
admin entering a new address clears it, and accounts the provider creates start
without it. Existing accounts keep linking, except those whose address moved
away from the registered one without an admin editing it. A login by email now
needs a verified address and an unmarked account, and is refused for another
subject of the same issuer, with email_link_blocked and a translated message on
the login screen. An email change in the profile settings writes a
user.email_change audit row.

Refs #2110
2026-10-12 17:06:52 +02:00
Maurice 92af437ff6 fix(roadtrip): the stop a booking put on its check-in day keeps the night over a rest later that day
The night went to the last visit of the hotel. On a day without hours the
booking seats its own stop first, and Days does not show that stop, so a rest
the traveller put mid-day was the last visit: it was held to the check-in and
the places behind it followed from there, the way the report describes.

The night is now the visit that ends the day, else the booking's stop, else
the last visit. A visit the traveller adds to the check-in day no longer moves
the night or its check-in. nightVisits in shared holds the rule, and the road
trip, calculate_roadtrip, the stored ride slot and the stop editor all read it.

Refs #2636
2026-10-12 16:05:17 +02:00
Maurice a0331bf53b fix(dashboard): a refused archive, delete or copy says why instead of only that it failed
A member without the right to archive a trip clicked Archive and read
"Failed to archive trip", while the server had answered why. The archive,
restore, delete and copy toasts now show the server's reason, as creating
and editing a trip already did; a failure without one keeps the old line.
The buttons stay where they are.

Refs #2604
2026-10-12 15:46:17 +02:00
Maurice 125649ce1b fix(planner): cards over the map stay clear of the layer pill, and a wide tab bar shows full tab names
The base-layer pill sits in the map's bottom-left corner on purpose. The
place inspector, a tour's detail and the day panel are centred between the
sidebars and were assumed never to reach that corner, but with both
sidebars open in a 1280 window they do, and the pill covered "Remove from
Day" and Edit. These cards now keep their left edge clear of the pill: a
narrow map moves the card right of it, a wide map keeps it centred as
before. The pill itself does not move, and the phone sheets are unchanged.

The Bookings tab showed "Book" at every width, which read as cut off. The
short form now only shows where the bar is tight; from xl up the tab shows
its full name.

Refs #2604
2026-10-12 15:46:09 +02:00
Maurice 676f6233ed fix(planner): undoing a place delete brings the place back whole, or is not offered
The undo wrote a new place from nine of its fields and put it on its days as a
bare stop, so notes, website, phone, hours, picture, the visit times, day notes
and travellers were gone while the toast said it was undone. It now writes every
field the place had and plans each visit again with its times, note, end of day,
route flag, travellers and leg modes, and casts the own rating again.

The server takes a booked night, its booking and expense, linked expenses, file
links, other members' ratings and an uploaded picture down with the place, and
writing the place again brings none of that back. Such a delete is no longer
offered for undo. Undo steps that name a deleted place are dropped at the delete
instead of failing later, and adding a place, moving categories and the phone
reorder and optimize now carry their place ids for that.

Taking a stop off a day and clearing a day undo with the visit details too. The
stays are read again when a deleted place had one, here and for collaborators.

Refs #2604
2026-10-12 13:44:44 +02:00
Maurice 8acc035efa fix(collections): all saved reads its lists four at a time and reloads once per burst of updates
The "All saved" view read every list in full at the same time, and every
collections:* websocket event started that again right away. An agent saving
places one by one over MCP sends one event per place, so an open collections
tab stacked up full reads of every list on the server.

The union now goes through the same batched loader the trip's saved-places
picker uses (four lists at a time), reloads asked for while it runs fold into
one more pass, and a list or union read that lands after the user switched to
something else is dropped instead of painting its places over the new view.
The page waits for a run of events to settle before it reloads and keeps the
selection on "All saved" like it already did on a single list. Desktop and
phone share useCollections, so both get it.

Refs #2559
2026-10-12 12:59:44 +02:00
Maurice 2f0b867685 fix(settings): the integrations tab is always there on desktop so api keys stay reachable
API keys were split off from MCP to work without any addon, but the tab
that holds them still hid unless a photo provider, MCP, AirTrail, AI
Parsing or Dawarich was enabled. On a fresh install all of those are off,
so there was no way to create a key. The desktop tab now always shows;
the addon backed sections inside it keep their own gates. The phone layout
has no API Keys section and keeps its gate.

The wiki now says where keys are created and that no addon is needed.

Refs #2561
2026-10-12 12:46:12 +02:00
Maurice 3dbe76945d fix(roadtrip): the day view drives the road picked in the road trip
A chosen alternative or a hand-bent drive is stored as vias, and only the
road trip rail routed through them. The day route on the map, its
connectors in the day list and on the phone, and the overview of all days
asked the router for the bare stops, so they drew and measured the default
road again.

They now thread the same vias between two stops that follow each other in
the stored list, with the anchor counted the way the rail counts it, and
fold the answer back to one leg per stop pair. Only while the road trip
addon is on; avoid settings and the routing engine stay with the rail.

Refs #2580
2026-10-12 11:32:15 +02:00
Maurice 565333a90c fix(roadtrip): a hotel visited again on its check-in day is the night only at its last visit
A stop counted as the booked night whenever a stay began at its place on its
day, so a hotel on its check-in day twice (the booking's own stop and a rest
the traveller planned there) was read as two nights. Both were held to the
check-in: the rest waited for the room or was set back to it, and with a check-in
far from its arrival the rest and every stop behind it moved onto the next day's
card.

oneNightPerStay in shared keeps the night and its check-in on the last visit of
the place and turns the earlier ones into ordinary stops, still a hotel. The
browser and calculate_roadtrip both run it, the stored ride slot times only that
row by the check-in, and opening an earlier visit in road trip mode opens the
stop rather than the night.

Refs #2636
2026-10-12 11:05:41 +02:00
Maurice e3bf18f9a6 fix(collections): a list invite can be accepted where its notification leads, on phone and desktop
The invite notification links to /collections/:id, a list the invitee
cannot read until they accept. The phone screen had no invite UI at all
and showed "Start your first collection", and on desktop the rail with the
invites is hidden below 1080px while the empty state had no way to open it.

useCollections now recognises a route id that is a pending invite, keeps
it out of the route sync and puts it first in the invites it hands out.
The phone screen shows the pending invites as cards above the lists, and
the desktop body shows them when the person has no lists of their own,
or the one invite the route points at. Both reuse the existing invite
strings. A route id that is neither a list nor an invite (declined,
withdrawn, deleted) now drops back to /collections once the lists are in,
instead of leaving the page on a list it cannot show.

Refs #2645
2026-10-12 10:44:57 +02:00
Maurice c94d275cfd fix(journey): gallery photos can be deleted on touch screens and ask before they go
The delete on a gallery tile only showed on mouse hover, so a phone or
tablet never saw it, and the phone screen had no delete at all. Where it
was reachable it deleted at once, although the server removes the photo
for good and takes it out of every entry that uses it.

The desktop tile now shows its delete on hover, on keyboard focus and
always where there is no hover, with a larger target there and an aria
label; viewers no longer get the button. The phone gallery gets the same
corner button for editors. Both ask through ConfirmDialog first, saying
that the photo also leaves the entries it is used in, and both delete
through the store action. The entry editor's photo controls follow the
same hover rule.

Refs #2593
2026-10-12 10:32:32 +02:00
Maurice 36b8baf259 fix(atlas): removing the last region keeps a country the user marked visited itself
Marking a region wrote its country with source 'manual', the same as ticking
the country off by hand, and removing the last region then took the country
away whatever its origin, Dawarich confirmations included. A country that
only comes in through a region is now stored as 'region', marking it visited
afterwards turns it into the user's own mark, and the cascade in unmarkRegion
only runs for a country without such a mark. Readers still see 'manual' for
those rows, so the country detail, the MCP resource and the plugin RPC answer
as before. Rows written before this change stay 'manual' and keep their
country.

REST, MCP and plugin RPC share the service. The atlas popup on desktop and
phone now asks the server whether the country is still marked before it
drops it from the map instead of guessing.

Refs #2597
2026-10-12 09:55:52 +02:00
Maurice b3fe593a1e fix(share): translate cost categories on the public trip page
The shared Costs tab grouped expenses by the stored category and printed it
as is, so the fixed keys ("accommodation", "flights") showed in English
whatever language the reader picked. It now groups through catMeta and
labels each group with costs.cat.*, the way the Costs tab does, so old
free-text labels also join their key instead of forming groups of their own.

Refs #2596
2026-10-12 09:38:19 +02:00
Maurice aa1bb41cf5 fix(collections): moving a place out of a list needs the same role as deleting it
Moving a saved place to another list takes it out of the source list, but
updatePlace only asked for edit rights there, so an editor could empty a
shared list they may not delete from. The source now takes owner or admin,
like a delete, and the target still takes edit rights. REST and the
update_collection_place tool share the service path. The Move to list
action on desktop and phone follows the delete permission.
2026-10-12 09:17:08 +02:00
Maurice 2b86d71d51 test(client): drop the mocks of the deleted server database service
server/src/nest/database/database.service no longer exists, so the five
vi.mock calls that guarded against importing it guarded nothing.
2026-10-10 21:31:33 +02:00
Maurice 33db4ea7cb fix(dashboard): the desktop currency widget always shows the rate for the currency picked last
Switching the from currency of the desktop dashboard currency widget quickly
could show the rate of the previous currency: when the older rate request
answered after the newer one, its answer overwrote the newer rates.

Cause: useCurrencyConverter only aborted a request still in flight in its
phone mode (abortStale true); the desktop dashboard passed false and fetched
without any stale guard.

Fix: the hook now always aborts the previous request when a new one starts
and when the widget goes away, and ignores answers of an aborted request. The
abortStale option only existed to keep the desktop without the guard, so it
is removed and both dashboards call useCurrencyConverter().

Red test: FE-COMP-FXHOOK-008 (useCurrencyConverter.test.ts) failed on the
unfixed code with "AssertionError: expected 1.1 to be 1.3".

Changed assertions:
- useCurrencyConverter.test.ts FE-COMP-FXHOOK-002: was "the desktop mode
  fetches without a signal, the phone mode with one" expecting the desktop
  call to be [url] only; now expects [url, { signal: AbortSignal }].
- FE-COMP-FXHOOK-003 no longer names the phone mode; its assertions are
  unchanged. All tests call the hook without the removed option.
2026-10-09 19:00:47 +02:00
Maurice d118423570 fix(journey): the desktop gallery Upload button shows the files counting up again
Uploading photos into a journey gallery on desktop gave no sign that
anything was happening until the toast at the end; the Upload button
stayed clickable the whole time. Up to v4.0.0 the button sat inside the
gallery and showed a spinner with "Uploading done/total" while it was
disabled. When the button moved up into the page header (onRegisterUpload)
that indicator was dropped, and the count kept being tracked with no
reader.

useGalleryUpload now also returns the progress it tracks, the gallery
hands it up through onUploadProgress into useJourneyDetail, and the
page's Upload button is disabled and shows the spinner with
journey.editor.uploadingProgress while the files go, as it did before.

Red before the fix: src/pages/JourneyDetailPage.wiring.test.tsx
FE-JRN-DETWIRE-043 failed with "expected undefined to be [Function
Mock]": the gallery was never given an onUploadProgress callback and
the button never showed a count. FE-JRN-GALLERY-021 and
FE-JRN-GALLERYUPLOAD-007 cover the gallery and the hook. No existing
assertions changed.
2026-10-09 19:00:45 +02:00
Maurice 49e618cbc7 fix(journey): hiding suggestions on desktop no longer throws when the preference save fails
On the desktop journey page, the eye toggle that hides the suggested
entries flipped the view and then saved the preference. When that save
was refused (offline, a server error) the promise rejected into a click
handler nothing awaited, leaving an unhandled rejection behind.

The phone already treats this as a view preference: it keeps the local
flip until the next load and swallows the failure on purpose. The
desktop toggle now does the same.

Red before the fix: src/pages/JourneyDetailPage.wiring.test.tsx
FE-JRN-DETWIRE-042 failed with "expected vi.fn() to not be called at
all, but actually been called 1 times" on the unhandledRejection
listener, called with [Error: offline]. No existing assertions changed.
2026-10-09 19:00:45 +02:00
Maurice e870270fb9 fix(planner): the plan view panel tabs say whether their panel is open and show a focus ring
In the plan view the tabs that collapse and reopen the left and right
panels gave a screen reader no open or closed state and showed no focus
ring when reached with the keyboard. The same tabs in the tour planner
had both, because only there LeftPanelTab got the "announced" option,
and the plan view's right tab was a hand copy of the left one.

LeftPanelTab becomes PanelTab with a side prop and always sets
aria-expanded and the focus ring. The plan view's right tab renders it
mirrored, so every panel tab shares one component. The offsets are
written with literal left and right keys so lint:rtl still counts them.
The page shrinks by 11 lines.

Red test: FE-PAGE-PLANNER-016b in client/src/pages/TripPlannerPage.test.tsx
failed on the old page with
expect(element).toHaveAttribute("aria-expanded", "true").
FE-PAGE-PLANNER-LEFTTAB-005 covers the mirrored right tab.

Changed assertions (they asserted the missing state):
- TripPlannerPage.leftPanelTab.test.tsx FE-PAGE-PLANNER-LEFTTAB-003:
  not.toHaveAttribute('aria-expanded') and not.toHaveClass
  ('focus-visible:outline') are now toHaveAttribute('aria-expanded',
  'true') and toHaveClass('focus-visible:outline') (title updated).
- TripPlannerPage.leftPanelTab.test.tsx FE-PAGE-PLANNER-LEFTTAB-004: the
  "announced" prop is dropped from both renders (title updated); the
  expectations are unchanged. The file renders PanelTab instead of
  LeftPanelTab.
2026-10-09 19:00:44 +02:00
Maurice 3fcfb12749 refactor(admin): share the fold head of the Google options and the TREK API card
Both folds on the settings page opened with the same summary line and
turning chevron. FoldSummary now draws it and each fold passes its own
label; the Google fold keeps its status pill.
2026-10-09 16:15:49 +02:00
Maurice 9f1d5c4a63 refactor(atlas): draw the country and place search rows with one row component
The country rows and the geocoded place rows repeated the same button,
hover tint and trailing chevron. A ResultRow inside AtlasCountrySearch
now draws that frame and each list passes its own leading content.
2026-10-09 16:15:49 +02:00
Maurice da37f3618d refactor(planner): share the left panel tab and the selected place props in the trip planner page
The plan view and the tour planner view each drew the left panel's tab in
full, and the place inspector and the tour dialog each listed the same props
twice, once beside the panels and once in the phone-width sheet.

LeftPanelTab, a small presentational component at the bottom of
TripPlannerPage.tsx, now draws the tab for both views. It stays in the page
file so the physical left and right offsets keep being counted there. The
tour planner's tab passes `announced`, which keeps its aria-expanded and its
focus ring; the plan view's tab still has neither.

The page body now builds selectedPlaceProps (what the inspector and the tour
dialog both take), placeInspectorProps and tourDetailProps once and spreads
them. What differs stays at each call site: the desktop inspector's
onOpenBooking and panel widths, the sheet's edit and delete closing the
sheet, the desktop tour dialog's non-modal focus return and widths, and
canEdit and canAssign on every tour dialog.
2026-10-09 16:15:48 +02:00
Maurice a0a4a24395 refactor(admin): share the invite link status between desktop and phone
Whether an invite is expired, used up or active, and which status label it shows, was worked out in both user views. It now lives in inviteStatus in the admin model; each view keeps its own row markup.
2026-10-09 15:19:51 +02:00
Maurice b598b97865 refactor(planner): share the trip sheet wiring between desktop and phone
The phone trip sheet host wrote out by hand three pieces of planner
wiring the desktop planner already had.

useBookingExpenseEditor now holds the expense editor both planners open
over the trip: the booking request state, the receipt fallback, the base
currency, the current user and the save that reloads the budget.
TripPlannerPage and MTripSheets both read it.

applyTripCoverUpdate patches a new trip cover into the store for the
trip form on both sides.

The transport editor and the transit route change moved into
openTransportEditorWith and changeTransitRouteWith, which take the
planner's setters. usePlannerDialogs builds openTransportEditor and
changeTransitRoute on them, and the phone sheet calls the same helpers
on the planner it receives. There are no differences between the two
views to keep as options.
2026-10-09 15:19:51 +02:00
Maurice 18eeb16aa0 refactor(dashboard): share the widget logic and plugin hooks between desktop and phone
The currency converter, the world clocks, the collection lists, the plugin widgets and card badges and the card date format each existed once per dashboard. They now live in useCurrencyConverter, useDashboardTimezones, useCollectionLists, useDashboardPlugins and dashboardModel; the phone keeps aborting a pending rate request through an option.
2026-10-09 15:19:50 +02:00
Maurice 8e95b4c7b6 refactor(journey): share the entry editor logic between desktop and phone
useJourneyEntryForm holds the fields, the photo queue that only goes out on
save, the gallery links, the location search and "use my location", the
verdict rows, quick capture and the save for both the editor dialog and the
entry sheet. journeyWeatherCategory moves to components/Journey/journeyWeather
so the dialog no longer reaches into mobile/. Where the two differed they still
do: the dialog starts with a blank verdict row, counts a moved point as a
change, toasts a failed save or location and fills the weather from the
forecast; the sheet edits tags and shows a refused location under the field.
2026-10-09 15:19:49 +02:00
Maurice e40bc98a33 refactor(atlas): share the country popup actions between desktop and phone
useAtlasCountryActions marks a country or a region, unmarks a region, adds the
country or region to the bucket list and takes the country off it again for
both the desktop dialog and the phone sheet. The desktop dialog moves into its
own component in AtlasPage so the page body keeps calling useAtlas only. The
phone sheet keeps storing a marked region as visited and its own month input;
the desktop keeps its month and year picker in useAtlas.
2026-10-09 15:19:49 +02:00
Maurice 3b4539f600 refactor(settings): share the integration and plugin tab gating between desktop and phone
The addon flags, the managed install flag and the addon reload of the integrations tab now come from one useIntegrationGates hook, and useSettings hands both shells the plugins tab flag next to the integrations one.
2026-10-09 15:19:47 +02:00
Maurice 6c5ab5414a refactor(admin): share the JWT rotation and passkey reset between desktop and phone
useAdminUserActions now rotates the JWT secret and resets a user's passkeys for the desktop dialogs and the phone sheets. Each shell keeps its own confirm step, and the phone sheet still stays busy until the reset settles.
2026-10-09 15:19:47 +02:00
Maurice feb99ce398 refactor(admin): share the admin settings saves and the TREK API lists between desktop and phone
useAdminSettingsActions now holds the OIDC and file type saves and the five place switches, writing through the admin bag both shells already receive. trekApiModel keeps the TREK Places API fields, facts and sources the desktop card and the phone block list.
2026-10-09 15:19:46 +02:00
Maurice 8c8069e983 refactor(admin): share the admin shell actions between desktop and phone
Saving the demo baseline and the bag tracking and collab feature switches now live in useAdmin. AdminPage and the phone admin screen pass them on instead of carrying their own inline copies.
2026-10-09 15:19:46 +02:00