Skip to content

feat(web): inline edit mode on playlist detail page with staged Apply#14322

Open
dylanjeffers wants to merge 1 commit into
claude/duplicate-copy-tracksfrom
claude/inline-edit-mode
Open

feat(web): inline edit mode on playlist detail page with staged Apply#14322
dylanjeffers wants to merge 1 commit into
claude/duplicate-copy-tracksfrom
claude/inline-edit-mode

Conversation

@dylanjeffers
Copy link
Copy Markdown
Contributor

Summary

Brings playlist detail-page editing inline per the new UX spec. The existing /edit route still works for advanced fields (audience, price, genre, etc.), but the common metadata flow — title, description, visibility, artwork — is now handled directly on the detail page with a staged Apply / Discard model and remote-change conflict detection.

Stacked on #14321#14320#14319#14318.

Implementation

  • State: new PlaylistEditModeProvider context holds isEditMode, the staged metadata draft, hasChanges, save status (idle / saving / conflict), and an editModeLoadedAt timestamp for conflict detection. The matching usePlaylistEditMode hook returns a no-op shape when not inside a provider so shared components like CollectionHeader stay backwards-compatible everywhere else they're used.
  • Detail page: desktop CollectionPage is wrapped in the provider. A sticky PlaylistEditModeBar renders at the page footer in three states:
    • Edit mode active, no pending changes → slim discard footer.
    • Edit mode active, pending changes → Discard / Apply pair (Apply shows loading state during the save).
    • Conflict detected → banner with a Reload action that exits edit mode and reloads.
  • EditButton: the pencil in the owner action row now toggles inline edit mode instead of routing to /edit. The legacy /edit link still works at the URL level and the button keeps the legacy behavior when no provider is mounted.
  • Header: title, description, and visibility become inline-editable.
    • TextInput for title (with autoFocus on entering edit mode, 64-char max).
    • TextArea for description (1000-char max, grows, char counter).
    • Switch for visibility — checked = Public, unchecked = Hidden.
  • Artwork: clicking "Change Artwork" in edit mode opens a native file picker. The selected file is resized via the existing resizeImage pipeline and previewed immediately; on Apply it's sent through as part of the edit payload.
  • Apply / conflict detection: Apply compares collection.updated_at to the editModeLoadedAt timestamp captured when the user entered edit mode. If updated_at has advanced, the bar flips to the conflict state and aborts — the user clicks Reload to get fresh data.
  • Specific success toasts: "Saved details", "Saved artwork", or "Saved details and artwork" depending on which fields the user actually changed.

Notes / scope

  • Track curation (multi-select, undo/redo, copy URLs) is deferred to the next PR in the chain — Apply currently saves metadata only.
  • The full /edit page is intentionally kept; this PR doesn't remove or redirect it.

Test plan

  • Visit your playlist detail page as the owner.
  • Click the pencil ✏️ in the action row → inline title input, description textarea, and visibility switch appear in the header. Sticky footer shows "Discard / Apply" (Apply disabled until changes).
  • Change the title → Apply enables → click Apply → toast reads "Saved details" → title updates and edit mode exits.
  • Re-enter edit mode → change description and toggle visibility → Apply → toast still "Saved details".
  • Click "Change Artwork" on the cover → pick a new image → preview replaces the old image immediately → Apply → toast "Saved artwork".
  • Change title AND artwork in one session → Apply → toast "Saved details and artwork".
  • Discard wipes the draft and exits edit mode.
  • In a second tab, edit the same playlist's title and Apply. Switch back to the first tab (still in edit mode). Apply → bar flips to the conflict state → Reload exits edit mode.
  • Visit a playlist you don't own → no pencil, no inline editing, header behaves as before.
  • /edit URL still loads the existing advanced editor.

🤖 Generated with Claude Code

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 15, 2026

⚠️ No Changeset found

Latest commit: ba2fa57

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Brings playlist detail-page editing inline per the new UX spec. The
existing /edit route still works for advanced fields (audience,
price, genre, etc.), but the common metadata flow is now handled
directly on the detail page.

- New `PlaylistEditModeProvider` context holds the edit-mode flag,
  the staged metadata draft, conflict status, and saving status. The
  matching `usePlaylistEditMode` hook safely returns a no-op shape
  when not inside the provider, so shared components stay
  backwards-compatible.
- Wrapped the desktop CollectionPage in the provider and rendered a
  sticky `PlaylistEditModeBar` at the page footer. The bar shows a
  Discard / Apply pair when there are pending changes, a slim "no
  changes yet" footer while in edit mode without changes, and a
  conflict banner with a Reload action when the playlist was changed
  remotely since edit mode started.
- The `EditButton` pencil in the owner action row now toggles inline
  edit mode instead of routing to /edit (the legacy link is kept as
  a fallback when no provider is mounted).
- CollectionHeader (desktop) renders an inline `TextInput` for the
  title, a `TextArea` for the description, and a `Switch` for
  visibility while in edit mode. Otherwise behavior is unchanged.
- Desktop Artwork supports inline upload (file picker) when edit
  mode is on; the staged image previews immediately and is sent
  through on Apply along with the metadata draft.
- Apply checks the collection's `updated_at` against the timestamp
  captured when edit mode started; if it has advanced, the bar
  flips to the conflict state and aborts the save.
- Success messages are specific ("Saved details", "Saved artwork",
  or "Saved details and artwork") based on which fields the user
  changed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@dylanjeffers dylanjeffers force-pushed the claude/inline-edit-mode branch from 10295c5 to ba2fa57 Compare May 15, 2026 18:12
@github-actions
Copy link
Copy Markdown
Contributor

🌐 Web preview ready

Preview URL: https://audius-web-preview-pr-14322.audius.workers.dev

Unique preview for this PR (deployed from this branch).
Workflow run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant