Skip to content

Commit 6a96ab8

Browse files
dylanjeffersclaude
andcommitted
Modals: wire nice-modal bridge saga + bridge createModal opens
Two fixes to the Wave D modal bridge that previously left several modals unable to open: 1. The bridge saga (`niceModalBridgeSagas`) was defined in `common` but never spawned by web or mobile rootSagas, so even the existing `setVisibility(id, true) → showNiceModal(id)` translation was dead code. Add it to both rootSagas and re-export from `@audius/common/services` so consumers can import it directly. 2. createModal-driven modals (LeavingAudiusModal, ArtistPickModal, etc.) open via `useFooModal().onOpen()` which dispatches `modals/{id}/open` — not the parent `setVisibility`. The bridge only listened for `setVisibility`, so these modals never reached `showNiceModal`. Add `watchOpenViaCreateModal` that matches the generic `modals/{id}/(open|close|closed)` action shape and bridges to `showNiceModal` / `hideNiceModal` when the id is in the registry. Together this restores Wave D's NiceModal-managed modals and unblocks migrating the remaining createModal-based modals in subsequent waves. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 7e18de0 commit 6a96ab8

4 files changed

Lines changed: 52 additions & 15 deletions

File tree

packages/common/src/services/nice-modal-bridge/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,5 @@ export const registerNiceModalId = (id: string) => {
7070
}
7171

7272
export const isNiceModalId = (id: string): boolean => niceModalIds.has(id)
73+
74+
export { default as niceModalBridgeSagas } from './sagas'
Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,41 @@
1+
import { Action } from '@reduxjs/toolkit'
2+
import { takeEvery as untypedTakeEvery } from 'redux-saga/effects'
13
import { takeEvery, call } from 'typed-redux-saga'
24

35
import { setVisibility } from '~/store/ui/modals/parentSlice'
46

5-
import {
6-
hideNiceModal,
7-
isNiceModalId,
8-
showNiceModal
9-
} from './index'
7+
import { hideNiceModal, isNiceModalId, showNiceModal } from './index'
108

119
/**
12-
* Bridge saga: translates legacy redux-driven `setVisibility(id, true|false)`
13-
* actions into `showNiceModal(id)` / `hideNiceModal(id)` for any modal id
14-
* that has registered itself via `registerNiceModalId(...)`.
10+
* Bridge saga: translates legacy redux-driven modal trigger actions into
11+
* `showNiceModal(id)` / `hideNiceModal(id)` for any modal id that has
12+
* registered itself via `registerNiceModalId(...)`.
13+
*
14+
* Two trigger shapes need to bridge:
15+
*
16+
* 1. `parentSlice.setVisibility({ modal, visible })` — used by hand-written
17+
* trigger sites that dispatch directly against the parent registry.
18+
*
19+
* 2. `modals/{reducerPath}/open` — emitted by the per-modal hooks created
20+
* by `createModal()`. e.g. `useLeavingAudiusModal().onOpen({ link })`
21+
* dispatches `modals/LeavingAudiusModal/open`. We watch this generic
22+
* action shape so createModal-driven modals migrate without editing
23+
* every trigger site.
1524
*
1625
* This lets NiceModal-managed modals coexist with the legacy modal registry
17-
* — every existing trigger site that dispatches `setVisibility` keeps
18-
* working unchanged, and migrating a modal to NiceModal becomes:
26+
* — every existing trigger site keeps working unchanged, and migrating a
27+
* modal to NiceModal becomes:
1928
* 1. Wrap with `NiceModal.create(...)`
20-
* 2. `NiceModal.register('X', Component)`
21-
* 3. `registerNiceModalId('X')`
22-
* 4. Add a side-effect import to `registerNiceModals.ts`
23-
* 5. Remove from web `Modals.tsx` / mobile `Drawers.tsx` (avoid double-mount)
29+
* 2. `NiceModal.register('X', Component)` + `registerNiceModalId('X')`
30+
* 3. Side-effect import in `registerNiceModals.ts`
31+
* 4. Remove from web `Modals.tsx` / mobile `Drawers.tsx` (avoid double-mount)
2432
*
2533
* Once every caller has been moved to call `showNiceModal` directly, this
2634
* bridge can be deleted.
2735
*/
36+
37+
const CREATE_MODAL_ACTION_RE = /^modals\/(.+)\/(open|close|closed)$/
38+
2839
function* watchOpenViaSetVisibility() {
2940
yield takeEvery(
3041
setVisibility,
@@ -43,6 +54,26 @@ function* watchOpenViaSetVisibility() {
4354
)
4455
}
4556

57+
function* watchOpenViaCreateModal() {
58+
// Match every action and filter inside. We use plain redux-saga's
59+
// `takeEvery('*', ...)` here because typed-redux-saga's takeEvery typings
60+
// and runtime path don't reliably accept the wildcard pattern.
61+
yield untypedTakeEvery('*', function* (action: Action) {
62+
if (typeof action?.type !== 'string') return
63+
const match = action.type.match(CREATE_MODAL_ACTION_RE)
64+
if (!match) return
65+
const [, modalId, kind] = match
66+
if (!isNiceModalId(modalId)) return
67+
if (kind === 'open') {
68+
yield call(showNiceModal, modalId)
69+
} else {
70+
// 'close' / 'closed' — NiceModal owns its own exit animation, so
71+
// just hide. modal.remove() is called automatically.
72+
yield call(hideNiceModal, modalId)
73+
}
74+
})
75+
}
76+
4677
export default function niceModalBridgeSagas() {
47-
return [watchOpenViaSetVisibility]
78+
return [watchOpenViaSetVisibility, watchOpenViaCreateModal]
4879
}

packages/mobile/src/store/sagas.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { niceModalBridgeSagas } from '@audius/common/services'
12
import {
23
buyUSDCSagas,
34
castSagas,
@@ -82,6 +83,7 @@ export default function* rootSaga() {
8283
...stripeModalUISagas(),
8384

8485
...modalsSagas(),
86+
...niceModalBridgeSagas(),
8587

8688
// Pages
8789
...trackPageSagas(),

packages/web/src/store/sagas.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { niceModalBridgeSagas } from '@audius/common/services'
12
import {
23
buyUSDCSagas,
34
castSagas,
@@ -80,6 +81,7 @@ export default function* rootSaga() {
8081
trackPageSagas(),
8182

8283
modalsSagas(),
84+
niceModalBridgeSagas(),
8385

8486
// Cache
8587
collectionsSagas(),

0 commit comments

Comments
 (0)