Skip to content

iOS: add a new person straight from the crew/passenger picker - #34

Merged
roznet merged 1 commit into
mainfrom
feat/picker-add-person
Sep 26, 2026
Merged

roznet merged 1 commit into
mainfrom
feat/picker-add-person

Conversation

@roznet

@roznet roznet commented Sep 26, 2026

Copy link
Copy Markdown
Owner

Closes #32

What changes for the pilot

  • The crew/passenger picker (Flight → Edit Crew & Passengers, and the people step of New Flight) has a (+) with Add Person, Scan Document and Import from Contact, the same options as the People tab (no CSV).
  • The person each ends with goes straight onto the flight: a passenger, or crew if they're usual crew. That includes an existing person the scan matched or the contact was merged into. The picker stays open.
  • Add Person and Contact open the person editor inside the picker (a contact brings no passport). A scan has already filled the name and document, so it doesn't open the editor.
  • When the search finds nobody: Add “Jane Zztest” as new person.
  • Backing out of Add Person without typing leaves nobody behind, in the picker and on the People tab (which leaked an empty person before).

How

  • Views/AddPersonMenu.swift: AddPersonMenuItems + .addPersonFlows(request:onPerson:) now hold the flows that were inside PeopleListView, including the macOS image/PDF scan. PeopleListView keeps CSV import/export.
  • Sheet hand-off: the contact picker, scan sheet, ContactResolveView and MRZResultActionView all call back before dismissing. The flows present the next step, or report the person, from onDismiss, because a presentation or push made while a sheet is still leaving is silently dropped. This matters most inside the picker's own sheet.
  • Person.isBlank (no name, DoB, contact details, place of birth or documents). The picker only removes a person it created, never one reached by a match or merge. Its swipe-away check sits on the NavigationStack, not the root list, because the root also disappears when the editor is pushed. The first UI run caught exactly that, when it was on the root.
  • One new string with draft fr/de/es (needs_review). designs/ios-app.md has a new Adding People section.

Testing

  • Unit: new AddPersonTests (8 tests: isBlank, discard rule, name split); the whole flyfun-formsTests target passes on iOS.
  • XCUI, run locally on iPhone 17 (CI doesn't run it): the full suite, 11/11 pass, including two new journeys:
    • testAddPassengerFromPeoplePicker: (+) → Add Person → type a name → back → selected as Passenger → Done → listed on the flight.
    • testPeoplePickerDiscardsBlankAndAddsSearchedName: blank person backed out → gone; searched name → added, prefilled, saved in People, no empty row left.
  • macOS app builds.
  • Not covered automatically: the Scan (camera) and Contact paths, which XCUI can't drive (camera / system contact picker). Worth one pass by hand on a device: scan a passport from the picker, and import a contact from the picker.

🤖 Generated with Claude Code

Someone not in the app yet meant leaving the flight, creating them under
People, and coming back to pick them. The picker now has a (+) with the same
Add Person, Scan Document and Import from Contact as the People tab; the
person it ends with, new or matched to someone already there, goes straight
into the selection as a passenger (crew if they are usual crew). Add Person
and a contact open the editor inside the picker, since both still need a
document; a scan has filled that in, so it doesn't. A search that finds
nobody offers to add them under the name typed.

The three flows move out of PeopleListView into AddPersonMenu, so the People
tab and the picker share one copy, including the macOS file-scan path. They
now hand over a person, or present the next sheet, only once the sheet before
has dismissed: every one of those sheets calls back first, and a push or
presentation made while a sheet is still leaving is dropped.

Backing out of Add Person without typing anything left an empty person in
People, and in the picker would have put them on the flight. Person.isBlank
now lets both take such a person away again; the picker only ever removes one
it created itself.

Closes #32

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Sep 26, 2026

Copy link
Copy Markdown

Code Review

Reviewed the diff, designs/ios-app.md, and the surrounding sheet/navigation code (AddPersonMenu.swift, PeoplePickerView.swift, PeopleListView.swift, ContactImportView.swift, Person.swift). No CLAUDE.md exists in this repo to check against.

Traced the blank-person lifecycle in detail (isBlank, discardIfBlank, the onChange/onDisappear pair on PeoplePickerView's NavigationStack, and the deferred sheet hand-off via onDismiss) looking for double-delete, dropped-presentation, and leaked-blank-person scenarios. Didn't find a case where a created-but-abandoned person survives, or where a real one gets discarded — the createdPersonID/editingPerson tracking correctly limits deletion to persons the picker itself created (never a scan match or contact merge), and the onDisappear placement on the stack rather than its root avoids the false-positive the PR description mentions catching during manual testing.

The one edge case noted (a contact "Create as New Person" that comes from a contact with no name/phone/email/address/DOB isn't tracked for blank-discard the way Add Person is) is unlikely enough in practice and mirrors pre-existing contact-import behavior, so not flagging it as a blocking issue.

No high-confidence bugs, design deviations, or correctness issues found. Approving.

@roznet
roznet merged commit 83e47fd into main Sep 26, 2026
3 of 4 checks passed
@roznet
roznet deleted the feat/picker-add-person branch September 26, 2026 12:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

iOS: add a new person (blank, scan, contact) straight from the crew/passenger picker

1 participant