feat: Dashboard-Badge → Favoriten-Tab, ❤ Button im Modal, xREL für TV ausblenden
This commit is contained in:
@@ -1983,7 +1983,7 @@ function Dashboard({ toast, mobile, setActive, setDevToolsNav, unreadMsgs=0, unr
|
|||||||
</button>
|
</button>
|
||||||
{/* Unquittierte Favoriten für alle User */}
|
{/* Unquittierte Favoriten für alle User */}
|
||||||
{unackedFavs > 0 && (
|
{unackedFavs > 0 && (
|
||||||
<button onClick={()=>{ setActive('media'); onAckFavs?.(); }} style={{
|
<button onClick={()=>{ setActive('media'); setMediaInitTab('favoriten'); onAckFavs?.(); }} style={{
|
||||||
background:'rgba(245,158,11,0.12)', border:'1px solid rgba(245,158,11,0.35)',
|
background:'rgba(245,158,11,0.12)', border:'1px solid rgba(245,158,11,0.35)',
|
||||||
borderRadius:7, color:'#f59e0b', cursor:'pointer',
|
borderRadius:7, color:'#f59e0b', cursor:'pointer',
|
||||||
padding:'4px 10px', fontSize:9, fontFamily:'monospace', letterSpacing:1,
|
padding:'4px 10px', fontSize:9, fontFamily:'monospace', letterSpacing:1,
|
||||||
@@ -3619,6 +3619,7 @@ export default function App() {
|
|||||||
const [unreadPromoted, setUnreadPromoted] = useState(0);
|
const [unreadPromoted, setUnreadPromoted] = useState(0);
|
||||||
const [unreadChangelog,setUnreadChangelog]= useState(0);
|
const [unreadChangelog,setUnreadChangelog]= useState(0);
|
||||||
const [unackedFavs, setUnackedFavs] = useState(0);
|
const [unackedFavs, setUnackedFavs] = useState(0);
|
||||||
|
const [mediaInitTab, setMediaInitTab] = useState(null);
|
||||||
|
|
||||||
const [authChecked, setAuthChecked] = useState(false);
|
const [authChecked, setAuthChecked] = useState(false);
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
@@ -3719,7 +3720,7 @@ export default function App() {
|
|||||||
<main ref={mainRef} style={mainStyle}>
|
<main ref={mainRef} style={mainStyle}>
|
||||||
{active==='dashboard' && <Dashboard toast={toast} mobile={mobile} setActive={setActive} setDevToolsNav={setDevToolsNav} unreadMsgs={unreadMsgs} unreadBoard={unreadBoard} unreadPromoted={unreadPromoted} onBoardRead={()=>{ setUnreadBoard(0); setUnreadPromoted(0); }} unreadChangelog={unreadChangelog} onChangelogRead={()=>setUnreadChangelog(0)} unackedFavs={unackedFavs} onAckFavs={()=>api('/tools/media/favorites/acknowledge-all',{method:'POST',body:{}}).then(()=>setUnackedFavs(0)).catch(()=>{})} user={user}/>}
|
{active==='dashboard' && <Dashboard toast={toast} mobile={mobile} setActive={setActive} setDevToolsNav={setDevToolsNav} unreadMsgs={unreadMsgs} unreadBoard={unreadBoard} unreadPromoted={unreadPromoted} onBoardRead={()=>{ setUnreadBoard(0); setUnreadPromoted(0); }} unreadChangelog={unreadChangelog} onChangelogRead={()=>setUnreadChangelog(0)} unackedFavs={unackedFavs} onAckFavs={()=>api('/tools/media/favorites/acknowledge-all',{method:'POST',body:{}}).then(()=>setUnackedFavs(0)).catch(()=>{})} user={user}/>}
|
||||||
{active==='admin' && <AdminPanel toast={toast} mobile={mobile} user={user} nav={devToolsNav}/>}
|
{active==='admin' && <AdminPanel toast={toast} mobile={mobile} user={user} nav={devToolsNav}/>}
|
||||||
{activeTool && <activeTool.component toast={toast} mobile={mobile} setActive={setActive} {...(activeTool.id==='devtools'?{nav:devToolsNav}:{})}/>}
|
{activeTool && <activeTool.component toast={toast} mobile={mobile} setActive={setActive} {...(activeTool.id==='devtools'?{nav:devToolsNav}:{})} {...(activeTool.id==='media' && mediaInitTab ? {initTab:mediaInitTab, onInitTabConsumed:()=>setMediaInitTab(null)} : {})}/>}
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
{mobile && (
|
{mobile && (
|
||||||
|
|||||||
@@ -38,8 +38,14 @@ const FSK_COLOR = fsk => {
|
|||||||
return { bg:'#444', color:'#fff' };
|
return { bg:'#444', color:'#fff' };
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function Media({ toast, mobile }) {
|
export default function Media({ toast, mobile, initTab, onInitTabConsumed }) {
|
||||||
const [activeTool, setActiveTool] = useState('kino');
|
const [activeTool, setActiveTool] = useState('kino');
|
||||||
|
const [favIds, toggleFav] = useFavIds();
|
||||||
|
|
||||||
|
// Wenn von außen ein Tab vorgegeben wird (z.B. Dashboard-Badge)
|
||||||
|
useEffect(() => {
|
||||||
|
if (initTab) { setActiveTool(initTab); onInitTabConsumed?.(); }
|
||||||
|
}, [initTab]);
|
||||||
const [modal, setModal] = useState(null); // { id, media_type }
|
const [modal, setModal] = useState(null); // { id, media_type }
|
||||||
const [xrelIds, setXrelIds] = useState(new Set()); // tmdb_ids mit bekannten Releases
|
const [xrelIds, setXrelIds] = useState(new Set()); // tmdb_ids mit bekannten Releases
|
||||||
|
|
||||||
@@ -126,10 +132,10 @@ export default function Media({ toast, mobile }) {
|
|||||||
<span style={{ color:'rgba(255,255,255,0.5)', fontFamily:'monospace', fontSize:10 }}>{active?.desc}</span>
|
<span style={{ color:'rgba(255,255,255,0.5)', fontFamily:'monospace', fontSize:10 }}>{active?.desc}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{activeTool === 'kino' && <KinoGrid onOpenModal={setModal} xrelIds={xrelIds} onXrelLoaded={ids => setXrelIds(prev => new Set([...prev, ...ids]))} />}
|
{activeTool === 'kino' && <KinoGrid onOpenModal={setModal} xrelIds={xrelIds} onXrelLoaded={ids => setXrelIds(prev => new Set([...prev, ...ids]))} favIds={favIds} onToggleFav={toggleFav}/>}
|
||||||
{activeTool === 'demnächst' && <DemnächstGrid onOpenModal={setModal} xrelIds={xrelIds} onXrelLoaded={ids => setXrelIds(prev => new Set([...prev, ...ids]))} />}
|
{activeTool === 'demnächst' && <DemnächstGrid onOpenModal={setModal} xrelIds={xrelIds} onXrelLoaded={ids => setXrelIds(prev => new Set([...prev, ...ids]))} favIds={favIds} onToggleFav={toggleFav}/>}
|
||||||
{activeTool === 'favoriten' && <FavoritenKalender onOpenModal={setModal} />}
|
{activeTool === 'favoriten' && <FavoritenKalender onOpenModal={setModal} />}
|
||||||
{activeTool === 'suchen' && <SucheGrid onOpenModal={setModal} xrelIds={xrelIds} onXrelLoaded={ids => setXrelIds(prev => new Set([...prev, ...ids]))} />}
|
{activeTool === 'suchen' && <SucheGrid onOpenModal={setModal} xrelIds={xrelIds} onXrelLoaded={ids => setXrelIds(prev => new Set([...prev, ...ids]))} favIds={favIds} onToggleFav={toggleFav}/>}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{modal && createPortal(
|
{modal && createPortal(
|
||||||
@@ -140,6 +146,8 @@ export default function Media({ toast, mobile }) {
|
|||||||
mobile={mobile}
|
mobile={mobile}
|
||||||
onHasXrel={id => setXrelIds(prev => new Set([...prev, id]))}
|
onHasXrel={id => setXrelIds(prev => new Set([...prev, id]))}
|
||||||
noYearFilter={activeTool === 'suchen'}
|
noYearFilter={activeTool === 'suchen'}
|
||||||
|
isFav={favIds.has(modal?.id || modal)}
|
||||||
|
onToggleFav={movie => toggleFav(movie, favIds.has(modal?.id || modal))}
|
||||||
/>,
|
/>,
|
||||||
document.body
|
document.body
|
||||||
)}
|
)}
|
||||||
@@ -809,7 +817,7 @@ function FavoritenKalender({ onOpenModal }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ── Film-Detail-Modal (via Portal) ────────────────────────────────────────────
|
// ── Film-Detail-Modal (via Portal) ────────────────────────────────────────────
|
||||||
function MovieModal({ tmdbId, mediaType='movie', onClose, mobile, onHasXrel, noYearFilter }) {
|
function MovieModal({ tmdbId, mediaType='movie', onClose, mobile, onHasXrel, noYearFilter, isFav=false, onToggleFav }) {
|
||||||
const [detail, setDetail] = useState(null);
|
const [detail, setDetail] = useState(null);
|
||||||
const [xrel, setXrel] = useState(null); // null=nicht gesucht, []=gesucht
|
const [xrel, setXrel] = useState(null); // null=nicht gesucht, []=gesucht
|
||||||
const [xrelDates, setXrelDates] = useState([]);
|
const [xrelDates, setXrelDates] = useState([]);
|
||||||
@@ -917,13 +925,22 @@ function MovieModal({ tmdbId, mediaType='movie', onClose, mobile, onHasXrel, noY
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Schließen – sticky außerhalb des Scroll-Containers */}
|
{/* Schließen + Favorit – sticky außerhalb des Scroll-Containers */}
|
||||||
<button onClick={onClose} style={{
|
<button onClick={onClose} style={{
|
||||||
position:'absolute', top:12, right:12,
|
position:'absolute', top:12, right:12,
|
||||||
background:'rgba(0,0,0,0.75)', border:'none', borderRadius:'50%',
|
background:'rgba(0,0,0,0.75)', border:'none', borderRadius:'50%',
|
||||||
width:34, height:34, cursor:'pointer', zIndex:10,
|
width:34, height:34, cursor:'pointer', zIndex:10,
|
||||||
color:'#fff', fontSize:18, display:'flex', alignItems:'center', justifyContent:'center',
|
color:'#fff', fontSize:18, display:'flex', alignItems:'center', justifyContent:'center',
|
||||||
}}>✕</button>
|
}}>✕</button>
|
||||||
|
{onToggleFav && detail && (
|
||||||
|
<button onClick={() => onToggleFav(detail)} style={{
|
||||||
|
position:'absolute', top:12, right:54,
|
||||||
|
background:'rgba(0,0,0,0.75)', border:'none', borderRadius:'50%',
|
||||||
|
width:34, height:34, cursor:'pointer', zIndex:10,
|
||||||
|
color: isFav ? '#f87171' : 'rgba(255,255,255,0.6)',
|
||||||
|
fontSize:18, display:'flex', alignItems:'center', justifyContent:'center',
|
||||||
|
}}>{isFav ? '❤' : '🤍'}</button>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Scrollbarer Inhalt */}
|
{/* Scrollbarer Inhalt */}
|
||||||
<div style={{ overflowY:'auto', WebkitOverflowScrolling:'touch', flex:1 }}>
|
<div style={{ overflowY:'auto', WebkitOverflowScrolling:'touch', flex:1 }}>
|
||||||
@@ -1042,7 +1059,7 @@ function MovieModal({ tmdbId, mediaType='movie', onClose, mobile, onHasXrel, noY
|
|||||||
</div>
|
</div>
|
||||||
) : null;
|
) : null;
|
||||||
})()}
|
})()}
|
||||||
<div style={{ display:'flex', alignItems:'center', gap:8, marginBottom: xrel?.length ? 8 : 0 }}>
|
{mediaType !== 'tv' && <div style={{ display:'flex', alignItems:'center', gap:8, marginBottom: xrel?.length ? 8 : 0 }}>
|
||||||
<div style={{ ...S.head, marginBottom:0, flex:1 }}>RELEASES (XREL.TO)</div>
|
<div style={{ ...S.head, marginBottom:0, flex:1 }}>RELEASES (XREL.TO)</div>
|
||||||
<button
|
<button
|
||||||
onClick={() => searchXrel(xrel !== null && xrel.length > 0)}
|
onClick={() => searchXrel(xrel !== null && xrel.length > 0)}
|
||||||
@@ -1057,7 +1074,7 @@ function MovieModal({ tmdbId, mediaType='movie', onClose, mobile, onHasXrel, noY
|
|||||||
{xrelLoading ? '⏳ Suche…' : xrel === null ? '🔍 Nach Releases suchen' : '🔄 Erneut suchen'}
|
{xrelLoading ? '⏳ Suche…' : xrel === null ? '🔍 Nach Releases suchen' : '🔄 Erneut suchen'}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{xrel !== null && xrel.length === 0 && (
|
{mediaType !== 'tv' && xrel !== null && xrel.length === 0 && (
|
||||||
<div style={{ fontSize:11, color:'rgba(255,255,255,0.3)', fontFamily:'monospace', fontStyle:'italic' }}>
|
<div style={{ fontSize:11, color:'rgba(255,255,255,0.3)', fontFamily:'monospace', fontStyle:'italic' }}>
|
||||||
Keine deutschen Releases gefunden
|
Keine deutschen Releases gefunden
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user