/* @component-map * App — Main container, tab navigation, layout shell [app.jsx] * EpisodeBoard — Drag-and-drop episode lineup with status management [components/EpisodeBoard.jsx] * EpisodeForm — Create/edit episode modal form [components/EpisodeForm.jsx] * EpisodeCard — Individual episode card with status badge [components/EpisodeCard.jsx] * StatsHeader — Season overview stats [components/StatsHeader.jsx] * @end-component-map */ import { useMemo, useState } from 'react'; import { useAuth, useCollection } from '@deplixo/sdk'; import { EpisodeBoard } from './components/EpisodeBoard.jsx'; import { EpisodeForm } from './components/EpisodeForm.jsx'; import { StatsHeader } from './components/StatsHeader.jsx'; function App() { const { user, loading, logout } = useAuth(); const { items: guests, add: addGuest, update: updateGuest, loading: guestsLoading } = useCollection('guests', { personal: true, }); const [showForm, setShowForm] = useState(false); const [editingEpisode, setEditingEpisode] = useState(null); const [showGuestForm, setShowGuestForm] = useState(false); const [guestFormError, setGuestFormError] = useState(''); const [guestDraft, setGuestDraft] = useState({ name: '', email: '', phone: '', company: '', bio: '', notes: '', }); const [selectedGuestId, setSelectedGuestId] = useState(''); const teamDisplayName = useMemo(() => { if (!user) return 'Podcast Team'; return user.name || user.email || 'Podcast Team'; }, [user]); const guestOptions = useMemo(() => { return [...(guests || [])].sort((a, b) => { const aName = (a?.name || '').toLowerCase(); const bName = (b?.name || '').toLowerCase(); return aName.localeCompare(bName); }); }, [guests]); function handleEdit(episode) { setEditingEpisode(episode); setShowForm(true); } function handleCloseForm() { setShowForm(false); setEditingEpisode(null); } function handleNewEpisode() { setEditingEpisode(null); setShowForm(true); } function handleGuestInputChange(event) { const { name, value } = event.target; setGuestDraft((current) => ({ ...current, [name]: value })); } async function handleCreateGuest(event) { event.preventDefault(); setGuestFormError(''); if (!guestDraft.name.trim()) { setGuestFormError('Guest name is required.'); return; } const payload = { name: guestDraft.name.trim(), email: guestDraft.email.trim(), phone: guestDraft.phone.trim(), company: guestDraft.company.trim(), bio: guestDraft.bio.trim(), notes: guestDraft.notes.trim(), pastAppearances: [], }; const created = await addGuest(payload); const createdId = created?.id || created?._id || created?.docId; setGuestDraft({ name: '', email: '', phone: '', company: '', bio: '', notes: '' }); setShowGuestForm(false); if (createdId) { setSelectedGuestId(createdId); } } async function handleLinkGuestToEpisode(event) { event.preventDefault(); if (!editingEpisode || !selectedGuestId) return; const guest = (guests || []).find((item) => String(item.id || item._id || item.docId) === String(selectedGuestId)); if (!guest) return; const appearance = { episodeId: editingEpisode.id || editingEpisode._id || editingEpisode.docId || null, episodeTitle: editingEpisode.title || '', linkedAt: new Date().toISOString(), }; const previousAppearances = Array.isArray(guest.pastAppearances) ? guest.pastAppearances : []; await updateGuest(guest.id || guest._id || guest.docId, { pastAppearances: [...previousAppearances, appearance], }); } if (loading) { return
Signing in...
; } if (!user) { return (
🎙️

PodPlanner

Sign in to access the podcast board

Use your Google account to join the podcast team, manage episode plans, and keep the season schedule in sync.

You’ll be redirected to Deplixo login automatically. After signing in, your session will be handled for you.
); } return (
🎙️

PodPlanner

Signed in as {teamDisplayName}
{showGuestForm && (

Guests

Create a guest record with contact details and track where they’ve appeared.

{guestFormError &&
{guestFormError}
}
{guestOptions.length === 0 ? (
No guests yet. Add one above to start linking appearances.
) : ( guestOptions.map((guest) => { const guestId = guest.id || guest._id || guest.docId; const appearances = Array.isArray(guest.pastAppearances) ? guest.pastAppearances.length : 0; return ( ); }) )}
)} {showForm && (

Link a Guest to This Episode

Select an existing guest and record this episode in their past appearances.

)}
); } ReactDOM.createRoot(document.getElementById("root")).render();