BDMS-932: Add contact edit panel#306
Conversation
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.
…me line as the input and type dropdown
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.
Preview DeploymentPreview URL: https://preview-bdms-932-contacts-edit-panel-auejgdbofq-uc.a.run.app Note: This preview uses the staging API endpoints. |
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.
Preview DeploymentPreview URL: https://preview-bdms-932-contacts-edit-panel-auejgdbofq-uc.a.run.app Note: This preview uses the staging API endpoints. |
1 similar comment
Preview DeploymentPreview URL: https://preview-bdms-932-contacts-edit-panel-auejgdbofq-uc.a.run.app Note: This preview uses the staging API endpoints. |
|
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? |


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
ContactEditPanelcomponent that opens as a side panel on the Contact show page, using the sameEditPanel/EditPanelLayout/EditPanelSectionpattern as WellsField details
Routing and navigation cleanup
Analytics
edit_panel_opened,edit_abandoned,edit_savedBug fixes
useLexicontruncating dropdown options for large categories (e.g. Role had 20 terms but only 10 were loading). SetpageSize: 500so all terms are fetchedoverflow-y-autoto the content area so the panel scrolls internallyonSavedcallback that callsquery.refetch()directly on theuseShowqueryTests
ContactEditPanelcovering: field editing, save/cancel, validation UX (blur-triggered errors, Save disabled on invalid input), email/phone add and delete, address add and deleteWellEditPaneluseLexiconpagination included in test mocksTest plan
npm run testand confirm all ContactEditPanel and WellEditPanel tests pass