Podcast workflow: episodes start manually via Start new episode (name, season, ep #); scripts no longer create entries; v2.17.0
Publish Container / build (push) Successful in 16m42s

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
nmemmertandClaude Sonnet 5.5 committed 2026-10-12 08:33:23 -04:00
1 parent 3a69e03e60
commit 326838e5bc
4 files changed
+55 -38

No files matched your search

+32 -13
View File
@@ -1820,7 +1820,6 @@ interface PodcastWorkflowItem {
released: boolean
releaseDate?: string
spotifyUrl?: string
hasScript?: boolean
planned?: boolean
state: PodcastWorkflowState
}
@@ -1833,6 +1832,8 @@ function PodcastWorkflowAdmin({ laneA, laneB }: { laneA: { title: string }; lane
const [lane, setLane] = useState<'A' | 'B' | 'other'>('A')
const [selectedKey, setSelectedKey] = useState('')
const [showReleased, setShowReleased] = useState(false)
const [starting, setStarting] = useState(false)
const [newSeason, setNewSeason] = useState('')
const [newNumber, setNewNumber] = useState('')
const [newTitle, setNewTitle] = useState('')
const [error, setError] = useState('')
@@ -1888,11 +1889,11 @@ function PodcastWorkflowAdmin({ laneA, laneB }: { laneA: { title: string }; lane
const r = await fetch('/api/admin/podcast-workflow/planned', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ season: laneSeason, episodeNumber: newNumber, title: newTitle, lane }),
body: JSON.stringify({ season: newSeason, episodeNumber: newNumber, title: newTitle }),
})
const d = await r.json()
if (!r.ok) { setError(d.message ?? 'Could not add episode.'); return }
setNewNumber(''); setNewTitle('')
setNewNumber(''); setNewTitle(''); setStarting(false)
await reload()
setSelectedKey(d.key)
}
@@ -1929,7 +1930,6 @@ function PodcastWorkflowAdmin({ laneA, laneB }: { laneA: { title: string }; lane
<strong>{label(i)}</strong>
<div style={{ fontSize: '0.78rem', opacity: 0.75 }}>
{i.released ? `Released ${i.releaseDate || ''}` : `${doneCount(i)}/${PODCAST_STEP_DEFS.length} steps`}
{!i.released && i.hasScript ? ' · script ready' : ''}
</div>
</button>
)
@@ -1967,7 +1967,7 @@ function PodcastWorkflowAdmin({ laneA, laneB }: { laneA: { title: string }; lane
onBlur={e => { if (e.target.value !== laneSeason) saveLaneSeason(e.target.value) }}
/>
<span className="admin-stats-note">
{laneSeason ? `Only season ${laneSeason} episodes are shown here.` : 'Set a season number so this lane picks up its episodes, or assign episodes by hand.'}
{laneSeason ? `Only season ${laneSeason} episodes are shown here.` : 'Set a season number so this lane picks up its episodes, or start an episode and assign it by hand.'}
</span>
</div>
) : (
@@ -1982,11 +1982,30 @@ function PodcastWorkflowAdmin({ laneA, laneB }: { laneA: { title: string }; lane
{upcoming.length === 0 && <p className="admin-stats-note">Nothing in progress.</p>}
{upcoming.map(row)}
</div>
{lane !== 'other' && (
<div style={{ display: 'flex', gap: 6, margin: '8px 0 14px', flexWrap: 'wrap' }}>
<input type="number" min={1} placeholder="Ep #" value={newNumber} onChange={e => setNewNumber(e.target.value)} style={{ width: 70 }} aria-label="New episode number" />
<input type="text" placeholder="Title (optional)" value={newTitle} onChange={e => setNewTitle(e.target.value)} style={{ flex: 1, minWidth: 120 }} aria-label="New episode title" />
<button type="button" className="btn-admin-add" onClick={addPlanned} disabled={!newNumber}>Add</button>
{!starting ? (
<button type="button" className="btn-admin-add" style={{ margin: '8px 0 14px' }} onClick={() => { setNewSeason(laneSeason); setStarting(true) }}>
+ Start new episode
</button>
) : (
<div style={{ margin: '8px 0 14px', padding: 10, border: '1px solid var(--color-border, #e5e0d5)', borderRadius: 6 }}>
<div className="admin-field">
<label htmlFor="pw-new-title">Episode name</label>
<input id="pw-new-title" type="text" value={newTitle} onChange={e => setNewTitle(e.target.value)} />
</div>
<div style={{ display: 'flex', gap: 10, marginBottom: 8 }}>
<div className="admin-field" style={{ flex: 1 }}>
<label htmlFor="pw-new-season">Season</label>
<input id="pw-new-season" type="number" min={1} value={newSeason} onChange={e => setNewSeason(e.target.value)} />
</div>
<div className="admin-field" style={{ flex: 1 }}>
<label htmlFor="pw-new-number">Episode #</label>
<input id="pw-new-number" type="number" min={1} value={newNumber} onChange={e => setNewNumber(e.target.value)} />
</div>
</div>
<div style={{ display: 'flex', gap: 8 }}>
<button type="button" className="btn-admin-save" onClick={addPlanned} disabled={!newTitle.trim() || !newSeason || !newNumber}>Start workflow</button>
<button type="button" className="btn-admin-ghost" onClick={() => setStarting(false)}>Cancel</button>
</div>
</div>
)}
<label style={{ fontSize: '0.82rem', display: 'block', marginBottom: 6 }}>
@@ -2006,7 +2025,7 @@ function PodcastWorkflowAdmin({ laneA, laneB }: { laneA: { title: string }; lane
</p>
) : (
<p style={{ fontSize: '0.86rem', opacity: 0.8 }}>
{selected.hasScript ? 'Script uploaded.' : 'No script yet.'} This moves to Released on its own once it shows up in the feed.
This moves to Released on its own once season {selected.season} episode {selected.episodeNumber} shows up in your Spotify feed.
</p>
)}
<div className="admin-field" style={{ maxWidth: 360, margin: '8px 0 12px' }}>
@@ -2053,8 +2072,8 @@ function PodcastWorkflowAdmin({ laneA, laneB }: { laneA: { title: string }; lane
onBlur={e => save(selected.key, { notes: e.target.value })}
/>
</div>
{selected.planned && !selected.released && !selected.hasScript && (
<button type="button" className="btn-admin-remove" onClick={() => removePlanned(selected.key)}>Remove planned episode</button>
{selected.planned && !selected.released && (
<button type="button" className="btn-admin-remove" onClick={() => removePlanned(selected.key)}>Remove this episode</button>
)}
</>
)}