SoulSync Discovery tab: open mirror detail modal after refresh
Phase 1c.3 left the click flow at "card shows 'mirrored' + toast",
which felt incomplete — Tidal / LB / Last.fm all open a follow-up
modal after their discovery flow so the user can act on the
results (sync to server playlist, queue downloads, etc.). SoulSync
Discovery skips the discovery phase (tracks pre-matched), so the
natural analog is the mirrored-playlist detail modal — same one
the Mirrored tab opens when you click a row.
- Inline ``fetch('/api/mirror-playlist', ...)`` in place of the
fire-and-forget ``mirrorPlaylist`` helper so we can capture
the returned ``playlist_id`` from the response.
- After successful mirror creation, call
``openMirroredPlaylistModal(playlist_id)`` (exposed by
stats-automations.js) to surface the tracks view.
The card itself keeps the ``♪ N / ✓ N / mirrored`` progress text
so a quick second click can re-refresh without re-opening the
modal each time (just re-runs the generator + re-upserts the
mirror).
This commit is contained in:
parent
bd91c94f92
commit
a8e6432e86
1 changed files with 41 additions and 12 deletions
|
|
@ -181,19 +181,37 @@ async function handleSoulsyncDiscoverySyncCardClick(kind, variant, name, cardEl)
|
|||
};
|
||||
});
|
||||
|
||||
if (typeof mirrorPlaylist === 'function') {
|
||||
mirrorPlaylist(
|
||||
'soulsync_discovery',
|
||||
syntheticId,
|
||||
finalName,
|
||||
mirrorTracks,
|
||||
{
|
||||
owner: 'SoulSync',
|
||||
description: `Personalized ${kind}${variant ? ' · ' + variant : ''} — regenerates on Auto-Sync refresh.`,
|
||||
image_url: '',
|
||||
},
|
||||
);
|
||||
// POST inline so we can capture the returned mirrored_playlists
|
||||
// row id and open the detail modal afterward. ``mirrorPlaylist``
|
||||
// (in stats-automations.js) is fire-and-forget and doesn't
|
||||
// surface the id, which the next step needs.
|
||||
const normalizedTracks = mirrorTracks.map(t => ({
|
||||
track_name: t.track_name || '',
|
||||
artist_name: t.artist_name || '',
|
||||
album_name: t.album_name || '',
|
||||
duration_ms: t.duration_ms || 0,
|
||||
image_url: t.image_url || null,
|
||||
source_track_id: t.source_track_id || '',
|
||||
extra_data: t.extra_data || null,
|
||||
}));
|
||||
const mirrorResp = await fetch('/api/mirror-playlist', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
source: 'soulsync_discovery',
|
||||
source_playlist_id: syntheticId,
|
||||
name: finalName,
|
||||
tracks: normalizedTracks,
|
||||
description: `Personalized ${kind}${variant ? ' · ' + variant : ''} — regenerates on Auto-Sync refresh.`,
|
||||
owner: 'SoulSync',
|
||||
image_url: '',
|
||||
}),
|
||||
});
|
||||
const mirrorData = await mirrorResp.json();
|
||||
if (!mirrorData.success) {
|
||||
throw new Error(mirrorData.error || 'Mirror creation failed');
|
||||
}
|
||||
const mirroredId = mirrorData.playlist_id;
|
||||
|
||||
if (progEl) {
|
||||
progEl.textContent = `♪ ${tracks.length} / ✓ ${mirrorTracks.length} / mirrored`;
|
||||
|
|
@ -219,6 +237,17 @@ async function handleSoulsyncDiscoverySyncCardClick(kind, variant, name, cardEl)
|
|||
if (typeof showToast === 'function') {
|
||||
showToast(`Mirrored '${finalName}' with ${mirrorTracks.length} tracks`, 'success');
|
||||
}
|
||||
|
||||
// Open the mirrored-playlist detail modal so the user lands on
|
||||
// the tracks view + can trigger sync / download from there.
|
||||
// Same flow the Mirrored tab uses when clicking a row.
|
||||
if (mirroredId && typeof openMirroredPlaylistModal === 'function') {
|
||||
try {
|
||||
await openMirroredPlaylistModal(mirroredId);
|
||||
} catch (e) {
|
||||
console.warn('Could not open mirrored playlist detail:', e);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
if (btn) {
|
||||
btn.disabled = false;
|
||||
|
|
|
|||
Loading…
Reference in a new issue