Skip to content

BDMS-932: Add contact edit panel#306

Open
jeremyzilar wants to merge 29 commits into
stagingfrom
BDMS-932-contacts-edit-panel
Open

BDMS-932: Add contact edit panel#306
jeremyzilar wants to merge 29 commits into
stagingfrom
BDMS-932-contacts-edit-panel

Conversation

@jeremyzilar

Copy link
Copy Markdown
Contributor

Closes BDMS-932

Summary

Adds an inline edit panel to the Contact show page, matching the pattern established on the Wells show page. Editors can open the panel, make changes, and save without leaving the page.

API changes: This PR depends on a fix in the API repo. See Fix TypeError crash when auth dependency returns True in local dev.

What changed

Edit panel

  • New ContactEditPanel component that opens as a side panel on the Contact show page, using the same EditPanel / EditPanelLayout / EditPanelSection pattern as Wells
  • Editable fields: Contact Type, Role, Name, Organization, phone numbers, email addresses, and addresses
  • Save requires at least one field to have changed (Save button is disabled otherwise)
  • Unsaved changes trigger a confirmation dialog before the panel can be closed
  • After a successful save the show page immediately refetches so the displayed data updates without a page reload

Field details

  • Contact Type, Role, Organization: Shadcn Select components backed by lexicon terms
  • Organization: Nullable. A "No organization" option at the top of the dropdown allows clearing the field. Note: new organizations cannot be added through the UI — they are lexicon terms and must be added at the database level or via a future admin tool
  • Phone numbers: Fixed +1 country code prefix, auto-formats to (XXX) XXX-XXXX, validates 10 digits on save. Add and delete supported
  • Email addresses: Validates format on save. Add and delete supported
  • Addresses: Full address fields with a US state dropdown defaulting to NM. Add and delete supported
  • Validation errors appear below the field after it loses focus (not on every keypress). Save is disabled while any field has a validation error

Routing and navigation cleanup

  • Removed the old standalone Contact create and edit pages and routes (replaced by the inline panel)
  • Removed the old Well full-page edit route (also replaced by the inline panel, already done on Wells)
  • Removed the Create button from the Contacts list page

Analytics

  • PostHog events track the edit panel lifecycle for both Contacts and Wells: edit_panel_opened, edit_abandoned, edit_saved
  • These events are designed to work as a funnel in PostHog

Bug fixes

  • Fixed useLexicon truncating dropdown options for large categories (e.g. Role had 20 terms but only 10 were loading). Set pageSize: 500 so all terms are fetched
  • Fixed the edit panel left border not extending to the bottom of the page when content overflowed. Added overflow-y-auto to the content area so the panel scrolls internally
  • Fixed the Contact show page not updating after a save. Added an onSaved callback that calls query.refetch() directly on the useShow query

Tests

  • Unit tests for ContactEditPanel covering: field editing, save/cancel, validation UX (blur-triggered errors, Save disabled on invalid input), email/phone add and delete, address add and delete
  • Unit tests for WellEditPanel
  • New useLexicon pagination included in test mocks

Test plan

  • Open a contact, click Edit, change the name, save. Confirm the show page updates immediately
  • Open a contact, add a phone number, save. Confirm it appears on the show page
  • Open a contact, set Organization to "No organization", save. Confirm it clears
  • Open a contact, make a change, click the close button. Confirm the unsaved changes dialog appears
  • Confirm a Viewer-role user does not see the Edit button
  • Run npm run test and confirm all ContactEditPanel and WellEditPanel tests pass

New edit panel for the Contact show page, matching the existing WellEditPanel pattern.
Allows editing name, organization, role, and contact_type via a slide-in panel.
Uses Shadcn Input and Select, EditPanel/EditPanelSection/EditPanelField layout,
and an AlertDialog for discard-changes confirmation. Saves via PATCH /contact/{id}
and invalidates the contact detail and list queries on success.
Replaces the suppressed headerButtons with an Edit button that toggles a
ContactEditPanel slide-in panel, matching the Wells show page pattern exactly.
Uses useSidebarPanelSync so the sidebar collapses when the panel opens.
Edit button is only shown to users with AMPEditor or AMPAdmin role.
Creating contacts is handled elsewhere. Removes the + Create button and cleans
up the unused useNavigation and Button imports.
Contact editing now happens in the inline ContactEditPanel on the show page,
so the edit and create resource actions are no longer needed. Also removes
the well edit resource action since WellEditPanel replaced the full-page edit
route.
ContactEdit and ContactCreate pages are no longer reachable now that
editing is done via the inline panel and creating contacts is not a
supported flow from the UI. WellEdit full-page route is removed because
WellEditPanel is the current standard editing interface for wells.
These pages are no longer registered in routes or resources. Contact editing
now happens in ContactEditPanel. Well editing uses WellEditPanel. The barrel
index files are updated to remove the deleted exports.
Fires edit_panel_opened on mount, edit_saved on successful patch (with
fields_changed list), and edit_abandoned when the user discards changes
(with had_changes flag). Events carry resource='contact' and contact_id
so they can be filtered alongside well events in a shared funnel.
Fires edit_panel_opened on mount, edit_saved on successful group save,
and edit_abandoned when the user discards changes. Matches the contact
edit events shape so both resources appear in the same funnel using a
resource property filter.
Registers DOM matchers like toBeDisabled and toHaveTextContent globally
so they are available across all test files.
18 tests covering: PostHog funnel events (edit_panel_opened, edit_saved,
edit_abandoned), panel title display, field pre-population from the contact
prop, save button enabled/disabled state, useUpdate called with only changed
fields, cache invalidation after save, and the full close/discard dialog flow
including keep-editing cancellation.
17 tests covering: PostHog funnel events (edit_panel_opened, edit_saved,
edit_abandoned), panel title display, assigned groups rendered as chips,
empty state message, save button enabled/disabled state, delete mutation
called for removed groups, well details invalidated after save, and the
full close/discard dialog flow including keep-editing cancellation.
Added three new collapsible sections to the contact editing panel. Each
section lets users add new items, edit existing ones, and delete them.
All sub-resource changes (POST/PATCH/DELETE) are batched and run in
parallel on save. Updated tests to cover the new sections — 40 tests
total, all passing.
Expanded the test suite from 18 to 40 tests. New tests cover rendering
existing sub-resources, adding new rows, deleting existing items, and
verifying the correct POST/PATCH/DELETE mutations are sent on save.
Phone numbers now display as (XXX) XXX-XXXX with a fixed +1 country
code prefix. Typing auto-formats to that pattern and saves as E.164
(+1XXXXXXXXXX) to the API. Email fields show an inline error for
invalid formats while typing. Both email and phone validation block
Save if any value is malformed.
Error messages now always occupy their line in the layout (invisible
when not erroring) so nothing jumps when a message appears. Each error
element has a proper id, aria-describedby on its input, and role=alert
so screen readers announce it. Save is disabled whenever any email or
phone value is invalid, so users know to fix the field before trying
to save.
…eSize 500

Lexicon categories like 'role' have 20+ terms. The default page size
of 10 silently cut off options like 'Owner' (11th alphabetically),
causing dropdowns to show blank for valid stored values.
Added min-h-0 and overflow-y-auto to the content area so the panel
scrolls internally instead of pushing the page. This keeps the left
border at full height regardless of content length.
Organization is a foreign key to lexicon_term in the API, so free text
caused 409 Conflict errors on save. Replaced with a Select populated by
useLexicon({ category: 'organization' }), with a No organization option
at the top for clearing the field.

Also adds an onSaved callback prop so the show page can trigger a refetch
after a successful save, fixing stale data after the panel closes.
Passes query.refetch() as onSaved to ContactEditPanel so the show page
immediately reloads with updated data when the panel closes after a save.
Updates org field tests to use selectOptions now that the field is a
Select instead of a text input. Adds tests for the blur-triggered
validation UX on email and phone: errors should not appear while typing,
only after the field loses focus, and Save should be disabled when
a field is invalid.
GROUP_ALPHA and GROUP_BETA were missing the required created_at property
from the IGroup interface, causing a TypeScript error in CI.
@github-actions

Copy link
Copy Markdown

Preview Deployment

Preview URL: https://preview-bdms-932-contacts-edit-panel-auejgdbofq-uc.a.run.app

Note: This preview uses the staging API endpoints.

@jeremyzilar

Copy link
Copy Markdown
Contributor Author

On staging, it takes a really long time for all the available data to load into the editing UI. I am not sure how to make that faster yet.

image

@jeremyzilar

Copy link
Copy Markdown
Contributor Author

Also note that Organizations are a dropdown because:

new organizations cannot be added through the UI — they are lexicon terms and must be added at the database level or via a future admin tool

image

dark:border-input (zinc-800) was nearly the same tone as the dark
background (zinc-900), making the border disappear. Removed the dark
mode override so border-border (zinc-700) applies in both themes, which
matches what other bordered elements like the PDF button group use.
@github-actions

Copy link
Copy Markdown

Preview Deployment

Preview URL: https://preview-bdms-932-contacts-edit-panel-auejgdbofq-uc.a.run.app

Note: This preview uses the staging API endpoints.

1 similar comment
@github-actions

Copy link
Copy Markdown

Preview Deployment

Preview URL: https://preview-bdms-932-contacts-edit-panel-auejgdbofq-uc.a.run.app

Note: This preview uses the staging API endpoints.

@chasetmartin

Copy link
Copy Markdown
Collaborator

This is looking really nice! I mainly have a code architecture question for the whole team that seems relevant @TylerAdamMartinez @jeremyzilar @jirhiker :

Should we adopt schema validators (Zod/Yup) for edit panels like this?

ContactEditPanel already uses interfaces + helper functions for validation and builds save payloads manually. We codegen Zod from OpenAPI but don't use it in the UI layer at all right now (and auto generation is probably not the best approach to this).

Do we want to keep this implementation as the convention, or move toward schema validators (Zod/Yup) for form validation and save-time payload checks?

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.

2 participants